diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 74246b0d..b2de41ba 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -13,6 +13,19 @@ jobs: runs-on: windows-2022 strategy: fail-fast: false + matrix: + target: + - raddbg + - radlink + - rdi_from_pdb + - raddump + - rdi_breakpad_from_pdb + compiler: + - msvc + - clang + mode: + - debug + - release steps: - name: checkout uses: actions/checkout@v2 @@ -20,13 +33,4 @@ jobs: shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 - call build raddbg msvc debug || exit /b 1 - call build rdi_from_pdb msvc debug || exit /b 1 - call build rdi_from_dwarf msvc debug || exit /b 1 - call build rdi_dump msvc debug || exit /b 1 - call build raddbg clang debug || exit /b 1 - call build rdi_from_pdb clang debug || exit /b 1 - call build rdi_from_dwarf clang debug || exit /b 1 - call build rdi_dump clang debug || exit /b 1 - call build radlink msvc debug || exit /b 1 - call build radlink clang debug || exit /b 1 \ No newline at end of file + call build ${{ matrix.target }} ${{ matrix.compiler }} ${{ matrix.mode }} || exit /b 1 diff --git a/README.md b/README.md index be4e9c25..8d8396ec 100644 --- a/README.md +++ b/README.md @@ -90,10 +90,11 @@ You should see the following output: ``` [debug mode] [msvc compile] +[default mode, assuming `raddbg` build] metagen_main.c -searching C:\devel\raddebugger/src... 309 files found -parsing metadesk... 15 metadesk files parsed -gathering tables... 96 tables found +searching C:\devel\raddebugger/src... 447 files found +parsing metadesk... 14 metadesk files parsed +gathering tables... 93 tables found generating layer code... raddbg_main.c ``` @@ -101,6 +102,16 @@ raddbg_main.c If everything worked correctly, there will be a `build` folder in the root level of the codebase, and it will contain a freshly-built `raddbg.exe`. +This `raddbg.exe` will have been built in **debug mode**, which is not built +with optimizations, and may perform worse. To produce a +**release mode executable**, run `build.bat` with a `release` argument: + +``` +build release +``` + +This build will take significantly longer. + ## Short-To-Medium-Term Roadmap ### The Initial Alpha Battle-Testing Phase diff --git a/build.bat b/build.bat index 2187d8f6..d8a2ca72 100644 --- a/build.bat +++ b/build.bat @@ -40,6 +40,7 @@ if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set auto_compile_flags= if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] +if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] :: --- Compile/Link Line Definitions ------------------------------------------ set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 @@ -52,14 +53,14 @@ set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%% set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" set cl_out= /out: set clang_out= -o -set cl_natvis= /NATVIS: -set clang_natvis= -Xlinker /NATVIS: +set cl_linker= +set clang_linker= -Xlinker :: --- Per-Build Settings ----------------------------------------------------- set link_dll=-DLL set link_icon=logo.res -if "%msvc%"=="1" set link_natvis=%cl_natvis% -if "%clang%"=="1" set link_natvis=%clang_natvis% +if "%msvc%"=="1" set linker=%cl_linker% +if "%clang%"=="1" set linker=%clang_linker% if "%msvc%"=="1" set only_compile=/c if "%clang%"=="1" set only_compile=-c if "%msvc%"=="1" set EHsc=/EHsc @@ -106,18 +107,20 @@ if not "%no_meta%"=="1" ( :: --- Build Everything (@build_targets) -------------------------------------- pushd build if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1 -if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %link_natvis%"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1 +if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1 +if "%radcon%"=="1" set didbuild=1 && %compile% ..\src\radcon\radcon_main.c %compile_link% %out%radcon.exe || exit /b 1 if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1 if "%rdi_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1 -if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 -if "%rdi_dump%"=="1" set didbuild=1 && %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1 +if "%rdi_from_dwarf%"=="1" set didbuild=1 && %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf_main.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 if "%rdi_breakpad_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1 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 "%eval_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\eval_scratch.c %compile_link% %out%eval_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 "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1 if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1 if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1 +if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1 if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 diff --git a/build.sh b/build.sh index 03bde82c..f7ea6139 100644 --- a/build.sh +++ b/build.sh @@ -15,11 +15,11 @@ if [ -v gcc ]; then compiler="${CC:-gcc}"; echo "[gcc compile]"; fi auto_compile_flags='' # --- Get Current Git Commit Id ----------------------------------------------- -git_hash=$(git rev-parse HEAD) +git_hash=$(git describe --always --dirty) git_hash_full=$(git rev-parse HEAD) # --- Compile/Link Line Definitions ------------------------------------------- -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_common="-I../src/ -I/usr/include/freetype2/ -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" @@ -33,6 +33,8 @@ gcc_out="-o" # --- Per-Build Settings ------------------------------------------------------ link_dll="-fPIC" link_os_gfx="-lX11 -lXext" +link_render="-lGL -lEGL" +link_font_provider="-lfreetype" # --- Choose Compile/Link Lines ----------------------------------------------- if [ -v gcc ]; then compile_debug="$gcc_debug"; fi @@ -62,13 +64,13 @@ 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 raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $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 if [ -v rdi_breakpad_from_pdb ]; then didbuild=1 && $compile ../src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c $compile_link $out rdi_breakpad_from_pdb; fi -if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $out ryan_scratch; fi +if [ -v ryan_scratch ]; then didbuild=1 && $compile ../src/scratch/ryan_scratch.c $compile_link $link_os_gfx $link_render $link_font_provider $out ryan_scratch; fi cd .. # --- Warn On No Builds ------------------------------------------------------- diff --git a/data/icons.ttf b/data/icons.ttf index 86db4361..f9d82393 100644 Binary files a/data/icons.ttf and b/data/icons.ttf differ diff --git a/project.4coder b/project.4coder index 0be9237b..32a1e737 100644 --- a/project.4coder +++ b/project.4coder @@ -45,12 +45,20 @@ load_paths = commands = { - //- rjf: fkey command slots (change locally but do not commit) - .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: [raddbg] + .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + + //- rjf: [textperf] + // .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + + //- rjf: [tester] + // .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + + //- rjf: running target + .f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, + // .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, //- rjf: local target builds .build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, diff --git a/src/async/async.c b/src/async/async.c index 9e8cda09..ec84c372 100644 --- a/src/async/async.c +++ b/src/async/async.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0x59b6c3ff + //////////////////////////////// //~ rjf: Top-Level Layer Initialization @@ -23,8 +26,9 @@ async_init(CmdLine *cmdline) String8 work_thread_count_string = cmd_line_string(cmdline, str8_lit("work_threads_count")); if(work_thread_count_string.size == 0 || !try_u64_from_str8_c_rules(work_thread_count_string, &async_shared->work_threads_count)) { - async_shared->work_threads_count = Max(1, os_get_system_info()->logical_processor_count-1); + async_shared->work_threads_count = Max(4, os_get_system_info()->logical_processor_count-1); } + async_shared->work_threads_count = Max(4, async_shared->work_threads_count); async_shared->work_threads = push_array(arena, OS_Handle, async_shared->work_threads_count); for EachIndex(idx, async_shared->work_threads_count) { @@ -57,6 +61,7 @@ async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params work.output = params->output; work.semaphore = params->semaphore; work.completion_counter = params->completion_counter; + work.working_counter = params->working_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 @@ -159,7 +164,6 @@ async_task_join(ASYNC_Task *task) internal ASYNC_Work async_pop_work(void) { - ProfBeginFunction(); ASYNC_Work work = {0}; B32 done = 0; ASYNC_Priority taken_priority = ASYNC_Priority_Low; @@ -194,7 +198,6 @@ async_pop_work(void) } os_condition_variable_broadcast(async_shared->ring_cv); os_condition_variable_broadcast(async_shared->rings[taken_priority].ring_cv); - ProfEnd(); return work; } @@ -223,6 +226,12 @@ async_execute_work(ASYNC_Work work) { ins_atomic_u64_inc_eval(work.completion_counter); } + + //- rjf: decrement working counter + if(work.working_counter != 0) + { + ins_atomic_u64_dec_eval(work.working_counter); + } } //////////////////////////////// diff --git a/src/async/async.h b/src/async/async.h index f793f3d1..6d9f2b00 100644 --- a/src/async/async.h +++ b/src/async/async.h @@ -29,6 +29,7 @@ struct ASYNC_WorkParams void **output; OS_Handle semaphore; U64 *completion_counter; + U64 *working_counter; U64 endt_us; ASYNC_Priority priority; }; @@ -41,6 +42,7 @@ struct ASYNC_Work void **output; OS_Handle semaphore; U64 *completion_counter; + U64 *working_counter; }; //////////////////////////////// diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index ba452a5a..976ff941 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -159,7 +159,7 @@ #endif #if !defined(BUILD_VERSION_PATCH) -# define BUILD_VERSION_PATCH 15 +# define BUILD_VERSION_PATCH 18 #endif #define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) diff --git a/src/base/base_core.c b/src/base/base_core.c index b392e4a0..e5faadde 100644 --- a/src/base/base_core.c +++ b/src/base/base_core.c @@ -602,3 +602,37 @@ ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_s } return read_size; } + +//////////////////////////////// + +internal U64 +u64_array_bsearch(U64 *arr, U64 count, U64 value) +{ + if(count > 1 && arr[0] <= value && value < arr[count-1]) + { + U64 l = 0; + U64 r = count - 1; + for(; l <= r; ) + { + U64 m = l + (r - l) / 2; + if(arr[m] == value) + { + return m; + } + else if(arr[m] < value) + { + l = m + 1; + } + else + { + r = m - 1; + } + } + } + else if (count == 1 && arr[0] == value) + { + return 0; + } + return max_U64; +} + diff --git a/src/base/base_core.h b/src/base/base_core.h index 191e1e7f..ab7b35f3 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -65,6 +65,14 @@ # define C_LINKAGE #endif +//////////////////////////////// +//~ rjf: Versions + +#define Version(major, minor, patch) (U64)((((U64)(major) & 0xffff) << 32) | ((((U64)(minor) & 0xffff) << 16)) | ((((U64)(patch) & 0xffff) << 0))) +#define MajorFromVersion(version) (((version) & 0xffff00000000ull) >> 32) +#define MinorFromVersion(version) (((version) & 0x0000ffff0000ull) >> 16) +#define PatchFromVersion(version) (((version) & 0x00000000ffffull) >> 0) + //////////////////////////////// //~ rjf: Units @@ -348,6 +356,9 @@ C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t s #define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0) #define ExtractBit(word, idx) (((word) >> (idx)) & 1) +#define Extract8(word, pos) (((word) >> ((pos)*8)) & max_U8) +#define Extract16(word, pos) (((word) >> ((pos)*16)) & max_U16) +#define Extract32(word, pos) (((word) >> ((pos)*32)) & max_U32) #if LANG_CPP # define zero_struct {} @@ -379,11 +390,33 @@ typedef S64 B64; typedef float F32; typedef double F64; typedef void VoidProc(void); -typedef struct U128 U128; -struct U128 +typedef union U128 U128; +union U128 { + U8 u8[16]; + U16 u16[8]; + U32 u32[4]; U64 u64[2]; }; +typedef union U256 U256; +union U256 +{ + U8 u8[32]; + U16 u16[16]; + U32 u32[8]; + U64 u64[4]; + U128 u128[2]; +}; +typedef union U512 U512; +union U512 +{ + U8 u8[64]; + U16 u16[32]; + U32 u32[16]; + U64 u64[8]; + U128 u128[4]; + U256 u256[2]; +}; //////////////////////////////// //~ rjf: Basic Types & Spaces @@ -565,15 +598,15 @@ global U32 max_U32 = 0xffffffff; global U16 max_U16 = 0xffff; global U8 max_U8 = 0xff; -global S64 max_S64 = (S64)0x7fffffffffffffffull; +global S64 max_S64 = (S64)0x7fffffffffffffffll; global S32 max_S32 = (S32)0x7fffffff; global S16 max_S16 = (S16)0x7fff; global S8 max_S8 = (S8)0x7f; -global S64 min_S64 = (S64)0xffffffffffffffffull; -global S32 min_S32 = (S32)0xffffffff; -global S16 min_S16 = (S16)0xffff; -global S8 min_S8 = (S8)0xff; +global S64 min_S64 = (S64)0x8000000000000000ll; +global S32 min_S32 = (S32)0x80000000; +global S16 min_S16 = (S16)0x8000; +global S8 min_S8 = (S8)0x80; global const U32 bitmask1 = 0x00000001; global const U32 bitmask2 = 0x00000003; @@ -885,4 +918,8 @@ internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_dat #define quick_sort(ptr, count, element_size, cmp_function) qsort((ptr), (count), (element_size), (int (*)(const void *, const void *))(cmp_function)) +//////////////////////////////// + +internal U64 u64_array_bsearch(U64 *arr, U64 count, U64 value); + #endif // BASE_CORE_H diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 21bbc363..6d489e66 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -121,6 +121,9 @@ update(void) { ProfTick(0); ins_atomic_u64_inc_eval(&global_update_tick_idx); +#if defined(FONT_CACHE_H) + fnt_frame(); +#endif #if OS_FEATURE_GRAPHICAL B32 result = frame(); #else diff --git a/src/base/base_inc.c b/src/base/base_inc.c index dc2916bf..299d9042 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -4,8 +4,8 @@ //////////////////////////////// //~ rjf: Base Includes -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.20f, 0.60f, 0.80f +#undef LAYER_COLOR +#define LAYER_COLOR 0.20f, 0.60f, 0.80f #include "base_core.c" #include "base_profile.c" diff --git a/src/base/base_log.h b/src/base/base_log.h index 3687390e..ba181ce2 100644 --- a/src/base/base_log.h +++ b/src/base/base_log.h @@ -49,12 +49,12 @@ internal void log_select(Log *log); internal void log_msg(LogMsgKind kind, String8 string); internal void log_msgf(LogMsgKind kind, char *fmt, ...); #define log_info(s) log_msg(LogMsgKind_Info, (s)) -#define log_infof(fmt, ...) log_msgf(LogMsgKind_Info, (fmt), __VA_ARGS__) +#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__) #define log_user_error(s) log_msg(LogMsgKind_UserError, (s)) -#define log_user_errorf(fmt, ...) log_msgf(LogMsgKind_UserError, (fmt), __VA_ARGS__) +#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__) #define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n")) -#define LogInfoNamedBlockF(fmt, ...) DeferLoop((log_infof(fmt, __VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n")) +#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n")) //////////////////////////////// //~ rjf: Log Scopes diff --git a/src/base/base_markup.h b/src/base/base_markup.h index fd291375..2de3aa5d 100644 --- a/src/base/base_markup.h +++ b/src/base/base_markup.h @@ -4,9 +4,19 @@ #ifndef BASE_MARKUP_H #define BASE_MARKUP_H +#define RADDBG_MARKUP_IMPLEMENTATION +#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf +#if OS_LINUX +# define RADDBG_MARKUP_STUBS +#endif +#include "lib_raddbg_markup/raddbg_markup.h" + +#if !defined(LAYER_COLOR) +# define LAYER_COLOR 0x404040ff +#endif + internal void set_thread_name(String8 string); internal void set_thread_namef(char *fmt, ...); -#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__)) -#define ThreadName(str) (set_thread_name(str)) +#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR)) #endif // BASE_MARKUP_H diff --git a/src/base/base_math.c b/src/base/base_math.c index 2c6201f3..7a65b45b 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -386,6 +386,21 @@ derotate_4x4f32(Mat4x4F32 mat) return mat; } +internal Mat4x4F32 +transpose_4x4f32(Mat4x4F32 mat) +{ + Mat4x4F32 result = + { + { + mat.v[0][0], mat.v[1][0], mat.v[2][0], mat.v[3][0], + mat.v[0][1], mat.v[1][1], mat.v[2][1], mat.v[3][1], + mat.v[0][2], mat.v[1][2], mat.v[2][2], mat.v[3][2], + mat.v[0][3], mat.v[1][3], mat.v[2][3], mat.v[3][3], + } + }; + return result; +} + //////////////////////////////// //~ rjf: Range Ops @@ -480,7 +495,9 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0 internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} //////////////////////////////// -//~ rjf: Miscellaneous Ops +//~ rjf: Color Operations + +//- rjf: hsv <-> rgb internal Vec3F32 hsv_from_rgb(Vec3F32 rgb) @@ -567,16 +584,102 @@ rgba_from_hsva(Vec4F32 hsva) return rgba; } -internal Vec4F32 -rgba_from_u32(U32 hex) +//- rjf: srgb <-> linear + +internal Vec3F32 +linear_from_srgb(Vec3F32 srgb) { - Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f, - ((hex&0x00ff0000)>>16)/255.f, - ((hex&0x0000ff00)>> 8)/255.f, - ((hex&0x000000ff)>> 0)/255.f); + Vec3F32 result; + for EachElement(idx, srgb.v) + { + result.v[idx] = (srgb.v[idx] < 0.0404482362771082f ? srgb.v[idx] / 12.92f : pow_f32((srgb.v[idx] + 0.055f) / 1.055f, 2.4f)); + } return result; } +internal Vec3F32 +srgb_from_linear(Vec3F32 linear) +{ + Vec3F32 result; + for EachElement(idx, linear.v) + { + result.v[idx] = (0 <= linear.v[idx] && linear.v[idx] < 0.00313066844250063) ? linear.v[idx]*12.92f : 1.05f * pow_f32(linear.v[idx], 1.f/2.4f) - 0.055f; + } + return result; +} + +internal Vec4F32 +linear_from_srgba(Vec4F32 srgba) +{ + Vec4F32 result; + result.xyz = linear_from_srgb(srgba.xyz); + result.w = srgba.w; + return result; +} + +internal Vec4F32 +srgba_from_linear(Vec4F32 linear) +{ + Vec4F32 result; + result.xyz = srgb_from_linear(linear.xyz); + result.w = linear.w; + return result; +} + +//- rjf: oklab <-> linear + +internal Vec3F32 +oklab_from_linear(Vec3F32 linear) +{ + F32 l = (0.4122214708f * linear.x + 0.5363325363f * linear.y + 0.0514459929f * linear.z); + F32 m = (0.2119034982f * linear.x + 0.6806995451f * linear.y + 0.1073969566f * linear.z); + F32 s = (0.0883024619f * linear.x + 0.2817188376f * linear.y + 0.6299787005f * linear.z); + F32 l_ = cbrt_f32(l); + F32 m_ = cbrt_f32(m); + F32 s_ = cbrt_f32(s); + Vec3F32 result; + result.x = 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_; + result.y = 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_; + result.z = 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_; + return result; +} + +internal Vec3F32 +linear_from_oklab(Vec3F32 oklab) +{ + F32 l_ = oklab.x + 0.3963377774f * oklab.y + 0.2158037573f * oklab.z; + F32 m_ = oklab.x - 0.1055613458f * oklab.y - 0.0638541728f * oklab.z; + F32 s_ = oklab.x - 0.0894841775f * oklab.y - 1.2914855480f * oklab.z; + F32 l = l_*l_*l_; + F32 m = m_*m_*m_; + F32 s = s_*s_*s_; + Vec3F32 result; + result.x = +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s; + result.y = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s; + result.z = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s; + return result; +} + +internal Vec4F32 +oklab_from_lineara(Vec4F32 lineara) +{ + Vec4F32 result; + result.xyz = oklab_from_linear(lineara.xyz); + result.w = lineara.w; + return result; +} + +internal Vec4F32 +lineara_from_oklab(Vec4F32 oklab) +{ + Vec4F32 result; + result.xyz = linear_from_oklab(oklab.xyz); + result.w = oklab.w; + return result; +} + +//- rjf: rgba <-> u32 + internal U32 u32_from_rgba(Vec4F32 rgba) { @@ -588,6 +691,16 @@ u32_from_rgba(Vec4F32 rgba) return result; } +internal Vec4F32 +rgba_from_u32(U32 hex) +{ + Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f, + ((hex&0x00ff0000)>>16)/255.f, + ((hex&0x0000ff00)>> 8)/255.f, + ((hex&0x000000ff)>> 0)/255.f); + return result; +} + //////////////////////////////// //~ rjf: List Type Functions @@ -634,6 +747,37 @@ rng1u64_array_from_list(Arena *arena, Rng1U64List *list) return arr; } +internal U64 +rng_1u64_array_bsearch(Rng1U64Array arr, U64 value) +{ + if(arr.count > 0 && arr.v[0].min <= value && value < arr.v[arr.count-1].max) + { + U64 l = 0; + U64 r = arr.count - 1; + for(; l <= r; ) + { + U64 m = l + (r - l) / 2; + if(contains_1u64(arr.v[m], value)) + { + return m; + } + else if(arr.v[m].min < value) + { + l = m + 1; + } + else + { + r = m - 1; + } + } + } + else if(arr.count == 1 && contains_1u64(arr.v[0], value)) + { + return 0; + } + return max_U64; +} + internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng) { @@ -657,3 +801,4 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list) } return arr; } + diff --git a/src/base/base_math.h b/src/base/base_math.h index b6063ad5..eb322865 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -379,14 +379,15 @@ struct Rng1S64Array #define abs_s64(v) (S64)llabs(v) #define sqrt_f32(v) sqrtf(v) +#define cbrt_f32(v) cbrtf(v) #define mod_f32(a, b) fmodf((a), (b)) #define pow_f32(b, e) powf((b), (e)) #define ceil_f32(v) ceilf(v) #define floor_f32(v) floorf(v) #define round_f32(v) roundf(v) #define abs_f32(v) fabsf(v) -#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f) -#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f) +#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f)) +#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f)) #define degrees_from_turns_f32(v) ((v)*360.f) #define turns_from_degrees_f32(v) ((v)/360.f) #define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v))) @@ -396,14 +397,15 @@ struct Rng1S64Array #define tan_f32(v) tanf(radians_from_turns_f32(v)) #define sqrt_f64(v) sqrt(v) +#define cbrt_f64(v) cbrt(v) #define mod_f64(a, b) fmod((a), (b)) #define pow_f64(b, e) pow((b), (e)) #define ceil_f64(v) ceil(v) #define floor_f64(v) floor(v) #define round_f64(v) round(v) #define abs_f64(v) fabs(v) -#define radians_from_turns_f64(v) ((v)*2*3.1415926535897) -#define turns_from_radians_f64(v) ((v)/2*3.1415926535897) +#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897)) +#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897)) #define degrees_from_turns_f64(v) ((v)*360.0) #define turns_from_degrees_f64(v) ((v)/360.0) #define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v))) @@ -543,6 +545,7 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b); internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale); internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m); internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat); +internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat); //////////////////////////////// //~ rjf: Range Ops @@ -651,15 +654,29 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b); internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v); //////////////////////////////// -//~ rjf: Miscellaneous Ops +//~ rjf: Color Operations +//- rjf: hsv <-> rgb internal Vec3F32 hsv_from_rgb(Vec3F32 rgb); internal Vec3F32 rgb_from_hsv(Vec3F32 hsv); internal Vec4F32 hsva_from_rgba(Vec4F32 rgba); internal Vec4F32 rgba_from_hsva(Vec4F32 hsva); -internal Vec4F32 rgba_from_u32(U32 hex); -internal U32 u32_from_rgba(Vec4F32 rgba); +//- rjf: srgb <-> linear +internal Vec3F32 linear_from_srgb(Vec3F32 srgb); +internal Vec3F32 srgb_from_linear(Vec3F32 linear); +internal Vec4F32 linear_from_srgba(Vec4F32 srgba); +internal Vec4F32 srgba_from_linear(Vec4F32 linear); + +//- rjf: oklab <-> linear +internal Vec3F32 oklab_from_linear(Vec3F32 linear); +internal Vec3F32 linear_from_oklab(Vec3F32 oklab); +internal Vec4F32 oklab_from_lineara(Vec4F32 lineara); +internal Vec4F32 lineara_from_oklab(Vec4F32 oklab); + +//- rjf: rgba <-> u32 +internal U32 u32_from_rgba(Vec4F32 rgba); +internal Vec4F32 rgba_from_u32(U32 hex); #define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f } //////////////////////////////// @@ -668,6 +685,7 @@ internal U32 u32_from_rgba(Vec4F32 rgba); internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); +internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value); internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); diff --git a/src/base/base_meta.c b/src/base/base_meta.c index c60dc237..2bf14eb6 100644 --- a/src/base/base_meta.c +++ b/src/base/base_meta.c @@ -44,8 +44,7 @@ typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr) switch(t->type->kind) { default:{}break; - case TypeKind_Ptr: - if(!(t->type->flags & TypeFlag_IsExternal)) + case TypeKind_Ptr: { *(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr)); }break; @@ -173,13 +172,13 @@ serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerialize task->containing_type = t->containing_type; task->containing_ptr = t->containing_ptr; SLLQueuePush(first_task, last_task, task); - } - - // rjf: catch-all: write pointer value - else - { - str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count)); - } + } + + // rjf: catch-all: write pointer value + else + { + str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count)); + } }break; //- rjf: arrays -> descend to underlying type, + count @@ -345,14 +344,14 @@ deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSeriali task->containing_type = t->containing_type; task->containing_ptr = t->containing_ptr; SLLQueuePush(first_task, last_task, task); - } - - // rjf: catch-all: read pointer value - else - { + } + + // rjf: catch-all: read pointer value + else + { MemoryCopy(t->dst, t_src, t->type->size*t->count); - read_off += t->type->size*t->count; - } + read_off += t->type->size*t->count; + } }break; //- rjf: arrays -> descend to underlying type, + count diff --git a/src/base/base_meta.h b/src/base/base_meta.h index 45d01e72..62faafeb 100644 --- a/src/base/base_meta.h +++ b/src/base/base_meta.h @@ -100,10 +100,9 @@ TypeKind; typedef U32 TypeFlags; enum { - TypeFlag_IsExternal = (1<<0), - TypeFlag_IsPlainText = (1<<1), - TypeFlag_IsCodeText = (1<<2), - TypeFlag_IsPathText = (1<<3), + TypeFlag_IsPlainText = (1<<0), + TypeFlag_IsCodeText = (1<<1), + TypeFlag_IsPathText = (1<<2), }; typedef U32 MemberFlags; diff --git a/src/base/base_profile.h b/src/base/base_profile.h index 098270f4..b39a2fc5 100644 --- a/src/base/base_profile.h +++ b/src/base/base_profile.h @@ -11,10 +11,6 @@ # define PROFILE_TELEMETRY 0 #endif -#if !defined(MARKUP_LAYER_COLOR) -# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f -#endif - //////////////////////////////// //~ rjf: Third Party Includes @@ -44,25 +40,25 @@ # 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); \ - } +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); \ - } +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 //////////////////////////////// diff --git a/src/base/base_strings.c b/src/base/base_strings.c index 9e42e0cd..f98d6e44 100644 --- a/src/base/base_strings.c +++ b/src/base/base_strings.c @@ -242,7 +242,7 @@ str8_cstring_capped_reverse(void *raw_start, void *raw_cap) for(; ptr > start; ) { ptr -= 1; - + if (*ptr == '\0') { break; @@ -427,23 +427,53 @@ str8_chop(String8 str, U64 amt){ } internal String8 -str8_skip_chop_whitespace(String8 string){ +str8_skip_chop_whitespace(String8 string) +{ U8 *first = string.str; U8 *opl = first + string.size; - for (;first < opl; first += 1){ - if (!char_is_space(*first)){ + for(;first < opl; first += 1) + { + if(!char_is_space(*first)) + { break; } } - for (;opl > first;){ + for(;opl > first;) + { opl -= 1; - if (!char_is_space(*opl)){ + if(!char_is_space(*opl)) + { opl += 1; break; } } String8 result = str8_range(first, opl); - return(result); + return result; +} + +internal String8 +str8_skip_chop_slashes(String8 string) +{ + U8 *first = string.str; + U8 *opl = first + string.size; + for(;first < opl; first += 1) + { + if(!char_is_slash(*first)) + { + break; + } + } + for(;opl > first;) + { + opl -= 1; + if(!char_is_slash(*opl)) + { + opl += 1; + break; + } + } + String8 result = str8_range(first, opl); + return result; } //////////////////////////////// @@ -573,44 +603,50 @@ s32_from_str8(String8 string, U32 radix) } internal B32 -try_u64_from_str8_c_rules(String8 string, U64 *x){ +try_u64_from_str8_c_rules(String8 string, U64 *x) +{ B32 is_integer = 0; - if (str8_is_integer(string, 10)){ + if(str8_is_integer(string, 10) && !str8_match(str8_prefix(string, 1), str8_lit("0"), 0)) + { is_integer = 1; *x = u64_from_str8(string, 10); } - else{ + else + { String8 hex_string = str8_skip(string, 2); - if (str8_match(str8_prefix(string, 2), str8_lit("0x"), 0) && - str8_is_integer(hex_string, 0x10)){ + if(str8_match(str8_prefix(string, 2), str8_lit("0x"), 0) && + str8_is_integer(hex_string, 0x10)) + { is_integer = 1; *x = u64_from_str8(hex_string, 0x10); } - else if (str8_match(str8_prefix(string, 2), str8_lit("0b"), 0) && - str8_is_integer(hex_string, 2)){ + else if(str8_match(str8_prefix(string, 2), str8_lit("0b"), 0) && str8_is_integer(hex_string, 2)) + { is_integer = 1; *x = u64_from_str8(hex_string, 2); } - else{ + else + { String8 oct_string = str8_skip(string, 1); - if (str8_match(str8_prefix(string, 1), str8_lit("0"), 0) && - str8_is_integer(hex_string, 010)){ + if(str8_match(str8_prefix(string, 1), str8_lit("0"), 0) && str8_is_integer(hex_string, 010)) + { is_integer = 1; *x = u64_from_str8(oct_string, 010); } } } - return(is_integer); + return is_integer; } internal B32 -try_s64_from_str8_c_rules(String8 string, S64 *x){ +try_s64_from_str8_c_rules(String8 string, S64 *x) +{ String8 string_tail = {0}; S64 sign = sign_from_str8(string, &string_tail); U64 x_u64 = 0; B32 is_integer = try_u64_from_str8_c_rules(string_tail, &x_u64); *x = x_u64*sign; - return(is_integer); + return is_integer; } //- rjf: integer -> string @@ -619,7 +655,7 @@ internal String8 str8_from_memory_size(Arena *arena, U64 size) { String8 result; - + if(size < KB(1)) { result = push_str8f(arena, "%llu Bytes", size); @@ -640,7 +676,7 @@ str8_from_memory_size(Arena *arena, U64 size) { result = push_str8f(arena, "%llu.%02llu TiB", size / TB(1), ((size * 100) / TB(1)) % 100); } - + return result; } @@ -648,7 +684,7 @@ internal String8 str8_from_count(Arena *arena, U64 count) { String8 result; - + if(count < 1 * 1000) { result = push_str8f(arena, "%llu", count); @@ -689,7 +725,7 @@ str8_from_count(Arena *arena, U64 count) result = push_str8f(arena, "%lluB", count / 1000000000, frac); } } - + return result; } @@ -1114,6 +1150,13 @@ str8_list_from_flags(Arena *arena, String8List *list, //////////////////////////////// //~ rjf; String Arrays +internal String8Array +str8_array_zero(void) +{ + String8Array result = {0}; + return result; +} + internal String8Array str8_array_from_list(Arena *arena, String8List *list) { @@ -1137,44 +1180,103 @@ str8_array_reserve(Arena *arena, U64 count) return arr; } +internal String8Array +str8_array_copy(Arena *arena, String8Array array) +{ + String8Array result = {0}; + result.count = array.count; + result.v = push_array(arena, String8, result.count); + for EachIndex(idx, result.count) + { + result.v[idx] = push_str8_copy(arena, array.v[idx]); + } + return result; +} + +//////////////////////////////// +//~ rjf: String Version Helpers + +internal U64 +version_from_str8(String8 string) +{ + U64 result = 0; + Temp scratch = scratch_begin(0, 0); + U64 version_major = 0; + U64 version_minor = 0; + U64 version_patch = 0; + String8List version_parts = str8_split(scratch.arena, string, (U8 *)".", 1, 0); + if(version_parts.first && + version_parts.first->next && + version_parts.first->next->next) + { + try_u64_from_str8_c_rules(version_parts.first->string, &version_major); + try_u64_from_str8_c_rules(version_parts.first->next->string, &version_minor); + try_u64_from_str8_c_rules(version_parts.first->next->next->string, &version_patch); + result = Version(version_major, version_minor, version_patch); + } + scratch_end(scratch); + return result; +} + +internal String8 +str8_from_version(Arena *arena, U64 version) +{ + U64 version_major = MajorFromVersion(version); + U64 version_minor = MinorFromVersion(version); + U64 version_patch = PatchFromVersion(version); + String8 result = push_str8f(arena, "%I64d.%I64d.%I64d", version_major, version_minor, version_patch); + return result; +} + //////////////////////////////// //~ rjf: String Path Helpers internal String8 -str8_chop_last_slash(String8 string){ - if (string.size > 0){ +str8_chop_last_slash(String8 string) +{ + if(string.size > 0) + { U8 *ptr = string.str + string.size - 1; - for (;ptr >= string.str; ptr -= 1){ - if (*ptr == '/' || *ptr == '\\'){ + for(;ptr >= string.str; ptr -= 1) + { + if(*ptr == '/' || *ptr == '\\') + { break; } } - if (ptr >= string.str){ + if(ptr >= string.str) + { string.size = (U64)(ptr - string.str); } - else{ + else + { string.size = 0; } } - return(string); + return string; } internal String8 -str8_skip_last_slash(String8 string){ - if (string.size > 0){ +str8_skip_last_slash(String8 string) +{ + if(string.size > 0) + { U8 *ptr = string.str + string.size - 1; - for (;ptr >= string.str; ptr -= 1){ - if (*ptr == '/' || *ptr == '\\'){ + for(;ptr >= string.str; ptr -= 1) + { + if(*ptr == '/' || *ptr == '\\') + { break; } } - if (ptr >= string.str){ + if(ptr >= string.str) + { ptr += 1; string.size = (U64)(string.str + string.size - ptr); string.str = ptr; } } - return(string); + return string; } internal String8 @@ -1182,80 +1284,94 @@ str8_chop_last_dot(String8 string) { String8 result = string; U64 p = string.size; - for (;p > 0;){ + for(;p > 0;) + { p -= 1; - if (string.str[p] == '.'){ + if(string.str[p] == '.') + { result = str8_prefix(string, p); break; } } - return(result); + return result; } internal String8 -str8_skip_last_dot(String8 string){ +str8_skip_last_dot(String8 string) +{ String8 result = string; U64 p = string.size; - for (;p > 0;){ + for(;p > 0;) + { p -= 1; - if (string.str[p] == '.'){ + if(string.str[p] == '.') + { result = str8_skip(string, p + 1); break; } } - return(result); + return result; } internal PathStyle -path_style_from_str8(String8 string){ +path_style_from_str8(String8 string) +{ PathStyle result = PathStyle_Relative; - if (string.size >= 1 && string.str[0] == '/'){ + if(string.size >= 1 && string.str[0] == '/') + { result = PathStyle_UnixAbsolute; } - else if (string.size >= 2 && - char_is_alpha(string.str[0]) && - string.str[1] == ':'){ - if (string.size == 2 || - char_is_slash(string.str[2])){ + else if(string.size >= 2 && + char_is_alpha(string.str[0]) && + string.str[1] == ':') + { + if(string.size == 2 || char_is_slash(string.str[2])) + { result = PathStyle_WindowsAbsolute; } } - return(result); + return result; } internal String8List -str8_split_path(Arena *arena, String8 string){ +str8_split_path(Arena *arena, String8 string) +{ String8List result = str8_split(arena, string, (U8*)"/\\", 2, 0); - return(result); + return result; } internal void -str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ +str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style) +{ Temp scratch = scratch_begin(0, 0); - String8MetaNode *stack = 0; String8MetaNode *free_meta_node = 0; String8Node *first = path->first; - MemoryZeroStruct(path); - for (String8Node *node = first, *next = 0; - node != 0; - node = next){ + for(String8Node *node = first, *next = 0; + node != 0; + node = next) + { // save next now next = node->next; // cases: - if (node == first && style == PathStyle_WindowsAbsolute){ + if(node == first && style == PathStyle_WindowsAbsolute) + { goto save_without_stack; } - if (node->string.size == 1 && node->string.str[0] == '.'){ + if(node->string.size == 1 && node->string.str[0] == '.') + { goto do_nothing; } - if (node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.'){ - if (stack != 0){ + if(node->string.size == 2 && node->string.str[0] == '.' && node->string.str[1] == '.') + { + if(stack != 0) + { goto eliminate_stack_top; } - else{ + else + { goto save_without_stack; } } @@ -1266,24 +1382,23 @@ str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ save_with_stack: { str8_list_push_node(path, node); - String8MetaNode *stack_node = free_meta_node; - if (stack_node != 0){ + if(stack_node != 0) + { SLLStackPop(free_meta_node); } - else{ + else + { stack_node = push_array_no_zero(scratch.arena, String8MetaNode, 1); } SLLStackPush(stack, stack_node); stack_node->node = node; - continue; } save_without_stack: { str8_list_push_node(path, node); - continue; } @@ -1291,13 +1406,13 @@ str8_path_list_resolve_dots_in_place(String8List *path, PathStyle style){ { path->node_count -= 1; path->total_size -= stack->node->string.size; - SLLStackPop(stack); - - if (stack == 0){ + if(stack == 0) + { path->last = path->first; } - else{ + else + { path->last = stack->node; } continue; @@ -1402,7 +1517,7 @@ utf8_decode(U8 *str, U64 max){ }break; case 2: { - if (2 < max) + if (1 < max) { U8 cont_byte = str[1]; if (utf8_class[cont_byte >> 3] == 0) @@ -1827,10 +1942,10 @@ try_guid_from_string(String8 string, Guid *guid_out) 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)) + 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); @@ -1838,10 +1953,10 @@ try_guid_from_string(String8 string, Guid *guid_out) 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) + data2 <= max_U16 && + data3 <= max_U16 && + data4_hi <= max_U16 && + data4_lo <= 0xffffffffffff) { guid_out->data1 = (U32)data1; guid_out->data2 = (U16)data2; @@ -1933,7 +2048,6 @@ escaped_from_raw_str8(Arena *arena, String8 string) case '\v': {separator_replace = str8_lit("\\v");}break; case '\\': {separator_replace = str8_lit("\\\\");}break; case '"': {separator_replace = str8_lit("\\\"");}break; - case '?': {separator_replace = str8_lit("\\?");}break; } if(split) { @@ -2370,77 +2484,3 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) *block_out = str8_substr(string, range); return block_out->size; } - -internal U64 -str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) -{ - U64 value = 0; - U64 shift = 0; - U64 cursor = off; - for(;;) - { - U8 byte = 0; - U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); - - if(bytes_read != sizeof(byte)) - { - break; - } - - U8 val = byte & 0x7fu; - value |= ((U64)val) << shift; - - cursor += bytes_read; - shift += 7u; - - if((byte & 0x80u) == 0) - { - break; - } - } - if(value_out != 0) - { - *value_out = value; - } - U64 bytes_read = cursor - off; - return bytes_read; -} - -internal U64 -str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) -{ - U64 value = 0; - U64 shift = 0; - U64 cursor = off; - for(;;) - { - U8 byte; - U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); - if(bytes_read != sizeof(byte)) - { - break; - } - - U8 val = byte & 0x7fu; - value |= ((U64)val) << shift; - - cursor += bytes_read; - shift += 7u; - - if((byte & 0x80u) == 0) - { - if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) - { - value |= -(S64)(1ull << shift); - } - break; - } - } - if(value_out != 0) - { - *value_out = value; - } - U64 bytes_read = cursor - off; - return bytes_read; -} - diff --git a/src/base/base_strings.h b/src/base/base_strings.h index 67e90349..b9b155ee 100644 --- a/src/base/base_strings.h +++ b/src/base/base_strings.h @@ -96,7 +96,7 @@ typedef enum PathStyle #elif OS_LINUX PathStyle_SystemAbsolute = PathStyle_UnixAbsolute #else -# error "absolute path style is undefined for this OS" +# error Absolute path style is undefined for this OS. #endif } PathStyle; @@ -223,6 +223,7 @@ internal String8 str8_skip(String8 str, U64 amt); internal String8 str8_postfix(String8 str, U64 size); internal String8 str8_chop(String8 str, U64 amt); internal String8 str8_skip_chop_whitespace(String8 string); +internal String8 str8_skip_chop_slashes(String8 string); //////////////////////////////// //~ rjf: String Formatting & Copying @@ -287,12 +288,34 @@ internal void str8_list_from_flags(Arena *arena, String8List *list, U32 //////////////////////////////// //~ rjf; String Arrays +internal String8Array str8_array_zero(void); internal String8Array str8_array_from_list(Arena *arena, String8List *list); internal String8Array str8_array_reserve(Arena *arena, U64 count); +internal String8Array str8_array_copy(Arena *arena, String8Array array); + +//////////////////////////////// +//~ rjf: String Version Helpers + +internal U64 version_from_str8(String8 string); +internal String8 str8_from_version(Arena *arena, U64 version); //////////////////////////////// //~ rjf: String Path Helpers +global read_only struct +{ + String8 string; + PathStyle path_style; +} +g_path_style_map[] = +{ + { str8_lit_comp(""), PathStyle_Null }, + { str8_lit_comp("relative"), PathStyle_Relative }, + { str8_lit_comp("windows"), PathStyle_WindowsAbsolute }, + { str8_lit_comp("unix"), PathStyle_UnixAbsolute }, + { str8_lit_comp("system"), PathStyle_SystemAbsolute }, +}; + internal String8 str8_chop_last_slash(String8 string); internal String8 str8_skip_last_slash(String8 string); internal String8 str8_chop_last_dot(String8 string); @@ -407,8 +430,6 @@ internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size); internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out); internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out); -internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out); -internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out); #define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr))) #define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1) diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index b2515c93..90a396fe 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -26,7 +26,7 @@ internal void tctx_init_and_equip(TCTX *tctx); internal void tctx_release(void); internal TCTX* tctx_get_equipped(void); -internal Arena* tctx_get_scratch(Arena **conflicts, U64 countt); +internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); internal void tctx_set_thread_name(String8 name); internal String8 tctx_get_thread_name(void); diff --git a/src/codeview/codeview.c b/src/codeview/codeview.c index 4836c249..fbae1c89 100644 --- a/src/codeview/codeview.c +++ b/src/codeview/codeview.c @@ -14,30 +14,30 @@ cv_arch_from_coff_machine(COFF_MachineType machine) CV_Arch arch = 0; switch(machine) { - case COFF_Machine_X64: arch = CV_Arch_X64; break; - case COFF_Machine_X86: arch = CV_Arch_8086; break; - case COFF_Machine_Am33: arch = CV_Arch_AM33; break; - case COFF_Machine_Arm: NotImplemented; break; - case COFF_Machine_Arm64: arch = CV_Arch_ARM64; break; - case COFF_Machine_ArmNt: arch = CV_Arch_ARMNT; break; - case COFF_Machine_Ebc: arch = CV_Arch_EBC; break; - case COFF_Machine_Ia64: arch = CV_Arch_IA64; break; - case COFF_Machine_M32R: arch = CV_Arch_M32R; break; - case COFF_Machine_Mips16: arch = CV_Arch_MIPS16; break; - case COFF_Machine_MipsFpu: NotImplemented; break; - case COFF_Machine_MipsFpu16: NotImplemented; break; - case COFF_Machine_PowerPc: NotImplemented; break; - case COFF_Machine_PowerPcFp: arch = CV_Arch_PPCFP; break; - case COFF_Machine_R4000: NotImplemented; break; - case COFF_Machine_RiscV32: NotImplemented; break; - case COFF_Machine_RiscV64: NotImplemented; break; - case COFF_Machine_RiscV128: NotImplemented; break; - case COFF_Machine_Sh3: arch = CV_Arch_SH3; break; - case COFF_Machine_Sh3Dsp: arch = CV_Arch_SH3DSP; break; - case COFF_Machine_Sh4: arch = CV_Arch_SH4; break; - case COFF_Machine_Sh5: NotImplemented; break; - case COFF_Machine_Thumb: arch = CV_Arch_THUMB; break; - case COFF_Machine_WceMipsV2: NotImplemented; break; + case COFF_MachineType_X64: arch = CV_Arch_X64; break; + case COFF_MachineType_X86: arch = CV_Arch_8086; break; + case COFF_MachineType_Am33: arch = CV_Arch_AM33; break; + case COFF_MachineType_Arm: NotImplemented; break; + case COFF_MachineType_Arm64: arch = CV_Arch_ARM64; break; + case COFF_MachineType_ArmNt: arch = CV_Arch_ARMNT; break; + case COFF_MachineType_Ebc: arch = CV_Arch_EBC; break; + case COFF_MachineType_Ia64: arch = CV_Arch_IA64; break; + case COFF_MachineType_M32R: arch = CV_Arch_M32R; break; + case COFF_MachineType_Mips16: arch = CV_Arch_MIPS16; break; + case COFF_MachineType_MipsFpu: NotImplemented; break; + case COFF_MachineType_MipsFpu16: NotImplemented; break; + case COFF_MachineType_PowerPc: NotImplemented; break; + case COFF_MachineType_PowerPcFp: arch = CV_Arch_PPCFP; break; + case COFF_MachineType_R4000: NotImplemented; break; + case COFF_MachineType_RiscV32: NotImplemented; break; + case COFF_MachineType_RiscV64: NotImplemented; break; + case COFF_MachineType_RiscV128: NotImplemented; break; + case COFF_MachineType_Sh3: arch = CV_Arch_SH3; break; + case COFF_MachineType_Sh3Dsp: arch = CV_Arch_SH3DSP; break; + case COFF_MachineType_Sh4: arch = CV_Arch_SH4; break; + case COFF_MachineType_Sh5: NotImplemented; break; + case COFF_MachineType_Thumb: arch = CV_Arch_THUMB; break; + case COFF_MachineType_WceMipsV2: NotImplemented; break; } return arch; } diff --git a/src/codeview/codeview.mdesk b/src/codeview/codeview.mdesk index 3cfb11e6..ac511efd 100644 --- a/src/codeview/codeview.mdesk +++ b/src/codeview/codeview.mdesk @@ -395,48 +395,48 @@ CV_BasicTypeTable: {FBASICSTR 0x06 "" } {NOTTRANS 0x07 "" } {HRESULT 0x08 "HRESULT" } - {CHAR 0x10 "char" } - {SHORT 0x11 "S16" } - {LONG 0x12 "S32" } - {QUAD 0x13 "S64" } - {OCT 0x14 "S128" } + {CHAR 0x10 "CHAR" } + {SHORT 0x11 "SHORT" } + {LONG 0x12 "LONG" } + {QUAD 0x13 "QUAD" } + {OCT 0x14 "OCT" } {UCHAR 0x20 "UCHAR" } - {USHORT 0x21 "U16" } - {ULONG 0x22 "U32" } - {UQUAD 0x23 "U64" } - {UOCT 0x24 "U128" } - {BOOL8 0x30 "B8" } - {BOOL16 0x31 "B16" } - {BOOL32 0x32 "B32" } - {BOOL64 0x33 "B64" } - {FLOAT32 0x40 "F32" } - {FLOAT64 0x41 "F64" } - {FLOAT80 0x42 "F80" } - {FLOAT128 0x43 "F128" } - {FLOAT48 0x44 "F48" } - {FLOAT32PP 0x45 "F32PP" } - {FLOAT16 0x46 "F16" } + {USHORT 0x21 "USHORT" } + {ULONG 0x22 "ULONG" } + {UQUAD 0x23 "UQUAD" } + {UOCT 0x24 "UOCT" } + {BOOL8 0x30 "BOOL8" } + {BOOL16 0x31 "BOOL16" } + {BOOL32 0x32 "BOOL32" } + {BOOL64 0x33 "BOOL64" } + {FLOAT32 0x40 "FLOAT32" } + {FLOAT64 0x41 "FLOAT64" } + {FLOAT80 0x42 "FLOAT80" } + {FLOAT128 0x43 "FLOAT128" } + {FLOAT48 0x44 "FLOAT48" } + {FLOAT32PP 0x45 "FLOAT32PP" } + {FLOAT16 0x46 "FLOAT16" } {COMPLEX32 0x50 "ComplexF32" } {COMPLEX64 0x51 "ComplexF64" } {COMPLEX80 0x52 "ComplexF80" } {COMPLEX128 0x53 "ComplexF128" } {BIT 0x60 "" } {PASCHAR 0x61 "" } - {BOOL32FF 0x62 "B32FF" } - {INT8 0x68 "S8" } - {UINT8 0x69 "U8" } + {BOOL32FF 0x62 "BOOL32FF" } + {INT8 0x68 "int8" } + {UINT8 0x69 "uint8" } {RCHAR 0x70 "char" } {WCHAR 0x71 "WCHAR" } - {INT16 0x72 "S16" } - {UINT16 0x73 "U16" } - {INT32 0x74 "S32" } - {UINT32 0x75 "U32" } - {INT64 0x76 "S64" } - {UINT64 0x77 "U64" } - {INT128 0x78 "S128" } - {UINT128 0x79 "U128" } - {CHAR16 0x7a "CHAR16" } - {CHAR32 0x7b "CHAR32" } + {INT16 0x72 "int16" } + {UINT16 0x73 "uint16" } + {INT32 0x74 "int32" } + {UINT32 0x75 "uint32" } + {INT64 0x76 "int64" } + {UINT64 0x77 "uint64" } + {INT128 0x78 "int128" } + {UINT128 0x79 "uint128" } + {CHAR16 0x7a "char16" } + {CHAR32 0x7b "char32" } {CHAR8 0x7c "char" } {PTR 0xf0 "PTR" } } diff --git a/src/codeview/codeview_enum.c b/src/codeview/codeview_enum.c index 3b03411b..4413fcca 100644 --- a/src/codeview/codeview_enum.c +++ b/src/codeview/codeview_enum.c @@ -930,15 +930,6 @@ cv_string_from_itemid(Arena *arena, CV_ItemId itemid) return result; } -internal String8 -cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 result = push_str8f(arena, "%S+%x", cv_string_from_reg_id(scratch.arena, arch, reg), off); - scratch_end(scratch); - return result; -} - internal String8 cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type) { diff --git a/src/codeview/codeview_enum.h b/src/codeview/codeview_enum.h index 02167351..67095f78 100644 --- a/src/codeview/codeview_enum.h +++ b/src/codeview/codeview_enum.h @@ -41,7 +41,6 @@ internal String8 cv_string_from_defrange_register_rel_flags(Arena *arena, CV_Def internal String8 cv_string_from_field_attribs(Arena *arena, CV_FieldAttribs attribs); internal String8 cv_string_from_itype(Arena *arena, CV_TypeIndex min_itype, CV_TypeIndex itype); internal String8 cv_string_from_itemid(Arena *arena, CV_ItemId itemid); -internal String8 cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg, U32 off); internal String8 cv_string_from_symbol_type(Arena *arena, CV_SymKind symbol_type); internal String8 cv_string_from_symbol_kind(Arena *arena, CV_SymKind kind); internal String8 cv_string_from_leaf_name(Arena *arena, U32 leaf_type); diff --git a/src/codeview/codeview_parse.c b/src/codeview/codeview_parse.c index 94c72e43..57a0020c 100644 --- a/src/codeview/codeview_parse.c +++ b/src/codeview/codeview_parse.c @@ -137,6 +137,10 @@ cv_u64_from_numeric(CV_NumericParsed *num) U64 result = 0; switch(num->kind) { + case CV_NumericKind_CHAR: {result = (U64)(S64)*(S8*)num->val;}break; + case CV_NumericKind_SHORT: {result = (U64)(S64)*(S16*)num->val;}break; + case CV_NumericKind_LONG: {result = (U64)(S64)*(S32*)num->val;}break; + case CV_NumericKind_QUADWORD: {result = (U64)(S64)*(S64*)num->val;}break; case CV_NumericKind_USHORT: {result = *(U16*)num->val;}break; case CV_NumericKind_ULONG: {result = *(U32*)num->val;}break; case CV_NumericKind_UQUADWORD:{result = *(U64*)num->val;}break; @@ -273,144 +277,144 @@ internal CV_C13InlineSiteDecoderStep cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary_annots) { CV_C13InlineSiteDecoderStep result = {0}; - + for (; decoder->cursor < binary_annots.size && result.flags == 0; ) { U32 op = CV_InlineBinaryAnnotation_Null; decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &op); - + switch (op) { - case CV_InlineBinaryAnnotation_Null: { - decoder->cursor = binary_annots.size; - // this is last run, append range with left over code bytes - decoder->code_length = decoder->code_offset - decoder->code_offset_lo; - decoder->code_length_changed = 1; - } break; - case CV_InlineBinaryAnnotation_CodeOffset: { - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_offset); - decoder->code_offset_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: { - AssertAlways(!"TODO: test case"); - // U32 delta = 0; - // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); - // decoder->code_offset_base = decoder->code_offset; - // decoder->code_offset_end = decoder->code_offset + delta; - // decoder->code_offset += delta; - } break; - case CV_InlineBinaryAnnotation_ChangeCodeOffset: { - U32 delta = 0; - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); - - decoder->code_offset += delta; - - if (!decoder->code_offset_lo_changed) { - decoder->code_offset_lo = decoder->code_offset; - decoder->code_offset_lo_changed = 1; - } - decoder->code_offset_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeCodeLength: { - decoder->code_length = 0; - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); - decoder->code_length_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeFile: { - U32 old_file_off = decoder->file_off; - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->file_off); - decoder->file_off_changed = old_file_off != decoder->file_off; - // Compiler isn't obligated to terminate code sequence before chaning files, - // so we have to always force emit code range on file change. - decoder->code_length_changed = decoder->file_off_changed; - } break; - case CV_InlineBinaryAnnotation_ChangeLineOffset: { - S32 delta = 0; - decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); - - decoder->ln += delta; - decoder->ln_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeLineEndDelta: { - AssertAlways(!"TODO: test case"); - // S32 end_delta = 1; - // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); - // decoder->ln += end_delta; - } break; - case CV_InlineBinaryAnnotation_ChangeRangeKind: { - AssertAlways(!"TODO: test case"); - // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &range_kind); - } break; - case CV_InlineBinaryAnnotation_ChangeColumnStart: { - AssertAlways(!"TODO: test case"); - // S32 delta; - // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); - // decoder->cn += delta; - } break; - case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: { - AssertAlways(!"TODO: test case"); - // S32 end_delta; - // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); - // decoder->cn += end_delta; - } break; - case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: { - U32 code_offset_and_line_offset = 0; - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &code_offset_and_line_offset); - - S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); - U32 code_delta = (code_offset_and_line_offset & 0xf); - - decoder->code_offset += code_delta; - decoder->ln += line_delta; - - if (!decoder->code_offset_lo_changed) { - decoder->code_offset_lo = decoder->code_offset; - decoder->code_offset_lo_changed = 1; - } - - decoder->code_offset_changed = 1; - decoder->ln_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: { - U32 offset_delta = 0; - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); - decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &offset_delta); - - decoder->code_offset += offset_delta; - - if (!decoder->code_offset_lo_changed) { - decoder->code_offset_lo = decoder->code_offset; - decoder->code_offset_lo_changed = 1; - } - - decoder->code_offset_changed = 1; - decoder->code_length_changed = 1; - } break; - case CV_InlineBinaryAnnotation_ChangeColumnEnd: { - AssertAlways(!"TODO: test case"); - // U32 column_end = 0; - // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &column_end); - } break; + case CV_InlineBinaryAnnotation_Null: { + decoder->cursor = binary_annots.size; + // this is last run, append range with left over code bytes + decoder->code_length = decoder->code_offset - decoder->code_offset_lo; + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_CodeOffset: { + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_offset); + decoder->code_offset_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffsetBase: { + AssertAlways(!"TODO: test case"); + // U32 delta = 0; + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); + // decoder->code_offset_base = decoder->code_offset; + // decoder->code_offset_end = decoder->code_offset + delta; + // decoder->code_offset += delta; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffset: { + U32 delta = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &delta); + + decoder->code_offset += delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + decoder->code_offset_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeLength: { + decoder->code_length = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeFile: { + U32 old_file_off = decoder->file_off; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->file_off); + decoder->file_off_changed = old_file_off != decoder->file_off; + // Compiler isn't obligated to terminate code sequence before chaning files, + // so we have to always force emit code range on file change. + decoder->code_length_changed = decoder->file_off_changed; + } break; + case CV_InlineBinaryAnnotation_ChangeLineOffset: { + S32 delta = 0; + decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); + + decoder->ln += delta; + decoder->ln_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeLineEndDelta: { + AssertAlways(!"TODO: test case"); + // S32 end_delta = 1; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); + // decoder->ln += end_delta; + } break; + case CV_InlineBinaryAnnotation_ChangeRangeKind: { + AssertAlways(!"TODO: test case"); + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &range_kind); + } break; + case CV_InlineBinaryAnnotation_ChangeColumnStart: { + AssertAlways(!"TODO: test case"); + // S32 delta; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &delta); + // decoder->cn += delta; + } break; + case CV_InlineBinaryAnnotation_ChangeColumnEndDelta: { + AssertAlways(!"TODO: test case"); + // S32 end_delta; + // decoder->cursor += cv_decode_inline_annot_s32(binary_annots, decoder->cursor, &end_delta); + // decoder->cn += end_delta; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeOffsetAndLineOffset: { + U32 code_offset_and_line_offset = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &code_offset_and_line_offset); + + S32 line_delta = cv_inline_annot_signed_from_unsigned_operand(code_offset_and_line_offset >> 4); + U32 code_delta = (code_offset_and_line_offset & 0xf); + + decoder->code_offset += code_delta; + decoder->ln += line_delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + + decoder->code_offset_changed = 1; + decoder->ln_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeCodeLengthAndCodeOffset: { + U32 offset_delta = 0; + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &decoder->code_length); + decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &offset_delta); + + decoder->code_offset += offset_delta; + + if (!decoder->code_offset_lo_changed) { + decoder->code_offset_lo = decoder->code_offset; + decoder->code_offset_lo_changed = 1; + } + + decoder->code_offset_changed = 1; + decoder->code_length_changed = 1; + } break; + case CV_InlineBinaryAnnotation_ChangeColumnEnd: { + AssertAlways(!"TODO: test case"); + // U32 column_end = 0; + // decoder->cursor += cv_decode_inline_annot_u32(binary_annots, decoder->cursor, &column_end); + } break; } - + U64 line_code_offset = decoder->code_offset; - + if (decoder->code_length_changed) { // compute upper bound of the range U64 code_offset_hi = decoder->code_offset + decoder->code_length; - + // can last code range be extended to cover current sequence too? if (decoder->last_range.max == decoder->parent_voff + decoder->code_offset_lo) { decoder->last_range.max = decoder->parent_voff + code_offset_hi; - + result.flags |= CV_C13InlineSiteDecoderStepFlag_ExtendLastRange; result.range = decoder->last_range; } else { decoder->last_range = rng_1u64(decoder->parent_voff + decoder->code_offset_lo, decoder->parent_voff + code_offset_hi); decoder->file_last_range = decoder->last_range; - + result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitRange; result.range = decoder->last_range; } - + // update state decoder->code_offset_lo = code_offset_hi; decoder->code_offset += decoder->code_length; @@ -418,18 +422,18 @@ cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary decoder->code_length_changed = 0; decoder->code_length = 0; } - + if (decoder->file_off_changed || (decoder->file_count == 0)) { result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitFile; result.file_off = decoder->file_off; - + // update state decoder->file_last_range = decoder->last_range; decoder->file_off_changed = 0; decoder->file_count += 1; decoder->file_line_count = 0; } - + if (decoder->code_offset_changed && decoder->ln_changed) { if (decoder->file_line_count == 0 || decoder->file_last_ln != decoder->ln) { result.flags |= CV_C13InlineSiteDecoderStepFlag_EmitLine; @@ -437,18 +441,18 @@ cv_c13_inline_site_decoder_step(CV_C13InlineSiteDecoder *decoder, String8 binary result.cn = decoder->cn; result.line_voff = decoder->parent_voff + line_code_offset; result.line_voff_end = decoder->last_range.max; - + // update state decoder->file_line_count += 1; decoder->file_last_ln = decoder->ln; } - + // update state decoder->code_offset_changed = 0; decoder->ln_changed = 0; } } - + return result; } @@ -459,9 +463,9 @@ cv_is_udt_name_anon(String8 name) { // corresponds to fUDTAnon from dbi/tm.cpp:817 B32 is_anon = str8_match_lit("", name, 0) || - str8_match_lit("__unnamed", name, 0) || - str8_match_lit("::", name, StringMatchFlag_RightSideSloppy) || - str8_match_lit("::__unnamed", name, StringMatchFlag_RightSideSloppy); + str8_match_lit("__unnamed", name, 0) || + str8_match_lit("::", name, StringMatchFlag_RightSideSloppy) || + str8_match_lit("::__unnamed", name, StringMatchFlag_RightSideSloppy); return is_anon; } @@ -469,15 +473,15 @@ internal B32 cv_is_udt(CV_LeafKind kind) { B32 is_udt = kind == CV_LeafKind_CLASS || - kind == CV_LeafKind_STRUCTURE || - kind == CV_LeafKind_CLASS2 || - kind == CV_LeafKind_STRUCT2 || - kind == CV_LeafKind_INTERFACE || - kind == CV_LeafKind_UNION || - kind == CV_LeafKind_ENUM || - kind == CV_LeafKind_UDT_MOD_SRC_LINE || - kind == CV_LeafKind_UDT_SRC_LINE || - kind == CV_LeafKind_ALIAS; + kind == CV_LeafKind_STRUCTURE || + kind == CV_LeafKind_CLASS2 || + kind == CV_LeafKind_STRUCT2 || + kind == CV_LeafKind_INTERFACE || + kind == CV_LeafKind_UNION || + kind == CV_LeafKind_ENUM || + kind == CV_LeafKind_UDT_MOD_SRC_LINE || + kind == CV_LeafKind_UDT_SRC_LINE || + kind == CV_LeafKind_ALIAS; return is_udt; } @@ -485,13 +489,13 @@ internal B32 cv_is_global_symbol(CV_SymKind kind) { B32 is_global_symbol = kind == CV_SymKind_CONSTANT || - kind == CV_SymKind_GDATA16 || - kind == CV_SymKind_GDATA32_16t || - kind == CV_SymKind_GDATA32_ST || - kind == CV_SymKind_GDATA32 || - kind == CV_SymKind_GTHREAD32_16t || - kind == CV_SymKind_GTHREAD32_ST || - kind == CV_SymKind_GTHREAD32; + kind == CV_SymKind_GDATA16 || + kind == CV_SymKind_GDATA32_16t || + kind == CV_SymKind_GDATA32_ST || + kind == CV_SymKind_GDATA32 || + kind == CV_SymKind_GTHREAD32_16t || + kind == CV_SymKind_GTHREAD32_ST || + kind == CV_SymKind_GTHREAD32; return is_global_symbol; } @@ -499,8 +503,8 @@ internal B32 cv_is_typedef(CV_SymKind kind) { B32 is_typedef = kind == CV_SymKind_UDT_16t || - kind == CV_SymKind_UDT_ST || - kind == CV_SymKind_UDT; + kind == CV_SymKind_UDT_ST || + kind == CV_SymKind_UDT; return is_typedef; } @@ -508,15 +512,15 @@ internal B32 cv_is_scope_symbol(CV_SymKind kind) { B32 is_scope = kind == CV_SymKind_GPROC32 || - kind == CV_SymKind_LPROC32 || - kind == CV_SymKind_BLOCK32 || - kind == CV_SymKind_THUNK32 || - kind == CV_SymKind_INLINESITE || - kind == CV_SymKind_INLINESITE2 || - kind == CV_SymKind_WITH32 || - kind == CV_SymKind_SEPCODE || - kind == CV_SymKind_GPROC32_ID || - kind == CV_SymKind_LPROC32_ID; + kind == CV_SymKind_LPROC32 || + kind == CV_SymKind_BLOCK32 || + kind == CV_SymKind_THUNK32 || + kind == CV_SymKind_INLINESITE || + kind == CV_SymKind_INLINESITE2 || + kind == CV_SymKind_WITH32 || + kind == CV_SymKind_SEPCODE || + kind == CV_SymKind_GPROC32_ID || + kind == CV_SymKind_LPROC32_ID; return is_scope; } @@ -524,8 +528,8 @@ internal B32 cv_is_end_symbol(CV_SymKind kind) { B32 is_end = kind == CV_SymKind_END || - kind == CV_SymKind_PROC_ID_END || - kind == CV_SymKind_INLINESITE_END; + kind == CV_SymKind_PROC_ID_END || + kind == CV_SymKind_INLINESITE_END; return is_end; } @@ -533,8 +537,8 @@ internal B32 cv_is_leaf_type_server(CV_LeafKind kind) { B32 is_type_server = kind == CV_LeafKind_TYPESERVER || - kind == CV_LeafKind_TYPESERVER2 || - kind == CV_LeafKind_TYPESERVER_ST; + kind == CV_LeafKind_TYPESERVER2 || + kind == CV_LeafKind_TYPESERVER_ST; return is_type_server; } @@ -542,8 +546,8 @@ internal B32 cv_is_leaf_pch(CV_LeafKind kind) { B32 is_pch = kind == CV_LeafKind_PRECOMP || - kind == CV_LeafKind_PRECOMP_ST || - kind == CV_LeafKind_PRECOMP_16t; + kind == CV_LeafKind_PRECOMP_ST || + kind == CV_LeafKind_PRECOMP_16t; return is_pch; } @@ -552,12 +556,12 @@ cv_type_index_source_from_leaf_kind(CV_LeafKind leaf_kind) { CV_TypeIndexSource source; if(leaf_kind == CV_LeafKind_FUNC_ID || - leaf_kind == CV_LeafKind_MFUNC_ID || - leaf_kind == CV_LeafKind_BUILDINFO || - leaf_kind == CV_LeafKind_SUBSTR_LIST || - leaf_kind == CV_LeafKind_STRING_ID || - leaf_kind == CV_LeafKind_UDT_SRC_LINE || - leaf_kind == CV_LeafKind_UDT_MOD_SRC_LINE) + leaf_kind == CV_LeafKind_MFUNC_ID || + leaf_kind == CV_LeafKind_BUILDINFO || + leaf_kind == CV_LeafKind_SUBSTR_LIST || + leaf_kind == CV_LeafKind_STRING_ID || + leaf_kind == CV_LeafKind_UDT_SRC_LINE || + leaf_kind == CV_LeafKind_UDT_MOD_SRC_LINE) { source = CV_TypeIndexSource_IPI; } @@ -579,10 +583,10 @@ cv_symbol_type_index_info_push(Arena *arena, CV_TypeIndexInfoList *list, CV_Type info->next = 0; info->offset = offset; info->source = source; - + SLLQueuePush(list->first, list->last, info); list->count += 1; - + return info; } @@ -591,63 +595,63 @@ cv_get_symbol_type_index_offsets(Arena *arena, CV_SymKind kind, String8 data) { CV_TypeIndexInfoList list = {0}; switch (kind) { - case CV_SymKind_BUILDINFO: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymBuildInfo, id)); - } break; - case CV_SymKind_GDATA32: - case CV_SymKind_LDATA32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymData32, itype)); - } break; - case CV_SymKind_LPROC32_ID: - case CV_SymKind_GPROC32_ID: - case CV_SymKind_LPROC32_DPC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymProc32, itype)); - } break; - case CV_SymKind_GPROC32: - case CV_SymKind_LPROC32: - case CV_SymKind_LPROC32_DPC: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymProc32, itype)); - } break; - case CV_SymKind_UDT: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymUDT, itype)); - } break; - case CV_SymKind_GTHREAD32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymThread32, itype)); - } break; - case CV_SymKind_FILESTATIC: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymFileStatic, itype)); - } break; - case CV_SymKind_LOCAL: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymLocal, itype)); - } break; - case CV_SymKind_REGREL32: - case CV_SymKind_BPREL32: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegrel32, itype)); - } break; - case CV_SymKind_REGISTER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegister, itype)); - } break; - case CV_SymKind_CONSTANT: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymConstant, itype)); - } break; - case CV_SymKind_CALLSITEINFO: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymCallSiteInfo, itype)); - } break; - case CV_SymKind_CALLERS: - case CV_SymKind_CALLEES: - case CV_SymKind_INLINEES: { - Assert(data.size >= sizeof(CV_SymFunctionList)); - CV_SymFunctionList *func_list = (CV_SymFunctionList*)data.str; - for (U64 i = 0; i < func_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_SymFunctionList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_SymKind_INLINESITE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymInlineSite, inlinee)); - } break; - case CV_SymKind_HEAPALLOCSITE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymHeapAllocSite, itype)); - } break; + case CV_SymKind_BUILDINFO: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymBuildInfo, id)); + } break; + case CV_SymKind_GDATA32: + case CV_SymKind_LDATA32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymData32, itype)); + } break; + case CV_SymKind_LPROC32_ID: + case CV_SymKind_GPROC32_ID: + case CV_SymKind_LPROC32_DPC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymProc32, itype)); + } break; + case CV_SymKind_GPROC32: + case CV_SymKind_LPROC32: + case CV_SymKind_LPROC32_DPC: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymProc32, itype)); + } break; + case CV_SymKind_UDT: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymUDT, itype)); + } break; + case CV_SymKind_GTHREAD32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymThread32, itype)); + } break; + case CV_SymKind_FILESTATIC: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymFileStatic, itype)); + } break; + case CV_SymKind_LOCAL: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymLocal, itype)); + } break; + case CV_SymKind_REGREL32: + case CV_SymKind_BPREL32: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegrel32, itype)); + } break; + case CV_SymKind_REGISTER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymRegister, itype)); + } break; + case CV_SymKind_CONSTANT: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymConstant, itype)); + } break; + case CV_SymKind_CALLSITEINFO: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymCallSiteInfo, itype)); + } break; + case CV_SymKind_CALLERS: + case CV_SymKind_CALLEES: + case CV_SymKind_INLINEES: { + Assert(data.size >= sizeof(CV_SymFunctionList)); + CV_SymFunctionList *func_list = (CV_SymFunctionList*)data.str; + for (U64 i = 0; i < func_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_SymFunctionList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_SymKind_INLINESITE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_SymInlineSite, inlinee)); + } break; + case CV_SymKind_HEAPALLOCSITE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_SymHeapAllocSite, itype)); + } break; } return list; } @@ -657,295 +661,295 @@ cv_get_leaf_type_index_offsets(Arena *arena, CV_LeafKind leaf_kind, String8 data { CV_TypeIndexInfoList list = {0}; switch (leaf_kind) { - case CV_LeafKind_NOTYPE: - case CV_LeafKind_VTSHAPE: - case CV_LeafKind_LABEL: - case CV_LeafKind_NULL: - case CV_LeafKind_NOTTRAN: { - // no type indices - } break; - case CV_LeafKind_MODIFIER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafModifier, itype)); - } break; - case CV_LeafKind_POINTER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafPointer, itype)); - CV_LeafPointer *ptr = (CV_LeafPointer *)data.str; - CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs); - if (ptr_kind == CV_PointerKind_BaseType) { - // TODO: add CV_LeafPointerBaseType - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); - } else { - CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs); - if (ptr_mode == CV_PointerMode_PtrMem || ptr_mode == CV_PointerMode_PtrMethod) { - // TODO: add type for the CvLeafPointerMember to syms_cv.mc + case CV_LeafKind_NOTYPE: + case CV_LeafKind_VTSHAPE: + case CV_LeafKind_LABEL: + case CV_LeafKind_NULL: + case CV_LeafKind_NOTTRAN: { + // no type indices + } break; + case CV_LeafKind_MODIFIER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafModifier, itype)); + } break; + case CV_LeafKind_POINTER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafPointer, itype)); + CV_LeafPointer *ptr = (CV_LeafPointer *)data.str; + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(ptr->attribs); + if (ptr_kind == CV_PointerKind_BaseType) { + // TODO: add CV_LeafPointerBaseType cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); - } - } - } break; - case CV_LeafKind_ARRAY: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, entry_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, index_itype)); - } break; - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - case CV_LeafKind_INTERFACE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, field_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, derived_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, vshape_itype)); - } break; - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, field_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, derived_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, vshape_itype)); - } break; - case CV_LeafKind_UNION: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUnion, field_itype)); - } break; - case CV_LeafKind_ALIAS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafAlias, itype)); - } break; - case CV_LeafKind_FUNC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafFuncId, scope_string_id)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafFuncId, itype)); - } break; - case CV_LeafKind_MFUNC_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, owner_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, itype)); - } break; - case CV_LeafKind_STRING_ID: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafStringId, substr_list_id)); - } break; - case CV_LeafKind_UDT_SRC_LINE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTSrcLine, udt_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTSrcLine, src_string_id)); - } break; - case CV_LeafKind_UDT_MOD_SRC_LINE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTModSrcLine, udt_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTModSrcLine, src_string_id)); - } break; - case CV_LeafKind_BUILDINFO: { - Assert(data.size >= sizeof(CV_LeafBuildInfo)); - CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo *)data.str; - for (U16 i = 0; i < build_info->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafBuildInfo) + i * sizeof(CV_ItemId)); - } - } break; - case CV_LeafKind_ENUM: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, base_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, field_itype)); - } break; - case CV_LeafKind_PROCEDURE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, ret_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, arg_itype)); - } break; - case CV_LeafKind_MFUNCTION: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, ret_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, class_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, this_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, arg_itype)); - } break; - case CV_LeafKind_VFTABLE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, owner_itype)); - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, base_table_itype)); - } break; - case CV_LeafKind_VFTPATH: { - Assert(sizeof(CV_LeafVFPath) <= data.size); - CV_LeafVFPath *vfpath = (CV_LeafVFPath *)data.str; - for (U32 i = 0; i < vfpath->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafVFPath) + i * sizeof(CV_TypeId)); - } - } break; - case CV_LeafKind_TYPESERVER: - case CV_LeafKind_TYPESERVER2: - case CV_LeafKind_TYPESERVER_ST: { - // no type indices - } break; - case CV_LeafKind_SKIP: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafSkip, itype)); - } break; - case CV_LeafKind_SUBSTR_LIST: { - Assert(sizeof(CV_LeafArgList) <= data.size); - CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; - for (U32 i = 0; i < arg_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_LeafKind_ARGLIST: { - Assert(sizeof(CV_LeafArgList) <= data.size); - CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; - for (U32 i = 0; i < arg_list->count; ++i) { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); - } - } break; - case CV_LeafKind_LIST: - case CV_LeafKind_FIELDLIST: { - for (U64 cursor = 0; cursor < data.size; ) { - CV_LeafKind list_member_kind = 0; - U64 read_size = str8_deserial_read_struct(data, cursor, &list_member_kind); - - if(read_size != sizeof(list_member_kind)) { - Assert(!"malformed LF_FIELDLIST"); - break; - } - cursor += read_size; - - switch (list_member_kind) { - default: Assert(!"TODO: handle malformed field member"); break; - case CV_LeafKind_INDEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafIndex, itype)); - cursor += sizeof(CV_LeafIndex); - } break; - case CV_LeafKind_MEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMember, itype)); - cursor += sizeof(CV_LeafMember); - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_STMEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafStMember, itype)); - cursor += sizeof(CV_LeafStMember); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_METHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethod, list_itype)); - cursor += sizeof(CV_LeafMethod); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_ONEMETHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafOneMethod, itype)); - - CV_LeafOneMethod onemethod; - cursor += str8_deserial_read_struct(data, cursor, &onemethod); - - CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(onemethod.attribs); - if(prop == CV_MethodProp_PureIntro || prop == CV_MethodProp_Intro) - { - cursor += sizeof(U32); // virtoff + } else { + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(ptr->attribs); + if (ptr_mode == CV_PointerMode_PtrMem || ptr_mode == CV_PointerMode_PtrMethod) { + // TODO: add type for the CvLeafPointerMember to syms_cv.mc + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafPointer) + 0); } - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_ENUMERATE: { - // no type index - cursor += sizeof(CV_LeafEnumerate); - CV_NumericParsed value; - cursor += cv_read_numeric(data, cursor, &value); - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_NESTTYPE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestType, itype)); - cursor += sizeof(CV_LeafNestType); - - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_NESTTYPEEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestTypeEx, itype)); - - cursor += sizeof(CV_LeafNestTypeEx); - String8 name; - cursor += str8_deserial_read_cstr(data, cursor, &name); - } break; - case CV_LeafKind_BCLASS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafBClass, itype)); - - cursor += sizeof(CV_LeafBClass); - CV_NumericParsed offset; - cursor += cv_read_numeric(data, cursor, &offset); - } break; - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVBClass, itype)); - cursor += sizeof(CV_LeafVBClass); - - CV_NumericParsed virtual_base_pointer; - cursor += cv_read_numeric(data, cursor, &virtual_base_pointer); - - CV_NumericParsed virtual_base_offset; - cursor += cv_read_numeric(data, cursor, &virtual_base_offset); - } break; - case CV_LeafKind_VFUNCTAB: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncTab, itype)); - cursor += sizeof(CV_LeafVFuncTab); - } break; - case CV_LeafKind_VFUNCOFF: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncOff, itype)); - cursor += sizeof(CV_LeafVFuncOff); - } break; } - cursor = AlignPow2(cursor, 4); - } - } break; - case CV_LeafKind_METHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMethod, list_itype)); - } break; - case CV_LeafKind_METHODLIST: { - for (U64 cursor = 0; cursor < data.size; ) { - // read method - CV_LeafMethodListMember method; - U64 read_size = str8_deserial_read_struct(data, cursor, &method); - - // error check read - if (read_size != sizeof(method)) { - Assert(!"malformed LF_METHODLIST"); - break; + } break; + case CV_LeafKind_ARRAY: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, entry_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafArray, index_itype)); + } break; + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + case CV_LeafKind_INTERFACE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, field_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, derived_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct, vshape_itype)); + } break; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, field_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, derived_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafStruct2, vshape_itype)); + } break; + case CV_LeafKind_UNION: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUnion, field_itype)); + } break; + case CV_LeafKind_ALIAS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafAlias, itype)); + } break; + case CV_LeafKind_FUNC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafFuncId, scope_string_id)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafFuncId, itype)); + } break; + case CV_LeafKind_MFUNC_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, owner_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFuncId, itype)); + } break; + case CV_LeafKind_STRING_ID: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafStringId, substr_list_id)); + } break; + case CV_LeafKind_UDT_SRC_LINE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTSrcLine, udt_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTSrcLine, src_string_id)); + } break; + case CV_LeafKind_UDT_MOD_SRC_LINE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafUDTModSrcLine, udt_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, OffsetOf(CV_LeafUDTModSrcLine, src_string_id)); + } break; + case CV_LeafKind_BUILDINFO: { + Assert(data.size >= sizeof(CV_LeafBuildInfo)); + CV_LeafBuildInfo *build_info = (CV_LeafBuildInfo *)data.str; + for (U16 i = 0; i < build_info->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafBuildInfo) + i * sizeof(CV_ItemId)); } - - // push type index offset - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethodListMember, itype)); - - // take into account intro virtual offset - CV_MethodProp mprop = CV_FieldAttribs_Extract_MethodProp(method.attribs); - if (mprop == CV_MethodProp_Intro || mprop == CV_MethodProp_PureIntro) { - read_size += sizeof(U32); + } break; + case CV_LeafKind_ENUM: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, base_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafEnum, field_itype)); + } break; + case CV_LeafKind_PROCEDURE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, ret_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafProcedure, arg_itype)); + } break; + case CV_LeafKind_MFUNCTION: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, ret_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, class_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, this_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMFunction, arg_itype)); + } break; + case CV_LeafKind_VFTABLE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, owner_itype)); + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFTable, base_table_itype)); + } break; + case CV_LeafKind_VFTPATH: { + Assert(sizeof(CV_LeafVFPath) <= data.size); + CV_LeafVFPath *vfpath = (CV_LeafVFPath *)data.str; + for (U32 i = 0; i < vfpath->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafVFPath) + i * sizeof(CV_TypeId)); } - - // advance - cursor += read_size; - } - } break; - case CV_LeafKind_ONEMETHOD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafOneMethod, itype)); - } break; - case CV_LeafKind_BITFIELD: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafBitField, itype)); - } break; - case CV_LeafKind_PRECOMP: - case CV_LeafKind_REFSYM: { - // no type indices - } break; - case CV_LeafKind_INDEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafIndex, itype)); - } break; - case CV_LeafKind_MEMBER: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMember, itype)); - } break; - case CV_LeafKind_VFUNCTAB: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncTab, itype)); - } break; - case CV_LeafKind_VFUNCOFF: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncOff, itype)); - } break; - case CV_LeafKind_NESTTYPE: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestType, itype)); - } break; - case CV_LeafKind_NESTTYPEEX: { - cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestTypeEx, itype)); - } break; - default: { - NotImplemented; - } break; + } break; + case CV_LeafKind_TYPESERVER: + case CV_LeafKind_TYPESERVER2: + case CV_LeafKind_TYPESERVER_ST: { + // no type indices + } break; + case CV_LeafKind_SKIP: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafSkip, itype)); + } break; + case CV_LeafKind_SUBSTR_LIST: { + Assert(sizeof(CV_LeafArgList) <= data.size); + CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; + for (U32 i = 0; i < arg_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_LeafKind_ARGLIST: { + Assert(sizeof(CV_LeafArgList) <= data.size); + CV_LeafArgList *arg_list = (CV_LeafArgList*)data.str; + for (U32 i = 0; i < arg_list->count; ++i) { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, sizeof(CV_LeafArgList) + i * sizeof(CV_TypeIndex)); + } + } break; + case CV_LeafKind_LIST: + case CV_LeafKind_FIELDLIST: { + for (U64 cursor = 0; cursor < data.size; ) { + CV_LeafKind list_member_kind = 0; + U64 read_size = str8_deserial_read_struct(data, cursor, &list_member_kind); + + if(read_size != sizeof(list_member_kind)) { + Assert(!"malformed LF_FIELDLIST"); + break; + } + cursor += read_size; + + switch (list_member_kind) { + default: Assert(!"TODO: handle malformed field member"); break; + case CV_LeafKind_INDEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafIndex, itype)); + cursor += sizeof(CV_LeafIndex); + } break; + case CV_LeafKind_MEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMember, itype)); + cursor += sizeof(CV_LeafMember); + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_STMEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafStMember, itype)); + cursor += sizeof(CV_LeafStMember); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_METHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethod, list_itype)); + cursor += sizeof(CV_LeafMethod); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_ONEMETHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafOneMethod, itype)); + + CV_LeafOneMethod onemethod; + cursor += str8_deserial_read_struct(data, cursor, &onemethod); + + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(onemethod.attribs); + if(prop == CV_MethodProp_PureIntro || prop == CV_MethodProp_Intro) + { + cursor += sizeof(U32); // virtoff + } + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_ENUMERATE: { + // no type index + cursor += sizeof(CV_LeafEnumerate); + CV_NumericParsed value; + cursor += cv_read_numeric(data, cursor, &value); + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_NESTTYPE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestType, itype)); + cursor += sizeof(CV_LeafNestType); + + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_NESTTYPEEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafNestTypeEx, itype)); + + cursor += sizeof(CV_LeafNestTypeEx); + String8 name; + cursor += str8_deserial_read_cstr(data, cursor, &name); + } break; + case CV_LeafKind_BCLASS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafBClass, itype)); + + cursor += sizeof(CV_LeafBClass); + CV_NumericParsed offset; + cursor += cv_read_numeric(data, cursor, &offset); + } break; + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVBClass, itype)); + cursor += sizeof(CV_LeafVBClass); + + CV_NumericParsed virtual_base_pointer; + cursor += cv_read_numeric(data, cursor, &virtual_base_pointer); + + CV_NumericParsed virtual_base_offset; + cursor += cv_read_numeric(data, cursor, &virtual_base_offset); + } break; + case CV_LeafKind_VFUNCTAB: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncTab, itype)); + cursor += sizeof(CV_LeafVFuncTab); + } break; + case CV_LeafKind_VFUNCOFF: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafVFuncOff, itype)); + cursor += sizeof(CV_LeafVFuncOff); + } break; + } + cursor = AlignPow2(cursor, 4); + } + } break; + case CV_LeafKind_METHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMethod, list_itype)); + } break; + case CV_LeafKind_METHODLIST: { + for (U64 cursor = 0; cursor < data.size; ) { + // read method + CV_LeafMethodListMember method; + U64 read_size = str8_deserial_read_struct(data, cursor, &method); + + // error check read + if (read_size != sizeof(method)) { + Assert(!"malformed LF_METHODLIST"); + break; + } + + // push type index offset + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, cursor + OffsetOf(CV_LeafMethodListMember, itype)); + + // take into account intro virtual offset + CV_MethodProp mprop = CV_FieldAttribs_Extract_MethodProp(method.attribs); + if (mprop == CV_MethodProp_Intro || mprop == CV_MethodProp_PureIntro) { + read_size += sizeof(U32); + } + + // advance + cursor += read_size; + } + } break; + case CV_LeafKind_ONEMETHOD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafOneMethod, itype)); + } break; + case CV_LeafKind_BITFIELD: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafBitField, itype)); + } break; + case CV_LeafKind_PRECOMP: + case CV_LeafKind_REFSYM: { + // no type indices + } break; + case CV_LeafKind_INDEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafIndex, itype)); + } break; + case CV_LeafKind_MEMBER: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafMember, itype)); + } break; + case CV_LeafKind_VFUNCTAB: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncTab, itype)); + } break; + case CV_LeafKind_VFUNCOFF: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafVFuncOff, itype)); + } break; + case CV_LeafKind_NESTTYPE: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestType, itype)); + } break; + case CV_LeafKind_NESTTYPEEX: { + cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_TPI, OffsetOf(CV_LeafNestTypeEx, itype)); + } break; + default: { + NotImplemented; + } break; } return list; } @@ -954,34 +958,34 @@ internal CV_TypeIndexInfoList cv_get_inlinee_type_index_offsets(Arena *arena, String8 raw_data) { CV_TypeIndexInfoList list = {0}; - + U64 cursor = 0; - + // first four bytes are always signature CV_C13InlineeLinesSig sig = max_U32; cursor += str8_deserial_read_struct(raw_data, cursor, &sig); - + while(cursor < raw_data.size) { // read header CV_C13InlineeSourceLineHeader *header = (CV_C13InlineeSourceLineHeader *) str8_deserial_get_raw_ptr(raw_data, cursor, sizeof(CV_C13InlineeSourceLineHeader)); - + // store type index offset cv_symbol_type_index_info_push(arena, &list, CV_TypeIndexSource_IPI, cursor + OffsetOf(CV_C13InlineeSourceLineHeader, inlinee)); - + // advance past header cursor += sizeof(*header); - + // skip extra files B32 has_extra_files = (sig == CV_C13InlineeLinesSig_EXTRA_FILES); if (has_extra_files) - { + { U32 file_count = 0; cursor += str8_deserial_read_struct(raw_data, cursor, &file_count); cursor += /* file id: */ sizeof(U32) * file_count; } } - + return list; } @@ -993,17 +997,17 @@ cv_get_data_around_type_indices(Arena *arena, CV_TypeIndexInfoList ti_list, Stri { result.count = ti_list.count + 1; result.v = push_array_no_zero(arena, String8, result.count); - + U64 cursor = 0; U64 ti_idx = 0; - + for(CV_TypeIndexInfo *ti_info = ti_list.first; ti_info != 0; ti_info = ti_info->next, ++ti_idx) - { + { result.v[ti_idx].size = ti_info->offset - cursor; result.v[ti_idx].str = data.str + cursor; cursor = ti_info->offset + sizeof(CV_TypeIndex); } - + result.v[result.count-1].size = data.size - cursor; result.v[result.count-1].str = data.str + cursor; } @@ -1021,62 +1025,62 @@ cv_name_offset_from_symbol(CV_SymKind kind, String8 data) { U64 offset = data.size; switch (kind) { - case CV_SymKind_COMPILE: break; - case CV_SymKind_OBJNAME: break; - case CV_SymKind_THUNK32: { - offset = sizeof(CV_SymThunk32); - } break; - case CV_SymKind_LABEL32: { - offset = sizeof(CV_SymLabel32); - } break; - case CV_SymKind_REGISTER: { - offset = sizeof(CV_SymRegister); - } break; - case CV_SymKind_CONSTANT: { - offset = sizeof(CV_SymConstant); - CV_NumericParsed size; - offset += cv_read_numeric(data, offset, &size); - } break; - case CV_SymKind_UDT: { - offset = sizeof(CV_SymUDT); - } break; - case CV_SymKind_BPREL32: { - offset = sizeof(CV_SymBPRel32); - } break; - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: { - offset = sizeof(CV_SymData32); - } break; - case CV_SymKind_PUB32: { - offset = sizeof(CV_SymPub32); - } break; - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - case CV_SymKind_LPROC32_ID: - case CV_SymKind_GPROC32_ID: { - offset = sizeof(CV_SymProc32); - } break; - case CV_SymKind_REGREL32: { - offset = sizeof(CV_SymRegrel32); - } break; - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: { - offset = sizeof(CV_SymData32); - } break; - case CV_SymKind_COMPILE2: break; - case CV_SymKind_LOCALSLOT: { - offset = sizeof(CV_SymSlot); - } break; - case CV_SymKind_PROCREF: - case CV_SymKind_LPROCREF: - case CV_SymKind_DATAREF: { - offset = sizeof(CV_SymRef2); - } break; - case CV_SymKind_TRAMPOLINE: break; - case CV_SymKind_LOCAL: { - offset = sizeof(CV_SymLocal); - } break; - default: InvalidPath; + case CV_SymKind_COMPILE: break; + case CV_SymKind_OBJNAME: break; + case CV_SymKind_THUNK32: { + offset = sizeof(CV_SymThunk32); + } break; + case CV_SymKind_LABEL32: { + offset = sizeof(CV_SymLabel32); + } break; + case CV_SymKind_REGISTER: { + offset = sizeof(CV_SymRegister); + } break; + case CV_SymKind_CONSTANT: { + offset = sizeof(CV_SymConstant); + CV_NumericParsed size; + offset += cv_read_numeric(data, offset, &size); + } break; + case CV_SymKind_UDT: { + offset = sizeof(CV_SymUDT); + } break; + case CV_SymKind_BPREL32: { + offset = sizeof(CV_SymBPRel32); + } break; + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: { + offset = sizeof(CV_SymData32); + } break; + case CV_SymKind_PUB32: { + offset = sizeof(CV_SymPub32); + } break; + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + case CV_SymKind_LPROC32_ID: + case CV_SymKind_GPROC32_ID: { + offset = sizeof(CV_SymProc32); + } break; + case CV_SymKind_REGREL32: { + offset = sizeof(CV_SymRegrel32); + } break; + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: { + offset = sizeof(CV_SymData32); + } break; + case CV_SymKind_COMPILE2: break; + case CV_SymKind_LOCALSLOT: { + offset = sizeof(CV_SymSlot); + } break; + case CV_SymKind_PROCREF: + case CV_SymKind_LPROCREF: + case CV_SymKind_DATAREF: { + offset = sizeof(CV_SymRef2); + } break; + case CV_SymKind_TRAMPOLINE: break; + case CV_SymKind_LOCAL: { + offset = sizeof(CV_SymLocal); + } break; + default: InvalidPath; } return offset; } @@ -1099,95 +1103,95 @@ cv_get_udt_info(CV_LeafKind kind, String8 data) CV_TypeProps props = 0; switch(kind) { - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - case CV_LeafKind_INTERFACE: { - U64 cursor = 0; + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + case CV_LeafKind_INTERFACE: { + U64 cursor = 0; + + CV_LeafStruct udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if (udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; - CV_LeafStruct udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: { + U64 cursor = 0; + + CV_LeafStruct2 udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if (udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); + case CV_LeafKind_UNION: { + U64 cursor = 0; + + CV_LeafUnion udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + CV_NumericParsed size; + cursor += cv_read_numeric(data, cursor, &size); + + props = udt.props; + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if(udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; - cursor += str8_deserial_read_cstr(data, cursor, &name); + case CV_LeafKind_ENUM: { + U64 cursor = 0; + + CV_LeafEnum udt; + cursor += str8_deserial_read_struct(data, cursor, &udt); + + props = udt.props; + + cursor += str8_deserial_read_cstr(data, cursor, &name); + + if(udt.props & CV_TypeProp_HasUniqueName) { + cursor += str8_deserial_read_cstr(data, cursor, &unique_name); + } + } break; - if (udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: { - U64 cursor = 0; - - CV_LeafStruct2 udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if (udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_UNION: { - U64 cursor = 0; + // dbi/tpi.cpp:1332 + case CV_LeafKind_UDT_SRC_LINE: { + CV_LeafUDTSrcLine *src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTSrcLine)); + name = str8_struct(&src_line->udt_itype); + } break; + case CV_LeafKind_UDT_MOD_SRC_LINE: { + CV_LeafUDTModSrcLine *mod_src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTModSrcLine)); + name = str8_struct(&mod_src_line->udt_itype); + } break; - CV_LeafUnion udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - CV_NumericParsed size; - cursor += cv_read_numeric(data, cursor, &size); - - props = udt.props; + case CV_LeafKind_ALIAS: { + str8_deserial_read_cstr(data, 0, &name); + } break; - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if(udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - case CV_LeafKind_ENUM: { - U64 cursor = 0; - - CV_LeafEnum udt; - cursor += str8_deserial_read_struct(data, cursor, &udt); - - props = udt.props; - - cursor += str8_deserial_read_cstr(data, cursor, &name); - - if(udt.props & CV_TypeProp_HasUniqueName) { - cursor += str8_deserial_read_cstr(data, cursor, &unique_name); - } - } break; - - // dbi/tpi.cpp:1332 - case CV_LeafKind_UDT_SRC_LINE: { - CV_LeafUDTSrcLine *src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTSrcLine)); - name = str8_struct(&src_line->udt_itype); - } break; - case CV_LeafKind_UDT_MOD_SRC_LINE: { - CV_LeafUDTModSrcLine *mod_src_line = str8_deserial_get_raw_ptr(data, 0, sizeof(CV_LeafUDTModSrcLine)); - name = str8_struct(&mod_src_line->udt_itype); - } break; - - case CV_LeafKind_ALIAS: { - str8_deserial_read_cstr(data, 0, &name); - } break; - - default: { - InvalidPath; - } break; + default: { + InvalidPath; + } break; } CV_UDTInfo info = {0}; diff --git a/src/codeview/generated/codeview.meta.c b/src/codeview/generated/codeview.meta.c index 7e5be454..898e4989 100644 --- a/src/codeview/generated/codeview.meta.c +++ b/src/codeview/generated/codeview.meta.c @@ -392,48 +392,48 @@ case CV_BasicType_NBASICSTR:{result = str8_lit("");}break; case CV_BasicType_FBASICSTR:{result = str8_lit("");}break; case CV_BasicType_NOTTRANS:{result = str8_lit("");}break; case CV_BasicType_HRESULT:{result = str8_lit("HRESULT");}break; -case CV_BasicType_CHAR:{result = str8_lit("char");}break; -case CV_BasicType_SHORT:{result = str8_lit("S16");}break; -case CV_BasicType_LONG:{result = str8_lit("S32");}break; -case CV_BasicType_QUAD:{result = str8_lit("S64");}break; -case CV_BasicType_OCT:{result = str8_lit("S128");}break; +case CV_BasicType_CHAR:{result = str8_lit("CHAR");}break; +case CV_BasicType_SHORT:{result = str8_lit("SHORT");}break; +case CV_BasicType_LONG:{result = str8_lit("LONG");}break; +case CV_BasicType_QUAD:{result = str8_lit("QUAD");}break; +case CV_BasicType_OCT:{result = str8_lit("OCT");}break; case CV_BasicType_UCHAR:{result = str8_lit("UCHAR");}break; -case CV_BasicType_USHORT:{result = str8_lit("U16");}break; -case CV_BasicType_ULONG:{result = str8_lit("U32");}break; -case CV_BasicType_UQUAD:{result = str8_lit("U64");}break; -case CV_BasicType_UOCT:{result = str8_lit("U128");}break; -case CV_BasicType_BOOL8:{result = str8_lit("B8");}break; -case CV_BasicType_BOOL16:{result = str8_lit("B16");}break; -case CV_BasicType_BOOL32:{result = str8_lit("B32");}break; -case CV_BasicType_BOOL64:{result = str8_lit("B64");}break; -case CV_BasicType_FLOAT32:{result = str8_lit("F32");}break; -case CV_BasicType_FLOAT64:{result = str8_lit("F64");}break; -case CV_BasicType_FLOAT80:{result = str8_lit("F80");}break; -case CV_BasicType_FLOAT128:{result = str8_lit("F128");}break; -case CV_BasicType_FLOAT48:{result = str8_lit("F48");}break; -case CV_BasicType_FLOAT32PP:{result = str8_lit("F32PP");}break; -case CV_BasicType_FLOAT16:{result = str8_lit("F16");}break; +case CV_BasicType_USHORT:{result = str8_lit("USHORT");}break; +case CV_BasicType_ULONG:{result = str8_lit("ULONG");}break; +case CV_BasicType_UQUAD:{result = str8_lit("UQUAD");}break; +case CV_BasicType_UOCT:{result = str8_lit("UOCT");}break; +case CV_BasicType_BOOL8:{result = str8_lit("BOOL8");}break; +case CV_BasicType_BOOL16:{result = str8_lit("BOOL16");}break; +case CV_BasicType_BOOL32:{result = str8_lit("BOOL32");}break; +case CV_BasicType_BOOL64:{result = str8_lit("BOOL64");}break; +case CV_BasicType_FLOAT32:{result = str8_lit("FLOAT32");}break; +case CV_BasicType_FLOAT64:{result = str8_lit("FLOAT64");}break; +case CV_BasicType_FLOAT80:{result = str8_lit("FLOAT80");}break; +case CV_BasicType_FLOAT128:{result = str8_lit("FLOAT128");}break; +case CV_BasicType_FLOAT48:{result = str8_lit("FLOAT48");}break; +case CV_BasicType_FLOAT32PP:{result = str8_lit("FLOAT32PP");}break; +case CV_BasicType_FLOAT16:{result = str8_lit("FLOAT16");}break; case CV_BasicType_COMPLEX32:{result = str8_lit("ComplexF32");}break; case CV_BasicType_COMPLEX64:{result = str8_lit("ComplexF64");}break; case CV_BasicType_COMPLEX80:{result = str8_lit("ComplexF80");}break; case CV_BasicType_COMPLEX128:{result = str8_lit("ComplexF128");}break; case CV_BasicType_BIT:{result = str8_lit("");}break; case CV_BasicType_PASCHAR:{result = str8_lit("");}break; -case CV_BasicType_BOOL32FF:{result = str8_lit("B32FF");}break; -case CV_BasicType_INT8:{result = str8_lit("S8");}break; -case CV_BasicType_UINT8:{result = str8_lit("U8");}break; +case CV_BasicType_BOOL32FF:{result = str8_lit("BOOL32FF");}break; +case CV_BasicType_INT8:{result = str8_lit("int8");}break; +case CV_BasicType_UINT8:{result = str8_lit("uint8");}break; case CV_BasicType_RCHAR:{result = str8_lit("char");}break; case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}break; -case CV_BasicType_INT16:{result = str8_lit("S16");}break; -case CV_BasicType_UINT16:{result = str8_lit("U16");}break; -case CV_BasicType_INT32:{result = str8_lit("S32");}break; -case CV_BasicType_UINT32:{result = str8_lit("U32");}break; -case CV_BasicType_INT64:{result = str8_lit("S64");}break; -case CV_BasicType_UINT64:{result = str8_lit("U64");}break; -case CV_BasicType_INT128:{result = str8_lit("S128");}break; -case CV_BasicType_UINT128:{result = str8_lit("U128");}break; -case CV_BasicType_CHAR16:{result = str8_lit("CHAR16");}break; -case CV_BasicType_CHAR32:{result = str8_lit("CHAR32");}break; +case CV_BasicType_INT16:{result = str8_lit("int16");}break; +case CV_BasicType_UINT16:{result = str8_lit("uint16");}break; +case CV_BasicType_INT32:{result = str8_lit("int32");}break; +case CV_BasicType_UINT32:{result = str8_lit("uint32");}break; +case CV_BasicType_INT64:{result = str8_lit("int64");}break; +case CV_BasicType_UINT64:{result = str8_lit("uint64");}break; +case CV_BasicType_INT128:{result = str8_lit("int128");}break; +case CV_BasicType_UINT128:{result = str8_lit("uint128");}break; +case CV_BasicType_CHAR16:{result = str8_lit("char16");}break; +case CV_BasicType_CHAR32:{result = str8_lit("char32");}break; case CV_BasicType_CHAR8:{result = str8_lit("char");}break; case CV_BasicType_PTR:{result = str8_lit("PTR");}break; } diff --git a/src/coff/coff.c b/src/coff/coff.c index 0f2ba099..11e5d92a 100644 --- a/src/coff/coff.c +++ b/src/coff/coff.c @@ -52,14 +52,13 @@ coff_section_flag_from_align_size(U64 align) } internal String8 -coff_name_from_section_header(String8 raw_coff, COFF_SectionHeader *header, U64 string_table_off) +coff_name_from_section_header(String8 string_table, COFF_SectionHeader *header) { String8 name = str8_cstring_capped(header->name, header->name + sizeof(header->name)); if (name.str[0] == '/') { - String8 ascii_off = str8_skip(name, 1); - U64 name_rel_off = u64_from_str8(ascii_off, 10); - U64 name_off = name_rel_off + string_table_off; - name = str8_cstring_capped(raw_coff.str + name_off, raw_coff.str + raw_coff.size); + String8 name_off_str = str8_skip(name, 1); + U64 name_off = u64_from_str8(name_off_str, 10); + name = str8_cstring_capped(string_table.str + name_off, string_table.str+string_table.size); } return name; } @@ -94,12 +93,11 @@ coff_parse_section_name(String8 full_name, String8 *name_out, String8 *postfix_o } internal String8 -coff_read_symbol_name(String8 raw_coff, U64 string_table_off, COFF_SymbolName *name) +coff_read_symbol_name(String8 string_table, COFF_SymbolName *name) { String8 name_str = str8_lit(""); if (name->long_name.zeroes == 0) { - U64 name_string_off = string_table_off + name->long_name.string_table_offset; - str8_deserial_read_cstr(raw_coff, name_string_off, &name_str); + str8_deserial_read_cstr(string_table, name->long_name.string_table_offset, &name_str); } else { U32 i; for (i = 0; i < sizeof(name->short_name); ++i) { @@ -174,8 +172,8 @@ internal U64 coff_apply_size_from_reloc(COFF_MachineType machine, COFF_RelocType x) { switch (machine) { - case COFF_Machine_X64: return coff_apply_size_from_reloc_x64(x); - case COFF_Machine_X86: return coff_apply_size_from_reloc_x86(x); + case COFF_MachineType_X64: return coff_apply_size_from_reloc_x64(x); + case COFF_MachineType_X86: return coff_apply_size_from_reloc_x86(x); default: NotImplemented; } return 0; @@ -221,7 +219,7 @@ coff_make_import_header_by_name(Arena *arena, flags |= COFF_ImportBy_Name << COFF_ImportHeader_ImportByShift; COFF_ImportHeader header = {0}; - header.sig1 = COFF_Machine_Unknown; + header.sig1 = COFF_MachineType_Unknown; header.sig2 = max_U16; header.version = 0; header.machine = machine; @@ -264,7 +262,7 @@ coff_make_import_header_by_ordinal(Arena *arena, flags |= COFF_ImportBy_Ordinal << COFF_ImportHeader_ImportByShift; COFF_ImportHeader header = {0}; - header.sig1 = COFF_Machine_Unknown; + header.sig1 = COFF_MachineType_Unknown; header.sig2 = max_U16; header.version = 0; header.machine = machine; @@ -298,8 +296,8 @@ coff_word_size_from_machine(COFF_MachineType machine) { U64 result = 0; switch (machine) { - case COFF_Machine_X64: result = 8; break; - case COFF_Machine_X86: result = 4; break; + case COFF_MachineType_X64: result = 8; break; + case COFF_MachineType_X86: result = 4; break; } return result; } @@ -332,11 +330,11 @@ arch_from_coff_machine(COFF_MachineType machine) { Arch result = Arch_Null; switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: result = Arch_x86; break; - case COFF_Machine_X64: result = Arch_x64; break; - case COFF_Machine_Arm: result = Arch_arm32; break; - case COFF_Machine_Arm64: result = Arch_arm64; break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: result = Arch_x86; break; + case COFF_MachineType_X64: result = Arch_x64; break; + case COFF_MachineType_Arm: result = Arch_arm32; break; + case COFF_MachineType_Arm64: result = Arch_arm64; break; } return result; } diff --git a/src/coff/coff.h b/src/coff/coff.h index 97727aef..33cec229 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -47,31 +47,31 @@ enum typedef U16 COFF_MachineType; enum { - COFF_Machine_Unknown = 0x0, - COFF_Machine_X86 = 0x14c, - COFF_Machine_X64 = 0x8664, - COFF_Machine_Am33 = 0x1d3, - COFF_Machine_Arm = 0x1c0, - COFF_Machine_Arm64 = 0xaa64, - COFF_Machine_ArmNt = 0x1c4, - COFF_Machine_Ebc = 0xebc, - COFF_Machine_Ia64 = 0x200, - COFF_Machine_M32R = 0x9041, - COFF_Machine_Mips16 = 0x266, - COFF_Machine_MipsFpu = 0x366, - COFF_Machine_MipsFpu16 = 0x466, - COFF_Machine_PowerPc = 0x1f0, - COFF_Machine_PowerPcFp = 0x1f1, - COFF_Machine_R4000 = 0x166, - COFF_Machine_RiscV32 = 0x5032, - COFF_Machine_RiscV64 = 0x5064, - COFF_Machine_RiscV128 = 0x5128, - COFF_Machine_Sh3 = 0x1a2, - COFF_Machine_Sh3Dsp = 0x1a3, - COFF_Machine_Sh4 = 0x1a6, - COFF_Machine_Sh5 = 0x1a8, - COFF_Machine_Thumb = 0x1c2, - COFF_Machine_WceMipsV2 = 0x169 + COFF_MachineType_Unknown = 0x0, + COFF_MachineType_X86 = 0x14c, + COFF_MachineType_X64 = 0x8664, + COFF_MachineType_Am33 = 0x1d3, + COFF_MachineType_Arm = 0x1c0, + COFF_MachineType_Arm64 = 0xaa64, + COFF_MachineType_ArmNt = 0x1c4, + COFF_MachineType_Ebc = 0xebc, + COFF_MachineType_Ia64 = 0x200, + COFF_MachineType_M32R = 0x9041, + COFF_MachineType_Mips16 = 0x266, + COFF_MachineType_MipsFpu = 0x366, + COFF_MachineType_MipsFpu16 = 0x466, + COFF_MachineType_PowerPc = 0x1f0, + COFF_MachineType_PowerPcFp = 0x1f1, + COFF_MachineType_R4000 = 0x166, + COFF_MachineType_RiscV32 = 0x5032, + COFF_MachineType_RiscV64 = 0x5064, + COFF_MachineType_RiscV128 = 0x5128, + COFF_MachineType_Sh3 = 0x1a2, + COFF_MachineType_Sh3Dsp = 0x1a3, + COFF_MachineType_Sh4 = 0x1a6, + COFF_MachineType_Sh5 = 0x1a8, + COFF_MachineType_Thumb = 0x1c2, + COFF_MachineType_WceMipsV2 = 0x169 }; typedef struct COFF_FileHeader @@ -87,7 +87,7 @@ typedef struct COFF_FileHeader typedef struct COFF_BigObjHeader { - U16 sig1; // COFF_Machine_Unknown + U16 sig1; // COFF_MachineType_Unknown U16 sig2; // max_U16 U16 version; // 2 COFF_MachineType machine; @@ -547,7 +547,7 @@ enum typedef struct COFF_ImportHeader { - U16 sig1; // COFF_Machine_Unknown + U16 sig1; // COFF_MachineType_Unknown U16 sig2; // max_U16 U16 version; // 0 COFF_MachineType machine; @@ -567,13 +567,13 @@ typedef struct COFF_ImportHeader internal U64 coff_align_size_from_section_flags(COFF_SectionFlags flags); internal COFF_SectionFlags coff_section_flag_from_align_size (U64 align); -internal String8 coff_name_from_section_header(String8 raw_coff, COFF_SectionHeader *header, U64 string_table_off); +internal String8 coff_name_from_section_header(String8 string_table, COFF_SectionHeader *header); internal void coff_parse_section_name (String8 full_name, String8 *name_out, String8 *postfix_out); //////////////////////////////// // Symbol -internal String8 coff_read_symbol_name(String8 raw_coff, U64 string_table_off, COFF_SymbolName *name); +internal String8 coff_read_symbol_name(String8 string_table, COFF_SymbolName *name); //////////////////////////////// // Reloc diff --git a/src/coff/coff_enum.c b/src/coff/coff_enum.c index 7636a78b..ccd96eeb 100644 --- a/src/coff/coff_enum.c +++ b/src/coff/coff_enum.c @@ -21,31 +21,31 @@ read_only struct String8 string; COFF_MachineType machine; } g_coff_machine_map[] = { - { str8_lit_comp(""), COFF_Machine_Unknown }, - { str8_lit_comp("X86"), COFF_Machine_X86 }, - { str8_lit_comp("Amd64"), COFF_Machine_X64 }, - { str8_lit_comp("X64"), COFF_Machine_X64 }, - { str8_lit_comp("Am33"), COFF_Machine_Am33 }, - { str8_lit_comp("Arm"), COFF_Machine_Arm }, - { str8_lit_comp("Arm64"), COFF_Machine_Arm64 }, - { str8_lit_comp("ArmNt"), COFF_Machine_ArmNt }, - { str8_lit_comp("Ebc"), COFF_Machine_Ebc }, - { str8_lit_comp("Ia64"), COFF_Machine_Ia64 }, - { str8_lit_comp("M32r"), COFF_Machine_M32R }, - { str8_lit_comp("Mips16"), COFF_Machine_Mips16 }, - { str8_lit_comp("MipsFpu"), COFF_Machine_MipsFpu }, - { str8_lit_comp("MipsFpu16"), COFF_Machine_MipsFpu16 }, - { str8_lit_comp("PowerPc"), COFF_Machine_PowerPc }, - { str8_lit_comp("PowerPcFp"), COFF_Machine_PowerPcFp }, - { str8_lit_comp("R4000"), COFF_Machine_R4000 }, - { str8_lit_comp("RiscV32"), COFF_Machine_RiscV32 }, - { str8_lit_comp("RiscV64"), COFF_Machine_RiscV64 }, - { str8_lit_comp("Sh3"), COFF_Machine_Sh3 }, - { str8_lit_comp("Sh3Dsp"), COFF_Machine_Sh3Dsp }, - { str8_lit_comp("Sh4"), COFF_Machine_Sh4 }, - { str8_lit_comp("Sh5"), COFF_Machine_Sh5 }, - { str8_lit_comp("Thumb"), COFF_Machine_Thumb }, - { str8_lit_comp("WceMipsV2"), COFF_Machine_WceMipsV2 }, + { str8_lit_comp(""), COFF_MachineType_Unknown }, + { str8_lit_comp("X86"), COFF_MachineType_X86 }, + { str8_lit_comp("Amd64"), COFF_MachineType_X64 }, + { str8_lit_comp("X64"), COFF_MachineType_X64 }, + { str8_lit_comp("Am33"), COFF_MachineType_Am33 }, + { str8_lit_comp("Arm"), COFF_MachineType_Arm }, + { str8_lit_comp("Arm64"), COFF_MachineType_Arm64 }, + { str8_lit_comp("ArmNt"), COFF_MachineType_ArmNt }, + { str8_lit_comp("Ebc"), COFF_MachineType_Ebc }, + { str8_lit_comp("Ia64"), COFF_MachineType_Ia64 }, + { str8_lit_comp("M32r"), COFF_MachineType_M32R }, + { str8_lit_comp("Mips16"), COFF_MachineType_Mips16 }, + { str8_lit_comp("MipsFpu"), COFF_MachineType_MipsFpu }, + { str8_lit_comp("MipsFpu16"), COFF_MachineType_MipsFpu16 }, + { str8_lit_comp("PowerPc"), COFF_MachineType_PowerPc }, + { str8_lit_comp("PowerPcFp"), COFF_MachineType_PowerPcFp }, + { str8_lit_comp("R4000"), COFF_MachineType_R4000 }, + { str8_lit_comp("RiscV32"), COFF_MachineType_RiscV32 }, + { str8_lit_comp("RiscV64"), COFF_MachineType_RiscV64 }, + { str8_lit_comp("Sh3"), COFF_MachineType_Sh3 }, + { str8_lit_comp("Sh3Dsp"), COFF_MachineType_Sh3Dsp }, + { str8_lit_comp("Sh4"), COFF_MachineType_Sh4 }, + { str8_lit_comp("Sh5"), COFF_MachineType_Sh5 }, + { str8_lit_comp("Thumb"), COFF_MachineType_Thumb }, + { str8_lit_comp("WceMipsV2"), COFF_MachineType_WceMipsV2 }, }; read_only static struct { @@ -446,10 +446,10 @@ internal String8 coff_string_from_reloc(COFF_MachineType machine, COFF_RelocType x) { switch (machine) { - case COFF_Machine_X86: return coff_string_from_reloc_x86(x); - case COFF_Machine_X64: return coff_string_from_reloc_x64(x); - case COFF_Machine_Arm: return coff_string_from_reloc_arm(x); - case COFF_Machine_Arm64: return coff_string_from_reloc_arm64(x); + case COFF_MachineType_X86: return coff_string_from_reloc_x86(x); + case COFF_MachineType_X64: return coff_string_from_reloc_x64(x); + case COFF_MachineType_Arm: return coff_string_from_reloc_arm(x); + case COFF_MachineType_Arm64: return coff_string_from_reloc_arm64(x); } return str8_zero(); } @@ -462,7 +462,7 @@ coff_machine_from_string(String8 string) return g_coff_machine_map[i].machine; } } - return COFF_Machine_Unknown; + return COFF_MachineType_Unknown; } internal COFF_ImportType diff --git a/src/coff/coff_parse.c b/src/coff/coff_parse.c index 6628722b..15a918a5 100644 --- a/src/coff/coff_parse.c +++ b/src/coff/coff_parse.c @@ -7,10 +7,10 @@ coff_is_big_obj(String8 raw_coff) B32 is_big_obj = 0; if (raw_coff.size >= sizeof(COFF_BigObjHeader)) { COFF_BigObjHeader *file_header32 = (COFF_BigObjHeader*)(raw_coff.str); - is_big_obj = file_header32->sig1 == COFF_Machine_Unknown && - file_header32->sig2 == max_U16 && - file_header32->version >= 2 && - MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0; + is_big_obj = file_header32->sig1 == COFF_MachineType_Unknown && + file_header32->sig2 == max_U16 && + file_header32->version >= 2 && + MemoryCompare(file_header32->magic, g_coff_big_header_magic, sizeof(file_header32->magic)) == 0; } return is_big_obj; } @@ -26,19 +26,19 @@ coff_is_obj(String8 raw_coff) // validate machine B32 is_machine_type_valid = 0; switch (header->machine) { - case COFF_Machine_Unknown: - case COFF_Machine_X86: case COFF_Machine_X64: - case COFF_Machine_Am33: case COFF_Machine_Arm: - case COFF_Machine_Arm64: case COFF_Machine_ArmNt: - case COFF_Machine_Ebc: case COFF_Machine_Ia64: - case COFF_Machine_M32R: case COFF_Machine_Mips16: - case COFF_Machine_MipsFpu:case COFF_Machine_MipsFpu16: - case COFF_Machine_PowerPc:case COFF_Machine_PowerPcFp: - case COFF_Machine_R4000: case COFF_Machine_RiscV32: - case COFF_Machine_RiscV64:case COFF_Machine_RiscV128: - case COFF_Machine_Sh3: case COFF_Machine_Sh3Dsp: - case COFF_Machine_Sh4: case COFF_Machine_Sh5: - case COFF_Machine_Thumb: case COFF_Machine_WceMipsV2: + case COFF_MachineType_Unknown: + case COFF_MachineType_X86: case COFF_MachineType_X64: + case COFF_MachineType_Am33: case COFF_MachineType_Arm: + case COFF_MachineType_Arm64: case COFF_MachineType_ArmNt: + case COFF_MachineType_Ebc: case COFF_MachineType_Ia64: + case COFF_MachineType_M32R: case COFF_MachineType_Mips16: + case COFF_MachineType_MipsFpu:case COFF_MachineType_MipsFpu16: + case COFF_MachineType_PowerPc:case COFF_MachineType_PowerPcFp: + case COFF_MachineType_R4000: case COFF_MachineType_RiscV32: + case COFF_MachineType_RiscV64:case COFF_MachineType_RiscV128: + case COFF_MachineType_Sh3: case COFF_MachineType_Sh3Dsp: + case COFF_MachineType_Sh4: case COFF_MachineType_Sh5: + case COFF_MachineType_Thumb: case COFF_MachineType_WceMipsV2: { is_machine_type_valid = 1; }break; @@ -99,33 +99,33 @@ coff_file_header_info_from_data(String8 raw_coff) COFF_BigObjHeader *header32 = (COFF_BigObjHeader*)raw_coff.str; info.is_big_obj = 1; info.machine = header32->machine; - info.header_size = sizeof(COFF_BigObjHeader); - info.section_array_off = sizeof(COFF_BigObjHeader); info.section_count_no_null = header32->section_count; - info.string_table_off = header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count; - info.symbol_size = sizeof(COFF_Symbol32); - info.symbol_off = header32->symbol_table_foff; info.symbol_count = header32->symbol_count; + info.symbol_size = sizeof(COFF_Symbol32); + info.header_range = rng_1u64(0, sizeof(COFF_BigObjHeader)); + info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header32->section_count); + info.symbol_table_range = rng_1u64(header32->symbol_table_foff, header32->symbol_table_foff + sizeof(COFF_Symbol32) * header32->symbol_count); + info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size); } else if (coff_is_obj(raw_coff)) { COFF_FileHeader *header16 = (COFF_FileHeader*)raw_coff.str; info.is_big_obj = 0; info.machine = header16->machine; - info.header_size = sizeof(COFF_FileHeader); - info.section_array_off = sizeof(COFF_FileHeader); info.section_count_no_null = header16->section_count; - info.string_table_off = header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count; - info.symbol_size = sizeof(COFF_Symbol16); - info.symbol_off = header16->symbol_table_foff; info.symbol_count = header16->symbol_count; + info.symbol_size = sizeof(COFF_Symbol16); + info.header_range = rng_1u64(0, sizeof(COFF_FileHeader)); + info.section_table_range = rng_1u64(info.header_range.max, info.header_range.max + sizeof(COFF_SectionHeader) * header16->section_count); + info.symbol_table_range = rng_1u64(header16->symbol_table_foff, header16->symbol_table_foff + sizeof(COFF_Symbol16) * header16->symbol_count); + info.string_table_range = rng_1u64(info.symbol_table_range.max, raw_coff.size); } return info; } internal COFF_ParsedSymbol -coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32) +coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32) { COFF_ParsedSymbol result = {0}; - result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym32->name); + result.name = coff_read_symbol_name(string_table, &sym32->name); result.value = sym32->value; result.section_number = sym32->section_number; result.type = sym32->type; @@ -135,10 +135,10 @@ coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32 } internal COFF_ParsedSymbol -coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16) +coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16) { COFF_ParsedSymbol result = {0}; - result.name = coff_read_symbol_name(raw_coff, string_table_off, &sym16->name); + result.name = coff_read_symbol_name(string_table, &sym16->name); result.value = sym16->value; if (sym16->section_number == COFF_Symbol_DebugSection16) { result.section_number = COFF_Symbol_DebugSection32; @@ -163,11 +163,11 @@ coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_ Rng1U64 sym16_arr_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count); String8 raw_sym16_arr = str8_substr(raw_coff, sym16_arr_range); COFF_Symbol16 *sym16_arr = (COFF_Symbol16 *)raw_sym16_arr.str; - + for (U64 isymbol = 0, count = raw_sym16_arr.size / sizeof(COFF_Symbol16); isymbol < count; isymbol += 1) { COFF_Symbol16 *sym16 = &sym16_arr[isymbol]; COFF_Symbol32 *sym32 = &result.v[isymbol]; - + sym32->name = sym16->name; sym32->value = sym16->value; if (sym16->section_number == COFF_Symbol_DebugSection16) { @@ -185,7 +185,7 @@ coff_symbol_array_from_data_16(Arena *arena, String8 raw_coff, U64 symbol_array_ for (U64 iaux = isymbol+1, iaux_hi = Min(count, iaux+sym16->aux_symbol_count); iaux < iaux_hi; iaux += 1) { COFF_Symbol16 *aux16 = sym16_arr + iaux; COFF_Symbol32 *aux32 = result.v + iaux; - + // 32bit COFF uses 16bit aux symbols MemoryCopy(aux32, aux16, sizeof(COFF_Symbol16)); MemoryZero((U8 *)aux32 + sizeof(COFF_Symbol16), sizeof(COFF_Symbol32)-sizeof(COFF_Symbol16)); @@ -286,11 +286,11 @@ 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); } @@ -358,14 +358,14 @@ coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource * { String8 raw_header = str8_skip(raw_res, off); U64 header_cursor = 0; - + // prefix COFF_ResourceHeaderPrefix prefix = {0}; header_cursor += str8_deserial_read_struct(raw_header, header_cursor, &prefix); - + Assert(prefix.header_size >= sizeof(COFF_ResourceHeaderPrefix)); raw_header = str8_prefix(raw_header, prefix.header_size); - + // header COFF_ResourceID16 type_16 = {0}; COFF_ResourceID16 name_16 = {0}; @@ -377,11 +377,11 @@ coff_read_resource(Arena *arena, String8 raw_res, U64 off, COFF_ParsedResource * 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); @@ -411,14 +411,14 @@ coff_write_resource_id(Arena *arena, COFF_ResourceID id) { String8 result = str8_zero(); switch (id.type) { - case COFF_ResourceIDType_Null: break; - case COFF_ResourceIDType_Number: { - result = coff_resource_number_from_u16(arena, id.u.number); - } break; - case COFF_ResourceIDType_String: { - result = coff_resource_string_from_str8(arena, id.u.string); - } break; - default: InvalidPath; + case COFF_ResourceIDType_Null: break; + case COFF_ResourceIDType_Number: { + result = coff_resource_number_from_u16(arena, id.u.number); + } break; + case COFF_ResourceIDType_String: { + result = coff_resource_string_from_str8(arena, id.u.string); + } break; + default: InvalidPath; } return result; } @@ -435,13 +435,13 @@ coff_write_resource(Arena *arena, String8 data) { Temp scratch = scratch_begin(&arena, 1); - + String8List list = {0}; - + COFF_ResourceHeaderPrefix *prefix = push_array(scratch.arena, COFF_ResourceHeaderPrefix, 1); String8 packed_type = coff_write_resource_id(scratch.arena, type); String8 packed_name = coff_write_resource_id(scratch.arena, name); - + // prefix + header str8_list_push(scratch.arena, &list, str8_struct(prefix)); str8_list_push(scratch.arena, &list, packed_type); @@ -451,24 +451,24 @@ coff_write_resource(Arena *arena, str8_list_push(scratch.arena, &list, str8_struct(&language_id)); str8_list_push(scratch.arena, &list, str8_struct(&version)); str8_list_push(scratch.arena, &list, str8_struct(&characteristics)); - + prefix->data_size = safe_cast_u32(data.size); prefix->header_size = safe_cast_u32(list.total_size); - + // data str8_list_push(scratch.arena, &list, data); - + // magic str8_list_push_front(scratch.arena, &list, str8_array_fixed(g_coff_res_magic)); - + // align U64 align_size = AlignPow2(list.total_size, COFF_ResourceAlign) - list.total_size; U8 *align = push_array(scratch.arena, U8, align_size); str8_list_push(scratch.arena, &list, str8(align, align_size)); - + // join String8 res = str8_list_join(arena, &list, 0); - + scratch_end(scratch); return res; } @@ -476,15 +476,15 @@ coff_write_resource(Arena *arena, internal int coff_resource_id_compar(void *raw_a, void *raw_b) { - int cmp = 0; + int cmp; COFF_ResourceID *a = raw_a; COFF_ResourceID *b = raw_b; if (a->type == b->type) { switch (a->type) { - case COFF_ResourceIDType_Null: cmp = 0; break; - case COFF_ResourceIDType_Number: cmp = MemoryCompare(&a->u.number, &b->u.number, sizeof(a->u.number)); break; - case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break; - default: InvalidPath; break; + default: + case COFF_ResourceIDType_Null: cmp = 0; break; + case COFF_ResourceIDType_Number: cmp = MemoryCompare(&a->u.number, &b->u.number, sizeof(a->u.number)); break; + case COFF_ResourceIDType_String: cmp = strncmp((char *)a->u.string.str, (char *)b->u.string.str, Min(a->u.string.size, b->u.string.size)); break; } } else { cmp = a->type < b->type ? -1 : a->type > b->type ? +1 : 0; @@ -499,7 +499,7 @@ coff_is_import(String8 raw_archive_member) if (raw_archive_member.size >= sizeof(U16)*2) { U16 *sig1 = (U16*)raw_archive_member.str; U16 *sig2 = sig1 + 1; - is_import = *sig1 == COFF_Machine_Unknown && *sig2 == 0xffff; + is_import = *sig1 == COFF_MachineType_Unknown && *sig2 == 0xffff; } return is_import; } @@ -563,10 +563,10 @@ coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArc String8 mode = str8_skip_chop_whitespace(str8_cstring_capped(header->mode, header->mode + sizeof(header->mode) )); String8 size = str8_skip_chop_whitespace(str8_cstring_capped(header->size, header->size + sizeof(header->size) )); String8 end = str8_cstring_capped(header->end, header->end + sizeof(header->end)); - + U32 data_size = u32_from_str8(size, 10); U64 data_off = offset + sizeof(COFF_ArchiveMemberHeader); - + header_out->name = name; header_out->time_stamp = u32_from_str8(date, 10); header_out->user_id = u32_from_str8(user_id, 10); @@ -574,7 +574,7 @@ coff_parse_archive_member_header(String8 raw_archive, U64 offset, COFF_ParsedArc header_out->mode = mode; header_out->is_end_correct = str8_match_lit("`\n", end, 0); header_out->data_range = rng_1u64(data_off, data_off + data_size); - + return sizeof(*header); } return 0; @@ -584,7 +584,7 @@ internal COFF_ArchiveFirstMember coff_parse_first_archive_member(COFF_ArchiveMember *member) { Assert(str8_match_lit("/", member->header.name, 0)); - + U64 cursor = 0; U32 symbol_count = 0; @@ -597,17 +597,17 @@ coff_parse_first_archive_member(COFF_ArchiveMember *member) Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); cursor += dim_1u64(string_table_range); - + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); U32 *member_offsets = (U32 *)raw_member_offsets.str; U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); - + COFF_ArchiveFirstMember result = {0}; result.symbol_count = symbol_count; result.member_offset_count = member_offset_count; result.member_offsets = member_offsets; result.string_table = str8_substr(member->data, string_table_range); - + return result; } @@ -615,7 +615,7 @@ internal COFF_ArchiveSecondMember coff_parse_second_archive_member(COFF_ArchiveMember *member) { COFF_ArchiveSecondMember result = {0}; - + if (str8_match_lit("/", member->header.name, 0)) { U64 cursor = 0; @@ -632,13 +632,13 @@ coff_parse_second_archive_member(COFF_ArchiveMember *member) cursor += dim_1u64(symbol_indices_range); Rng1U64 string_table_range = rng_1u64(cursor, member->data.size); - + String8 raw_member_offsets = str8_substr(member->data, member_offsets_range); String8 raw_indices = str8_substr(member->data, symbol_indices_range); - + U32 *member_offsets = (U32 *)raw_member_offsets.str; U64 member_offset_count = raw_member_offsets.size / sizeof(member_offsets[0]); - + U16 *symbol_indices = (U16 *)raw_indices.str; U64 symbol_index_count = raw_indices.size / sizeof(symbol_indices[0]); @@ -650,7 +650,7 @@ coff_parse_second_archive_member(COFF_ArchiveMember *member) result.symbol_index_count = symbol_index_count; result.string_table = str8_substr(member->data, string_table_range); } - + return result; } @@ -683,7 +683,7 @@ coff_parse_import(String8 raw_archive_member, U64 offset, COFF_ParsedArchiveImpo Rng1U64 data_range = rng_1u64(offset + sizeof(*header), offset + sizeof(*header) + header->data_size); String8 raw_data = str8_substr(raw_archive_member, data_range); U64 data_cursor = 0; - + header_out->version = header->version; header_out->machine = header->machine; header_out->time_stamp = header->time_stamp; @@ -744,7 +744,7 @@ coff_regular_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_Arc if (member_out->header.is_end_correct) { member_out->offset = *offset; member_out->data = str8_substr(raw_archive, member_out->header.data_range); - + U64 read_size = AlignPow2(header_size + dim_1u64(member_out->header.data_range), COFF_Archive_MemberAlign); *offset += read_size; @@ -771,19 +771,19 @@ coff_thin_archive_member_iter_next(String8 raw_archive, U64 *offset, COFF_Archiv member_out->header.is_end_correct = 0; U64 header_size = coff_parse_archive_member_header(raw_archive, *offset, &member_out->header); - + if (member_out->header.is_end_correct) { Rng1U64 data_in_archive_range = {0}; if (str8_match_lit("/", member_out->header.name, 0) || str8_match_lit("//", member_out->header.name, 0)) { data_in_archive_range = member_out->header.data_range; } - + member_out->offset = *offset; member_out->data = str8_substr(raw_archive, data_in_archive_range); - + U64 read_size = AlignPow2(header_size + dim_1u64(data_in_archive_range), COFF_Archive_MemberAlign); *offset += read_size; - + is_parsed = 1; } @@ -806,9 +806,9 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) COFF_ArchiveMember first_header = {0}; COFF_ArchiveMember second_header = {0}; COFF_ArchiveMember long_names_member = {0}; - + COFF_ArchiveMemberNode *ptr = member_list.first; - + if (ptr) { if (str8_match_lit("/", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { @@ -821,7 +821,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) } else { error = str8_lit("missing first header"); } - + if (!error.size && ptr) { if (str8_match_lit("/", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { @@ -833,7 +833,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) } } } - + if (!error.size && ptr) { if (str8_match_lit("//", ptr->data.header.name, 0)) { if (ptr->data.header.is_end_correct) { @@ -853,7 +853,7 @@ coff_archive_parse_from_member_list(COFF_ArchiveMemberList member_list) parse.second_member = coff_parse_second_archive_member(&second_header); parse.long_names = long_names_member.data; parse.error = error; - + return parse; } @@ -894,9 +894,9 @@ coff_archive_parse_from_data(String8 raw_archive) { COFF_ArchiveType type = coff_archive_type_from_data(raw_archive); switch (type) { - case COFF_Archive_Null: break; - case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive); - case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive); + case COFF_Archive_Null: break; + case COFF_Archive_Regular: return coff_regular_archive_parse_from_data(raw_archive); + case COFF_Archive_Thin: return coff_thin_archive_parse_from_data(raw_archive); } COFF_ArchiveParse null_parse = {0}; return null_parse; diff --git a/src/coff/coff_parse.h b/src/coff/coff_parse.h index 2ed92e92..7e237646 100644 --- a/src/coff/coff_parse.h +++ b/src/coff/coff_parse.h @@ -9,12 +9,13 @@ typedef struct COFF_FileHeaderInfo B32 is_big_obj; COFF_MachineType machine; U64 header_size; - U64 section_array_off; U64 section_count_no_null; - U64 string_table_off; U64 symbol_size; - U64 symbol_off; U64 symbol_count; + Rng1U64 header_range; + Rng1U64 section_table_range; + Rng1U64 symbol_table_range; + Rng1U64 string_table_range; } COFF_FileHeaderInfo; //////////////////////////////// @@ -249,8 +250,8 @@ internal COFF_FileHeaderInfo coff_file_header_info_from_data(String8 raw_coff); //////////////////////////////// // Symbol -internal COFF_ParsedSymbol coff_parse_symbol32(String8 raw_coff, U64 string_table_off, COFF_Symbol32 *sym32); -internal COFF_ParsedSymbol coff_parse_symbol16(String8 raw_coff, U64 string_table_off, COFF_Symbol16 *sym16); +internal COFF_ParsedSymbol coff_parse_symbol32(String8 string_table, COFF_Symbol32 *sym32); +internal COFF_ParsedSymbol coff_parse_symbol16(String8 string_table, COFF_Symbol16 *sym16); internal COFF_Symbol32Array coff_symbol_array_from_data_16(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); internal COFF_Symbol32Array coff_symbol_array_from_data_32(Arena *arena, String8 data, U64 symbol_array_off, U64 symbol_count); diff --git a/src/ctrl/ctrl.mdesk b/src/ctrl/ctrl.mdesk index abc3401d..ceb2fca1 100644 --- a/src/ctrl/ctrl.mdesk +++ b/src/ctrl/ctrl.mdesk @@ -4,17 +4,19 @@ //////////////////////////////// //~ rjf: Entity Kinds -@table(name display_string) +@table(name code_name display_string) CTRL_EntityKindTable: { - {Root "Root" } - {Machine "Machine" } - {Process "Process" } - {Thread "Thread" } - {Module "Module" } - {EntryPoint "Entry Point" } - {DebugInfoPath "Debug Info Path" } - {PendingThreadName "Pending Thread Name" } + {Root root "Root" } + {Machine machine "Machine" } + {Process process "Process" } + {Thread thread "Thread" } + {Module module "Module" } + {EntryPoint entry_point "Entry Point" } + {DebugInfoPath debug_info_path "Debug Info Path" } + {PendingThreadName pending_thread_name "Pending Thread Name" } + {PendingThreadColor pending_thread_color "Pending Thread Color" } + {Breakpoint breakpoint "Breakpoint" } } @enum CTRL_EntityKind: @@ -24,6 +26,12 @@ CTRL_EntityKindTable: COUNT, } +@data(String8) ctrl_entity_kind_code_name_table: +{ + `{0}`, + @expand(CTRL_EntityKindTable a) `str8_lit_comp("$(a.code_name)")` +} + @data(String8) ctrl_entity_kind_display_string_table: { `{0}`, diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 3be0a2fb..99cd7cd8 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -43,6 +43,21 @@ ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind) return cause; } +internal CTRL_ExceptionKind +ctrl_exception_kind_from_dmn(DMN_ExceptionKind kind) +{ + CTRL_ExceptionKind result = CTRL_ExceptionKind_Null; + switch(kind) + { + default:{}break; + case DMN_ExceptionKind_MemoryRead: {result = CTRL_ExceptionKind_MemoryRead;}break; + case DMN_ExceptionKind_MemoryWrite: {result = CTRL_ExceptionKind_MemoryWrite;}break; + case DMN_ExceptionKind_MemoryExecute: {result = CTRL_ExceptionKind_MemoryExecute;}break; + case DMN_ExceptionKind_CppThrow: {result = CTRL_ExceptionKind_CppThrow;}break; + } + return result; +} + internal String8 ctrl_string_from_event_kind(CTRL_EventKind kind) { @@ -91,6 +106,41 @@ ctrl_string_from_msg_kind(CTRL_MsgKind kind) return result; } +internal CTRL_EntityKind +ctrl_entity_kind_from_string(String8 string) +{ + CTRL_EntityKind result = CTRL_EntityKind_Null; + for EachNonZeroEnumVal(CTRL_EntityKind, k) + { + if(str8_match(ctrl_entity_kind_code_name_table[k], string, 0)) + { + result = k; + break; + } + } + return result; +} + +internal DMN_TrapFlags +ctrl_dmn_trap_flags_from_user_breakpoint_flags(CTRL_UserBreakpointFlags flags) +{ + DMN_TrapFlags result = 0; + if(flags & CTRL_UserBreakpointFlag_BreakOnWrite) { result |= DMN_TrapFlag_BreakOnWrite; } + if(flags & CTRL_UserBreakpointFlag_BreakOnRead) { result |= DMN_TrapFlag_BreakOnRead; } + if(flags & CTRL_UserBreakpointFlag_BreakOnExecute) { result |= DMN_TrapFlag_BreakOnExecute; } + return result; +} + +internal CTRL_UserBreakpointFlags +ctrl_user_breakpoint_flags_from_dmn_trap_flags(DMN_TrapFlags flags) +{ + CTRL_UserBreakpointFlags result = 0; + if(flags & DMN_TrapFlag_BreakOnWrite) { result |= CTRL_UserBreakpointFlag_BreakOnWrite; } + if(flags & DMN_TrapFlag_BreakOnRead) { result |= CTRL_UserBreakpointFlag_BreakOnRead; } + if(flags & DMN_TrapFlag_BreakOnExecute) { result |= CTRL_UserBreakpointFlag_BreakOnExecute; } + return result; +} + //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -136,6 +186,34 @@ ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src) return dst; } +internal String8 +ctrl_string_from_handle(Arena *arena, CTRL_Handle handle) +{ + String8 result = push_str8f(arena, "$%I64x$%I64x", handle.machine_id, handle.dmn_handle.u64[0]); + return result; +} + +internal CTRL_Handle +ctrl_handle_from_string(String8 string) +{ + CTRL_Handle handle = {0}; + { + Temp scratch = scratch_begin(0, 0); + U8 split = '$'; + String8List parts = str8_split(scratch.arena, string, &split, 1, 0); + if(parts.first && parts.first->next) + { + CTRL_MachineID machine_id = u64_from_str8(parts.first->string, 16); + DMN_Handle dmn_handle = {0}; + dmn_handle.u64[0] = u64_from_str8(parts.first->next->string, 16); + handle.machine_id = machine_id; + handle.dmn_handle = dmn_handle; + } + scratch_end(scratch); + } + return handle; +} + //////////////////////////////// //~ rjf: Trap Type Functions @@ -201,7 +279,6 @@ ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src) dst->env_string_list = str8_list_copy(arena, &src->env_string_list); dst->traps = ctrl_trap_list_copy(arena, &src->traps); dst->user_bps = ctrl_user_breakpoint_list_copy(arena, &src->user_bps); - dst->meta_evals = *deep_copy_from_struct(arena, CTRL_MetaEvalArray, &src->meta_evals); } //- rjf: list building @@ -325,17 +402,15 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs) { CTRL_UserBreakpoint *bp = &n->v; str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->kind); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->flags); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->id); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->string.size); str8_serial_push_data(scratch.arena, &msgs_srlzed, bp->string.str, bp->string.size); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->pt); - str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->u64); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->size); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &bp->condition.size); str8_serial_push_data(scratch.arena, &msgs_srlzed, bp->condition.str, bp->condition.size); } - - // rjf: write meta-eval-info array - String8 meta_evals_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEvalArray, &msg->meta_evals); - str8_serial_push_string(scratch.arena, &msgs_srlzed, meta_evals_srlzed); } } String8 string = str8_serial_end(arena, &msgs_srlzed); @@ -450,21 +525,17 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string) msg->user_bps.count += 1; CTRL_UserBreakpoint *bp = &n->v; read_off += str8_deserial_read_struct(string, read_off, &bp->kind); + read_off += str8_deserial_read_struct(string, read_off, &bp->flags); + read_off += str8_deserial_read_struct(string, read_off, &bp->id); read_off += str8_deserial_read_struct(string, read_off, &bp->string.size); bp->string.str = push_array_no_zero(arena, U8, bp->string.size); read_off += str8_deserial_read(string, read_off, bp->string.str, bp->string.size, 1); read_off += str8_deserial_read_struct(string, read_off, &bp->pt); - read_off += str8_deserial_read_struct(string, read_off, &bp->u64); + read_off += str8_deserial_read_struct(string, read_off, &bp->size); read_off += str8_deserial_read_struct(string, read_off, &bp->condition.size); bp->condition.str = push_array_no_zero(arena, U8, bp->condition.size); read_off += str8_deserial_read(string, read_off, bp->condition.str, bp->condition.size, 1); } - - // rjf: read meta-eval-info array - String8 meta_evals_data = str8_skip(string, read_off); - U64 meta_evals_size = 0; - msg->meta_evals = *struct_from_serialized(arena, CTRL_MetaEvalArray, meta_evals_data, .advance_out = &meta_evals_size); - read_off += meta_evals_size; } } return msgs; @@ -524,8 +595,9 @@ ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event, U64 max) str8_serial_push_struct(scratch.arena, &srl, &event->stack_base); str8_serial_push_struct(scratch.arena, &srl, &event->tls_root); str8_serial_push_struct(scratch.arena, &srl, &event->timestamp); - str8_serial_push_struct(scratch.arena, &srl, &event->rgba); str8_serial_push_struct(scratch.arena, &srl, &event->exception_code); + str8_serial_push_struct(scratch.arena, &srl, &event->rgba); + str8_serial_push_struct(scratch.arena, &srl, &event->bp_flags); String8 string = event->string; string.size = Min(string.size, max-srl.total_size); str8_serial_push_struct(scratch.arena, &srl, &string.size); @@ -558,6 +630,7 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) read_off += str8_deserial_read_struct(string, read_off, &event.timestamp); read_off += str8_deserial_read_struct(string, read_off, &event.exception_code); read_off += str8_deserial_read_struct(string, read_off, &event.rgba); + read_off += str8_deserial_read_struct(string, read_off, &event.bp_flags); read_off += str8_deserial_read_struct(string, read_off, &event.string.size); event.string.str = push_array_no_zero(arena, U8, event.string.size); read_off += str8_deserial_read(string, read_off, event.string.str, event.string.size, 1); @@ -580,12 +653,12 @@ ctrl_entity_list_push(Arena *arena, CTRL_EntityList *list, CTRL_Entity *entity) } internal CTRL_EntityList -ctrl_entity_list_from_handle_list(Arena *arena, CTRL_EntityStore *store, CTRL_HandleList *list) +ctrl_entity_list_from_handle_list(Arena *arena, CTRL_EntityCtx *ctx, CTRL_HandleList *list) { CTRL_EntityList result = {0}; for(CTRL_HandleNode *n = list->first; n != 0; n = n->next) { - CTRL_Entity *entity = ctrl_entity_from_handle(store, n->v); + CTRL_Entity *entity = ctrl_entity_from_handle(ctx, n->v); ctrl_entity_list_push(arena, &result, entity); } return result; @@ -607,284 +680,17 @@ ctrl_entity_array_from_list(Arena *arena, CTRL_EntityList *list) return result; } -//- rjf: cache creation/destruction - -internal CTRL_EntityStore * -ctrl_entity_store_alloc(void) -{ - Arena *arena = arena_alloc(); - CTRL_EntityStore *store = push_array(arena, CTRL_EntityStore, 1); - store->arena = arena; - store->hash_slots_count = 1024; - store->hash_slots = push_array(arena, CTRL_EntityHashSlot, store->hash_slots_count); - for EachEnumVal(CTRL_EntityKind, k) - { - store->entity_kind_lists_arenas[k] = arena_alloc(); - } - CTRL_Entity *root = store->root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, Arch_Null, ctrl_handle_zero(), 0); - CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, arch_from_context(), ctrl_handle_make(CTRL_MachineID_Local, dmn_handle_zero()), 0); - Temp scratch = scratch_begin(0, 0); - String8 local_machine_name = push_str8f(scratch.arena, "This PC (%S)", os_get_system_info()->machine_name); - ctrl_entity_equip_string(store, local_machine, local_machine_name); - scratch_end(scratch); - return store; -} - -internal void -ctrl_entity_store_release(CTRL_EntityStore *cache) -{ - arena_release(cache->arena); -} - -//- rjf: string allocation/deletion - -internal U64 -ctrl_name_bucket_idx_from_string_size(U64 size) -{ - U64 size_rounded = u64_up_to_pow2(size+1); - size_rounded = ClampBot((1<<4), size_rounded); - U64 bucket_idx = 0; - switch(size_rounded) - { - case 1<<4: {bucket_idx = 0;}break; - case 1<<5: {bucket_idx = 1;}break; - case 1<<6: {bucket_idx = 2;}break; - case 1<<7: {bucket_idx = 3;}break; - case 1<<8: {bucket_idx = 4;}break; - case 1<<9: {bucket_idx = 5;}break; - case 1<<10:{bucket_idx = 6;}break; - default:{bucket_idx = ArrayCount(((CTRL_EntityStore *)0)->free_string_chunks)-1;}break; - } - return bucket_idx; -} - -internal String8 -ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string) -{ - if(string.size == 0) {return str8_zero();} - U64 bucket_idx = ctrl_name_bucket_idx_from_string_size(string.size); - CTRL_EntityStringChunkNode *node = store->free_string_chunks[bucket_idx]; - - // rjf: pull from bucket free list - if(node != 0) - { - if(bucket_idx == ArrayCount(store->free_string_chunks)-1) - { - node = 0; - CTRL_EntityStringChunkNode *prev = 0; - for(CTRL_EntityStringChunkNode *n = store->free_string_chunks[bucket_idx]; - n != 0; - prev = n, n = n->next) - { - if(n->size >= string.size) - { - if(prev == 0) - { - store->free_string_chunks[bucket_idx] = n->next; - } - else - { - prev->next = n->next; - } - node = n; - break; - } - } - } - else - { - SLLStackPop(store->free_string_chunks[bucket_idx]); - } - } - - // rjf: no found node -> allocate new - if(node == 0) - { - U64 chunk_size = 0; - if(bucket_idx < ArrayCount(store->free_string_chunks)-1) - { - chunk_size = 1<<(bucket_idx+4); - } - else - { - chunk_size = u64_up_to_pow2(string.size); - } - U8 *chunk_memory = push_array(store->arena, U8, chunk_size); - node = (CTRL_EntityStringChunkNode *)chunk_memory; - node->size = chunk_size; - } - - // rjf: fill string & return - String8 allocated_string = str8((U8 *)node, string.size); - MemoryCopy((U8 *)node, string.str, string.size); - return allocated_string; -} - -internal void -ctrl_entity_string_release(CTRL_EntityStore *store, String8 string) -{ - if(string.size == 0) {return;} - U64 bucket_idx = ctrl_name_bucket_idx_from_string_size(string.size); - CTRL_EntityStringChunkNode *node = (CTRL_EntityStringChunkNode *)string.str; - node->size = u64_up_to_pow2(string.size); - SLLStackPush(store->free_string_chunks[bucket_idx], node); -} - -//- rjf: entity construction/deletion +//- rjf: entity context (entity group read-only) functions internal CTRL_Entity * -ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Arch arch, CTRL_Handle handle, U64 id) -{ - CTRL_Entity *entity = &ctrl_entity_nil; - { - // rjf: allocate - entity = store->free; - { - if(entity != 0) - { - SLLStackPop(store->free); - } - else - { - entity = push_array_no_zero(store->arena, CTRL_Entity, 1); - } - MemoryZeroStruct(entity); - } - - // rjf: fill - { - entity->kind = kind; - entity->arch = arch; - entity->handle = handle; - entity->id = id; - entity->parent = parent; - entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; - if(parent != &ctrl_entity_nil) - { - DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); - } - } - - // rjf: insert into hash map - { - U64 hash = ctrl_hash_from_handle(handle); - U64 slot_idx = hash%store->hash_slots_count; - CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->entity->handle, handle)) - { - node = n; - break; - } - } - if(node == 0) - { - node = store->hash_node_free; - if(node != 0) - { - SLLStackPop(store->hash_node_free); - } - else - { - node = push_array_no_zero(store->arena, CTRL_EntityHashNode, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->entity = entity; - } - } - - // rjf: bump counters - store->entity_kind_counts[kind] += 1; - store->entity_kind_alloc_gens[kind] += 1; - } - return entity; -} - -internal void -ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity) -{ - // rjf: unhook root - if(entity->parent != &ctrl_entity_nil) - { - DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); - } - - // rjf: walk every entity in this tree, free each - if(entity != &ctrl_entity_nil) - { - Temp scratch = scratch_begin(0, 0); - typedef struct Task Task; - struct Task - { - Task *next; - CTRL_Entity *e; - }; - Task start_task = {0, entity}; - Task *first_task = &start_task; - Task *last_task = &start_task; - for(Task *t = first_task; t != 0; t = t->next) - { - for(CTRL_Entity *child = t->e->first; child != &ctrl_entity_nil; child = child->next) - { - Task *t = push_array(scratch.arena, Task, 1); - t->e = child; - SLLQueuePush(first_task, last_task, t); - } - - // rjf: free entity - SLLStackPush(store->free, t->e); - - // rjf: remove from hash map - { - U64 hash = ctrl_hash_from_handle(t->e->handle); - U64 slot_idx = hash%store->hash_slots_count; - CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; - CTRL_EntityHashNode *node = 0; - for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->entity->handle, t->e->handle)) - { - DLLRemove(slot->first, slot->last, n); - SLLStackPush(store->hash_node_free, n); - break; - } - } - } - - // rjf: dec counter - store->entity_kind_counts[t->e->kind] -= 1; - store->entity_kind_alloc_gens[t->e->kind] += 1; - } - scratch_end(scratch); - } -} - -//- rjf: entity equipment - -internal void -ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string) -{ - if(entity->string.size != 0) - { - ctrl_entity_string_release(store, entity->string); - } - entity->string = ctrl_entity_string_alloc(store, string); -} - -//- rjf: entity store lookups - -internal CTRL_Entity * -ctrl_entity_from_handle(CTRL_EntityStore *store, CTRL_Handle handle) +ctrl_entity_from_handle(CTRL_EntityCtx *ctx, CTRL_Handle handle) { CTRL_Entity *entity = &ctrl_entity_nil; if(!ctrl_handle_match(handle, ctrl_handle_zero())) { U64 hash = ctrl_hash_from_handle(handle); - U64 slot_idx = hash%store->hash_slots_count; - CTRL_EntityHashSlot *slot = &store->hash_slots[slot_idx]; + U64 slot_idx = hash%ctx->hash_slots_count; + CTRL_EntityHashSlot *slot = &ctx->hash_slots[slot_idx]; CTRL_EntityHashNode *node = 0; for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) { @@ -970,28 +776,11 @@ ctrl_dbgi_key_from_module(CTRL_Entity *module) return dbgi_key; } -internal CTRL_EntityList -ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityStore *store, DI_Key *dbgi_key) -{ - CTRL_EntityList list = {0}; - CTRL_EntityList all_modules = ctrl_entity_list_from_kind(store, CTRL_EntityKind_Module); - for(CTRL_EntityNode *n = all_modules.first; n != 0; n = n->next) - { - CTRL_Entity *module = n->v; - DI_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); - if(di_key_match(&module_dbgi_key, dbgi_key)) - { - ctrl_entity_list_push(arena, &list, module); - } - } - return list; -} - internal CTRL_Entity * -ctrl_module_from_thread_candidates(CTRL_EntityStore *store, CTRL_Entity *thread, CTRL_EntityList *candidates) +ctrl_module_from_thread_candidates(CTRL_EntityCtx *ctx, CTRL_Entity *thread, CTRL_EntityList *candidates) { CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - U64 thread_rip_vaddr = ctrl_query_cached_rip_from_thread(store, thread->handle); + U64 thread_rip_vaddr = ctrl_rip_from_thread(ctx, thread->handle); CTRL_Entity *src_module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_EntityNode *n = candidates->first; n != 0; n = n->next) @@ -1010,27 +799,6 @@ ctrl_module_from_thread_candidates(CTRL_EntityStore *store, CTRL_Entity *thread, return module; } -internal CTRL_EntityList -ctrl_entity_list_from_kind(CTRL_EntityStore *store, CTRL_EntityKind kind) -{ - if(store->entity_kind_lists_gens[kind] != store->entity_kind_alloc_gens[kind]) - { - arena_clear(store->entity_kind_lists_arenas[kind]); - MemoryZeroStruct(&store->entity_kind_lists[kind]); - for(CTRL_Entity *e = store->root; - e != &ctrl_entity_nil; - e = ctrl_entity_rec_depth_first_pre(e, store->root).next) - { - if(e->kind == kind) - { - ctrl_entity_list_push(store->entity_kind_lists_arenas[kind], &store->entity_kind_lists[kind], e); - } - } - store->entity_kind_lists_gens[kind] = store->entity_kind_alloc_gens[kind]; - } - return store->entity_kind_lists[kind]; -} - internal U64 ctrl_vaddr_from_voff(CTRL_Entity *module, U64 voff) { @@ -1078,6 +846,349 @@ ctrl_entity_tree_is_frozen(CTRL_Entity *root) return is_frozen; } +//- rjf: entity ctx r/w store state functions + +internal CTRL_EntityCtxRWStore * +ctrl_entity_ctx_rw_store_alloc(void) +{ + Arena *arena = arena_alloc(); + CTRL_EntityCtxRWStore *store = push_array(arena, CTRL_EntityCtxRWStore, 1); + store->arena = arena; + store->ctx.hash_slots_count = 1024; + store->ctx.hash_slots = push_array(arena, CTRL_EntityHashSlot, store->ctx.hash_slots_count); + CTRL_Entity *root = store->ctx.root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, Arch_Null, ctrl_handle_zero(), 0); + CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, arch_from_context(), ctrl_handle_make(CTRL_MachineID_Local, dmn_handle_zero()), 0); + Temp scratch = scratch_begin(0, 0); + String8 local_machine_name = push_str8f(scratch.arena, "This PC (%S)", os_get_system_info()->machine_name); + ctrl_entity_equip_string(store, local_machine, local_machine_name); + scratch_end(scratch); + return store; +} + +internal void +ctrl_entity_ctx_rw_store_release(CTRL_EntityCtxRWStore *store) +{ + arena_release(store->arena); +} + +//- rjf: string allocation/deletion + +internal U64 +ctrl_name_bucket_num_from_string_size(U64 size) +{ + U64 bucket_num = 0; + if(size > 0) + { + for EachElement(idx, ctrl_entity_string_bucket_chunk_sizes) + { + if(size <= ctrl_entity_string_bucket_chunk_sizes[idx]) + { + bucket_num = idx+1; + break; + } + } + } + return bucket_num; +} + +internal String8 +ctrl_entity_string_alloc(CTRL_EntityCtxRWStore *store, String8 string) +{ + //- rjf: allocate node + CTRL_EntityStringChunkNode *node = 0; + { + U64 bucket_num = ctrl_name_bucket_num_from_string_size(string.size); + if(bucket_num == ArrayCount(ctrl_entity_string_bucket_chunk_sizes)) + { + CTRL_EntityStringChunkNode *best_node = 0; + CTRL_EntityStringChunkNode *best_node_prev = 0; + U64 best_node_size = max_U64; + { + for(CTRL_EntityStringChunkNode *n = store->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next)) + { + if(n->size >= string.size && n->size < best_node_size) + { + best_node = n; + best_node_prev = prev; + best_node_size = n->size; + } + } + } + if(best_node != 0) + { + node = best_node; + if(best_node_prev) + { + best_node_prev->next = best_node->next; + } + else + { + store->free_string_chunks[bucket_num-1] = best_node->next; + } + } + else + { + U64 chunk_size = u64_up_to_pow2(string.size); + node = (CTRL_EntityStringChunkNode *)push_array(store->arena, U8, chunk_size); + } + } + else if(bucket_num != 0) + { + node = store->free_string_chunks[bucket_num-1]; + if(node != 0) + { + SLLStackPop(store->free_string_chunks[bucket_num-1]); + } + else + { + node = (CTRL_EntityStringChunkNode *)push_array(store->arena, U8, ctrl_entity_string_bucket_chunk_sizes[bucket_num-1]); + } + } + } + + //- rjf: fill node + String8 result = {0}; + if(node != 0) + { + result.str = (U8 *)node; + result.size = string.size; + MemoryCopy(result.str, string.str, result.size); + } + return result; +} + +internal void +ctrl_entity_string_release(CTRL_EntityCtxRWStore *store, String8 string) +{ + U64 bucket_num = ctrl_name_bucket_num_from_string_size(string.size); + if(1 <= bucket_num && bucket_num <= ArrayCount(rd_name_bucket_chunk_sizes)) + { + U64 bucket_idx = bucket_num-1; + CTRL_EntityStringChunkNode *node = (CTRL_EntityStringChunkNode *)string.str; + SLLStackPush(store->free_string_chunks[bucket_idx], node); + node->size = u64_up_to_pow2(string.size); + } +} + +//- rjf: entity construction/deletion + +internal CTRL_Entity * +ctrl_entity_alloc(CTRL_EntityCtxRWStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Arch arch, CTRL_Handle handle, U64 id) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + { + // rjf: allocate + entity = store->free; + { + if(entity != 0) + { + SLLStackPop(store->free); + } + else + { + entity = push_array_no_zero(store->arena, CTRL_Entity, 1); + } + MemoryZeroStruct(entity); + } + + // rjf: fill + { + entity->kind = kind; + entity->arch = arch; + entity->handle = handle; + entity->id = id; + entity->parent = parent; + entity->next = entity->prev = entity->first = entity->last = &ctrl_entity_nil; + if(parent != &ctrl_entity_nil) + { + DLLPushBack_NPZ(&ctrl_entity_nil, parent->first, parent->last, entity, next, prev); + } + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_handle(handle); + U64 slot_idx = hash%store->ctx.hash_slots_count; + CTRL_EntityHashSlot *slot = &store->ctx.hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->entity->handle, handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = store->hash_node_free; + if(node != 0) + { + SLLStackPop(store->hash_node_free); + } + else + { + node = push_array_no_zero(store->arena, CTRL_EntityHashNode, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = entity; + } + } + + // rjf: bump counters + store->ctx.entity_kind_counts[kind] += 1; + store->ctx.entity_kind_alloc_gens[kind] += 1; + } + return entity; +} + +internal void +ctrl_entity_release(CTRL_EntityCtxRWStore *store, CTRL_Entity *entity) +{ + // rjf: unhook root + if(entity->parent != &ctrl_entity_nil) + { + DLLRemove_NPZ(&ctrl_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); + } + + // rjf: walk every entity in this tree, free each + if(entity != &ctrl_entity_nil) + { + Temp scratch = scratch_begin(0, 0); + typedef struct Task Task; + struct Task + { + Task *next; + CTRL_Entity *e; + }; + Task start_task = {0, entity}; + Task *first_task = &start_task; + Task *last_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) + { + for(CTRL_Entity *child = t->e->first; child != &ctrl_entity_nil; child = child->next) + { + Task *t = push_array(scratch.arena, Task, 1); + t->e = child; + SLLQueuePush(first_task, last_task, t); + } + + // rjf: free entity + SLLStackPush(store->free, t->e); + + // rjf: remove from hash map + { + U64 hash = ctrl_hash_from_handle(t->e->handle); + U64 slot_idx = hash%store->ctx.hash_slots_count; + CTRL_EntityHashSlot *slot = &store->ctx.hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->entity->handle, t->e->handle)) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(store->hash_node_free, n); + break; + } + } + } + + // rjf: dec counter + store->ctx.entity_kind_counts[t->e->kind] -= 1; + store->ctx.entity_kind_alloc_gens[t->e->kind] += 1; + } + scratch_end(scratch); + } +} + +//- rjf: entity equipment + +internal void +ctrl_entity_equip_string(CTRL_EntityCtxRWStore *store, CTRL_Entity *entity, String8 string) +{ + if(entity->string.size != 0) + { + ctrl_entity_string_release(store, entity->string); + } + entity->string = ctrl_entity_string_alloc(store, string); +} + +//- rjf: accelerated entity context lookups + +internal CTRL_EntityCtxLookupAccel * +ctrl_thread_entity_ctx_lookup_accel(void) +{ + if(ctrl_entity_ctx_lookup_accel == 0) + { + Arena *arena = arena_alloc(); + ctrl_entity_ctx_lookup_accel = push_array(arena, CTRL_EntityCtxLookupAccel, 1); + ctrl_entity_ctx_lookup_accel->arena = arena; + for EachEnumVal(CTRL_EntityKind, k) + { + ctrl_entity_ctx_lookup_accel->entity_kind_arrays_arenas[k] = arena_alloc(); + } + } + return ctrl_entity_ctx_lookup_accel; +} + +internal CTRL_EntityArray +ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind) +{ + CTRL_EntityCtxLookupAccel *accel = ctrl_thread_entity_ctx_lookup_accel(); + if(accel->entity_kind_arrays_gens[kind] != ctx->entity_kind_alloc_gens[kind]) + { + Temp scratch = scratch_begin(0, 0); + CTRL_EntityList entities = {0}; + for(CTRL_Entity *e = ctx->root; + e != &ctrl_entity_nil; + e = ctrl_entity_rec_depth_first_pre(e, ctx->root).next) + { + if(e->kind == kind) + { + ctrl_entity_list_push(scratch.arena, &entities, e); + } + } + accel->entity_kind_arrays_gens[kind] = ctx->entity_kind_alloc_gens[kind]; + arena_clear(accel->entity_kind_arrays_arenas[kind]); + accel->entity_kind_arrays[kind] = ctrl_entity_array_from_list(accel->entity_kind_arrays_arenas[kind], &entities); + scratch_end(scratch); + } + return accel->entity_kind_arrays[kind]; +} + +internal CTRL_EntityList +ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key) +{ + CTRL_EntityList list = {0}; + CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Module); + for EachIndex(idx, all_modules.count) + { + CTRL_Entity *module = all_modules.v[idx]; + DI_Key module_dbgi_key = ctrl_dbgi_key_from_module(module); + if(di_key_match(&module_dbgi_key, dbgi_key)) + { + ctrl_entity_list_push(arena, &list, module); + } + } + return list; +} + +internal CTRL_Entity * +ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id) +{ + CTRL_Entity *thread = &ctrl_entity_nil; + CTRL_EntityArray threads = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Thread); + for EachIndex(idx, threads.count) + { + if(threads.v[idx]->id == id) + { + thread = threads.v[idx]; + } + } + return thread; +} + //- rjf: entity tree iteration internal CTRL_EntityRec @@ -1105,7 +1216,7 @@ ctrl_entity_rec_depth_first(CTRL_Entity *entity, CTRL_Entity *subtree_root, U64 //- rjf: applying events to entity caches internal void -ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) +ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *list) { //- rjf: scan events & construct entities for(CTRL_EventNode *n = list->first; n != 0; n = n->next) @@ -1118,14 +1229,14 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) //- rjf: processes case CTRL_EventKind_NewProc: { - CTRL_Entity *machine = ctrl_entity_from_handle(store, ctrl_handle_make(event->entity.machine_id, dmn_handle_zero())); + CTRL_Entity *machine = ctrl_entity_from_handle(&store->ctx, ctrl_handle_make(event->entity.machine_id, dmn_handle_zero())); CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->arch, event->entity, (U64)event->entity_id); }break; case CTRL_EventKind_EndProc: { - CTRL_Entity *process = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->entity); ctrl_entity_release(store, process); - for(CTRL_Entity *entry = store->root->first, *next = &ctrl_entity_nil; + for(CTRL_Entity *entry = store->ctx.root->first, *next = &ctrl_entity_nil; entry != &ctrl_entity_nil; entry = next) { @@ -1140,35 +1251,55 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) //- rjf: threads case CTRL_EventKind_NewThread: { - CTRL_Entity *process = ctrl_entity_from_handle(store, event->parent); + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); CTRL_Entity *thread = ctrl_entity_alloc(store, process, CTRL_EntityKind_Thread, event->arch, event->entity, (U64)event->entity_id); CTRL_Entity *first_thread = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Thread); if(first_thread == thread) { ctrl_entity_equip_string(store, thread, str8_lit("main_thread")); } - CTRL_EntityList pending_thread_names = ctrl_entity_list_from_kind(store, CTRL_EntityKind_PendingThreadName); - for(CTRL_EntityNode *n = pending_thread_names.first; n != 0; n = n->next) + CTRL_EntityArray pending_thread_names = ctrl_entity_array_from_kind(&store->ctx, CTRL_EntityKind_PendingThreadName); + for EachIndex(idx, pending_thread_names.count) { - if(n->v->id == event->entity_id) + CTRL_Entity *entity = pending_thread_names.v[idx]; + if(entity->id == event->entity_id) { - ctrl_entity_equip_string(store, thread, n->v->string); - ctrl_entity_release(store, n->v); + ctrl_entity_equip_string(store, thread, entity->string); + ctrl_entity_release(store, entity); + break; + } + } + CTRL_EntityArray pending_thread_colors = ctrl_entity_array_from_kind(&store->ctx, CTRL_EntityKind_PendingThreadColor); + for EachIndex(idx, pending_thread_colors.count) + { + CTRL_Entity *entity = pending_thread_colors.v[idx]; + if(entity->id == event->entity_id) + { + thread->rgba = entity->rgba; + ctrl_entity_release(store, entity); break; } } thread->stack_base = event->stack_base; - ctrl_query_cached_rip_from_thread(store, event->entity); + ctrl_rip_from_thread(&store->ctx, event->entity); }break; case CTRL_EventKind_EndThread: { - CTRL_Entity *thread = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *thread = ctrl_entity_from_handle(&store->ctx, event->entity); ctrl_entity_release(store, thread); }break; case CTRL_EventKind_ThreadName: { - CTRL_Entity *process = ctrl_entity_from_handle(store, event->parent); - CTRL_Entity *thread = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); + CTRL_Entity *thread = &ctrl_entity_nil; + if(event->entity_id == 0) + { + thread = ctrl_entity_from_handle(&store->ctx, event->entity); + } + else + { + thread = ctrl_thread_from_id(&store->ctx, event->entity_id); + } if(thread != &ctrl_entity_nil) { ctrl_entity_equip_string(store, thread, event->string); @@ -1181,17 +1312,34 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) }break; case CTRL_EventKind_ThreadColor: { - CTRL_Entity *thread = ctrl_entity_from_handle(store, event->entity); - thread->rgba = event->rgba; + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); + CTRL_Entity *thread = &ctrl_entity_nil; + if(event->entity_id == 0) + { + thread = ctrl_entity_from_handle(&store->ctx, event->entity); + } + else + { + thread = ctrl_thread_from_id(&store->ctx, event->entity_id); + } + if(thread != &ctrl_entity_nil) + { + thread->rgba = event->rgba; + } + else + { + CTRL_Entity *pending = ctrl_entity_alloc(store, process, CTRL_EntityKind_PendingThreadColor, Arch_Null, ctrl_handle_zero(), event->entity_id); + pending->rgba = event->rgba; + } }break; case CTRL_EventKind_ThreadFrozen: { - CTRL_Entity *thread = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *thread = ctrl_entity_from_handle(&store->ctx, event->entity); thread->is_frozen = 1; }break; case CTRL_EventKind_ThreadThawed: { - CTRL_Entity *thread = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *thread = ctrl_entity_from_handle(&store->ctx, event->entity); thread->is_frozen = 0; }break; @@ -1199,7 +1347,7 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) case CTRL_EventKind_NewModule: { Temp scratch = scratch_begin(0, 0); - CTRL_Entity *process = ctrl_entity_from_handle(store, event->parent); + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->entity, event->vaddr_rng.min); ctrl_entity_equip_string(store, module, event->string); module->timestamp = event->timestamp; @@ -1213,12 +1361,12 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) }break; case CTRL_EventKind_EndModule: { - CTRL_Entity *module = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *module = ctrl_entity_from_handle(&store->ctx, event->entity); ctrl_entity_release(store, module); }break; case CTRL_EventKind_ModuleDebugInfoPathChange: { - CTRL_Entity *module = ctrl_entity_from_handle(store, event->entity); + CTRL_Entity *module = ctrl_entity_from_handle(&store->ctx, event->entity); CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); if(debug_info_path == &ctrl_entity_nil) { @@ -1227,10 +1375,90 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) ctrl_entity_equip_string(store, debug_info_path, event->string); debug_info_path->timestamp = event->timestamp; }break; + + //- rjf: dynamic, program-created breakpoints + case CTRL_EventKind_SetBreakpoint: + { + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); + CTRL_Entity *bp = ctrl_entity_alloc(store, process, CTRL_EntityKind_Breakpoint, Arch_Null, ctrl_handle_zero(), 0); + bp->vaddr_range = event->vaddr_rng; + bp->bp_flags = event->bp_flags; + }break; + case CTRL_EventKind_UnsetBreakpoint: + { + CTRL_Entity *process = ctrl_entity_from_handle(&store->ctx, event->parent); + for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == CTRL_EntityKind_Breakpoint && + child->vaddr_range.min == event->vaddr_rng.min && + child->vaddr_range.max == event->vaddr_rng.max && + child->bp_flags == event->bp_flags) + { + ctrl_entity_release(store, child); + break; + } + } + }break; } } } +//////////////////////////////// +//~ rjf: Cache Accessing Scopes + +internal CTRL_Scope * +ctrl_scope_open(void) +{ + if(ctrl_tctx == 0) + { + Arena *arena = arena_alloc(); + ctrl_tctx = push_array(arena, CTRL_TCTX, 1); + ctrl_tctx->arena = arena; + } + CTRL_Scope *scope = ctrl_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(ctrl_tctx->free_scope); + } + else + { + scope = push_array_no_zero(ctrl_tctx->arena, CTRL_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +ctrl_scope_close(CTRL_Scope *scope) +{ + for(CTRL_ScopeCallStackTouch *t = scope->first_call_stack_touch, *next = 0; t != 0; t = next) + { + next = t->next; + ins_atomic_u64_dec_eval(&t->node->scope_touch_count); + os_condition_variable_broadcast(t->stripe->cv); + SLLStackPush(ctrl_tctx->free_call_stack_touch, t); + } + SLLStackPush(ctrl_tctx->free_scope, scope); +} + +internal void +ctrl_scope_touch_call_stack_node__stripe_r_guarded(CTRL_Scope *scope, CTRL_CallStackCacheStripe *stripe, CTRL_CallStackCacheNode *node) +{ + ins_atomic_u64_inc_eval(&node->scope_touch_count); + CTRL_ScopeCallStackTouch *touch = ctrl_tctx->free_call_stack_touch; + if(touch != 0) + { + SLLStackPop(ctrl_tctx->free_call_stack_touch); + } + else + { + touch = push_array(ctrl_tctx->arena, CTRL_ScopeCallStackTouch, 1); + } + SLLQueuePush(scope->first_call_stack_touch, scope->last_call_stack_touch, touch); + touch->stripe = stripe; + touch->node = node; +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -1275,6 +1503,16 @@ ctrl_init(void) ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); } + ctrl_state->call_stack_cache.slots_count = 1024; + ctrl_state->call_stack_cache.slots = push_array(arena, CTRL_CallStackCacheSlot, ctrl_state->call_stack_cache.slots_count); + ctrl_state->call_stack_cache.stripes_count = os_get_system_info()->logical_processor_count; + ctrl_state->call_stack_cache.stripes = push_array(arena, CTRL_CallStackCacheStripe, ctrl_state->call_stack_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->call_stack_cache.stripes_count; idx += 1) + { + ctrl_state->call_stack_cache.stripes[idx].arena = arena_alloc(); + ctrl_state->call_stack_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->call_stack_cache.stripes[idx].cv = os_condition_variable_alloc(); + } ctrl_state->module_image_info_cache.slots_count = 1024; ctrl_state->module_image_info_cache.slots = push_array(arena, CTRL_ModuleImageInfoCacheSlot, ctrl_state->module_image_info_cache.slots_count); ctrl_state->module_image_info_cache.stripes_count = os_get_system_info()->logical_processor_count; @@ -1302,10 +1540,11 @@ ctrl_init(void) os_write_data_to_file_path(ctrl_state->ctrl_thread_log_path, str8_zero()); scratch_end(scratch); } - ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); + ctrl_state->ctrl_thread_entity_ctx_rw_mutex = os_rw_mutex_alloc(); + ctrl_state->ctrl_thread_entity_store = ctrl_entity_ctx_rw_store_alloc(); + ctrl_state->ctrl_thread_eval_cache = e_cache_alloc(); ctrl_state->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)) { @@ -1318,6 +1557,10 @@ ctrl_init(void) ctrl_state->u2ms_ring_base = push_array(arena, U8, ctrl_state->u2ms_ring_size); ctrl_state->u2ms_ring_mutex = os_mutex_alloc(); ctrl_state->u2ms_ring_cv = os_condition_variable_alloc(); + ctrl_state->u2csb_ring_size = KB(64); + ctrl_state->u2csb_ring_base = push_array(arena, U8, ctrl_state->u2csb_ring_size); + ctrl_state->u2csb_ring_mutex = os_mutex_alloc(); + ctrl_state->u2csb_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); } @@ -1334,201 +1577,224 @@ ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) //////////////////////////////// //~ rjf: Process Memory Functions -//- rjf: process memory cache interaction +//- rjf: process memory cache key reading -internal U128 -ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated) +internal HS_Key +ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale) { - U64 key_hash_data[] = + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + + //- rjf: unpack process key + U64 process_hash = ctrl_hash_from_handle(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: get the hash store root for this process; construct process node if it + // doesn't exist + HS_Root root = {0}; { - (U64)process.machine_id, - (U64)process.dmn_handle.u64[0], - range.min, - range.max, - (U64)zero_terminated, - }; - U128 key = hs_hash_from_data(str8((U8*)key_hash_data, sizeof(key_hash_data))); - return key; -} - -internal U128 -ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us) -{ - ProfBeginFunction(); - U128 result = {0}; - U64 size = dim_1u64(range); - U64 pre_mem_gen = dmn_mem_gen(); - if(size != 0) for(;;) - { - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - 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]; - U64 range_hash = ctrl_hash_from_string(str8_struct(&range)); - - //- rjf: try to read from cache - B32 is_good = 0; - B32 is_stale = 1; + B32 node_found = 0; OS_MutexScopeR(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) + node_found = 1; + root = n->root; + break; + } + } + } + if(!node_found) 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)) + { + node_found = 1; + root = n->root; + break; + } + } + if(!node_found) + { + Arena *node_arena = arena_alloc(); + CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); + DLLPushBack(process_slot->first, process_slot->last, node); + node->arena = node_arena; + node->handle = process; + node->root = hs_root_alloc(); + node->range_hash_slots_count = 1024; + node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); + root = node->root; + } + } + } + + //- rjf: form ID for this process memory query + HS_ID id = {0}; + { + id.u128[0].u64[0] = vaddr_range.min & 0x00ffffffffffffffull; + id.u128[0].u64[1] = vaddr_range.max & 0x00ffffffffffffffull; + if(zero_terminated) + { + id.u128[0].u64[0] |= (1ull << 63); + } + } + U64 range_hash = hs_little_hash_from_data(str8_struct(&id)); + + //- rjf: form full key + HS_Key key = hs_key_make(root, id); + + //- rjf: loop: try to look for current results, request if not there, wait if we can, repeat until we can't + U64 mem_gen = ctrl_mem_gen(); + B32 key_is_stale = 0; + B32 requested = 0; + for(;;) + { + //- rjf: step 1: [read-only] try to look for current results for key's ID + B32 id_exists = 0; + B32 id_stale = 0; + B32 id_working = 0; + OS_MutexScopeR(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) + { + if(ctrl_handle_match(process_n->handle, process)) + { + U64 range_slot_idx = range_hash%process_n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + if(hs_id_match(n->id, id)) { - result = range_n->hash; - is_good = 1; - is_stale = (range_n->mem_gen != pre_mem_gen); - goto read_cache__break_all; + id_exists = 1; + id_stale = (n->mem_gen < mem_gen); + id_working = (ins_atomic_u64_eval(&n->working_count) != 0); + goto end_fast_lookup; } } } } - read_cache__break_all:; + end_fast_lookup:; + } + key_is_stale = id_stale; + + //- rjf: step 2: if the ID exists and is not stale, then we're done; + // the hash store contains the most up-to-date representation of the + // process memory for this key. + if(id_exists && !id_stale) + { + break; } - //- rjf: not good -> create process cache node if necessary - if(!is_good) + //- rjf: step 3: if the ID does not exist in the process' cache, then we + // need to build a node for it. if that, or if the ID is stale, then also + // request that that range is streamed. + if(!id_exists || (id_exists && id_stale && !id_working)) { + B32 node_needs_stream = 0; + U64 *node_working_count = 0; OS_MutexScopeW(process_stripe->rw_mutex) { - B32 process_node_exists = 0; - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) { - if(ctrl_handle_match(n->handle, process)) + if(ctrl_handle_match(process_n->handle, process)) { - process_node_exists = 1; - break; - } - } - if(!process_node_exists) - { - Arena *node_arena = arena_alloc(); - CTRL_ProcessMemoryCacheNode *node = push_array(node_arena, CTRL_ProcessMemoryCacheNode, 1); - node->arena = node_arena; - node->handle = process; - node->range_hash_slots_count = 1024; - node->range_hash_slots = push_array(node_arena, CTRL_ProcessMemoryRangeHashSlot, node->range_hash_slots_count); - DLLPushBack(process_slot->first, process_slot->last, node); - } - } - } - - //- rjf: not good -> create range node if necessary - U64 last_time_requested_us = 0; - if(!is_good) - { - 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]; - B32 range_node_exists = 0; - for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + U64 range_slot_idx = range_hash%process_n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; + CTRL_ProcessMemoryRangeHashNode *range_n = 0; + for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + if(hs_id_match(n->id, id)) { - last_time_requested_us = range_n->last_time_requested_us; - range_node_exists = 1; + range_n = n; break; } } - if(!range_node_exists) + if(range_n == 0) { - CTRL_ProcessMemoryRangeHashNode *range_n = push_array(n->arena, CTRL_ProcessMemoryRangeHashNode, 1); + range_n = push_array(process_n->arena, CTRL_ProcessMemoryRangeHashNode, 1); SLLQueuePush(range_slot->first, range_slot->last, range_n); - range_n->vaddr_range = range; + range_n->vaddr_range = vaddr_range; range_n->zero_terminated = zero_terminated; - range_n->vaddr_range_clamped = range; - { - range_n->vaddr_range_clamped.max = Max(range_n->vaddr_range_clamped.max, range_n->vaddr_range_clamped.min); - U64 max_size_cap = Min(max_U64-range_n->vaddr_range_clamped.min, GB(1)); - range_n->vaddr_range_clamped.max = Min(range_n->vaddr_range_clamped.max, range_n->vaddr_range_clamped.min+max_size_cap); - } - break; + range_n->id = id; + ins_atomic_u64_inc_eval(&range_n->working_count); + node_needs_stream = 1; } + else + { + node_needs_stream = (range_n->mem_gen < mem_gen); + if(node_needs_stream) + { + ins_atomic_u64_inc_eval(&range_n->working_count); + } + } + node_working_count = &range_n->working_count; + break; } } } - } - - //- 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)) + if(node_needs_stream) { - OS_MutexScopeW(process_stripe->rw_mutex) + if(ctrl_u2ms_enqueue_req(key, process, vaddr_range, zero_terminated, endt_us)) { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + async_push_work(ctrl_mem_stream_work, .working_counter = node_working_count); + requested = 1; + } + else OS_MutexScopeR(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *process_n = process_slot->first; process_n != 0; process_n = process_n->next) { - if(ctrl_handle_match(n->handle, process)) + if(ctrl_handle_match(process_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%process_n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &process_n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) { - if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + if(hs_id_match(n->id, id)) { - range_n->last_time_requested_us = os_now_microseconds(); - break; + ins_atomic_u64_dec_eval(&n->working_count); + goto end_fail_work; } } } } + end_fail_work:; } - async_push_work(ctrl_mem_stream_work); } } - //- rjf: out of time? -> exit + //- rjf: step 4: if we have no time to wait, then abort; if we submitted a + // request, but the work is done and we have no results, then abort; + // otherwise, wait on this process' stripe if(os_now_microseconds() >= endt_us) { - if(is_stale && out_is_stale) - { - out_is_stale[0] = 1; - } break; } - - //- rjf: done? -> exit - if(is_good && !is_stale) + else if(!id_working && requested) { break; } + else OS_MutexScopeR(process_stripe->rw_mutex) + { + os_condition_variable_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); + } } - U64 post_mem_gen = dmn_mem_gen(); - if(post_mem_gen != pre_mem_gen && out_is_stale) + if(out_is_stale) { - out_is_stale[0] = 1; + *out_is_stale = key_is_stale; } - ProfEnd(); - return result; -} - -//- rjf: bundled key/stream helper - -internal U128 -ctrl_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated) -{ - U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, range, zero_terminated); - ctrl_stored_hash_from_process_vaddr_range(process, range, zero_terminated, 0, 0); return key; } //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice -ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us) +ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us) { ProfBeginFunction(); CTRL_ProcessMemorySlice result = {0}; @@ -1554,9 +1820,9 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle proces for(U64 page_idx = 0; page_idx < page_count; page_idx += 1) { U64 page_base_vaddr = page_range.min + page_idx*page_size; - U128 page_key = ctrl_calc_hash_store_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0); B32 page_is_stale = 0; - U128 page_hash = ctrl_stored_hash_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, &page_is_stale, endt_us); + HS_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale); + U128 page_hash = hs_hash_from_key(page_key, 0); U128 page_last_hash = hs_hash_from_key(page_key, 1); result.stale = (result.stale || page_is_stale); page_hashes[page_idx] = page_hash; @@ -1671,37 +1937,12 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle proces return result; } -internal CTRL_ProcessMemorySlice -ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us) -{ - CTRL_ProcessMemorySlice result = ctrl_query_cached_data_from_process_vaddr_range(arena, process, r1u64(vaddr, vaddr+limit), endt_us); - U64 element_count = result.data.size/element_size; - for(U64 element_idx = 0; element_idx < element_count; element_idx += 1) - { - B32 element_is_zero = 1; - for(U64 element_byte_idx = 0; element_byte_idx < element_size; element_byte_idx += 1) - { - if(result.data.str[element_idx*element_size + element_byte_idx] != 0) - { - element_is_zero = 0; - break; - } - } - if(element_is_zero) - { - result.data.size = element_idx*element_size; - break; - } - } - return result; -} - internal B32 -ctrl_read_cached_process_memory(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) +ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) { Temp scratch = scratch_begin(0, 0); U64 needed_size = dim_1u64(range); - CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process, range, endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, endt_us); B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); if(good) { @@ -1774,7 +2015,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) for(Task *task = first_task; task != 0; task = task->next) { Temp temp = temp_begin(scratch.arena); - ctrl_query_cached_data_from_process_vaddr_range(temp.arena, task->process, task->range, endt_us); + ctrl_process_memory_slice_from_vaddr_range(temp.arena, task->process, task->range, endt_us); temp_end(temp); } @@ -1791,10 +2032,10 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src) //- rjf: thread register cache reading internal void * -ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle handle) +ctrl_reg_block_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle handle) { CTRL_ThreadRegCache *cache = &ctrl_state->thread_reg_cache; - CTRL_Entity *thread_entity = ctrl_entity_from_handle(store, handle); + CTRL_Entity *thread_entity = ctrl_entity_from_handle(ctx, handle); Arch arch = thread_entity->arch; U64 reg_block_size = regs_block_size_from_arch(arch); U64 hash = ctrl_hash_from_handle(handle); @@ -1850,31 +2091,31 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C } internal U64 -ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_Handle handle) +ctrl_tls_root_vaddr_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle) { U64 result = dmn_tls_root_vaddr_from_thread(handle.dmn_handle); return result; } internal U64 -ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_Handle handle) +ctrl_rip_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle) { Temp scratch = scratch_begin(0, 0); - CTRL_Entity *thread_entity = ctrl_entity_from_handle(store, handle); + CTRL_Entity *thread_entity = ctrl_entity_from_handle(ctx, handle); Arch arch = thread_entity->arch; - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, handle); + void *block = ctrl_reg_block_from_thread(scratch.arena, ctx, handle); U64 result = regs_rip_from_arch_block(arch, block); scratch_end(scratch); return result; } internal U64 -ctrl_query_cached_rsp_from_thread(CTRL_EntityStore *store, CTRL_Handle handle) +ctrl_rsp_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle) { Temp scratch = scratch_begin(0, 0); - CTRL_Entity *thread_entity = ctrl_entity_from_handle(store, handle); + CTRL_Entity *thread_entity = ctrl_entity_from_handle(ctx, handle); Arch arch = thread_entity->arch; - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, handle); + void *block = ctrl_reg_block_from_thread(scratch.arena, ctx, handle); U64 result = regs_rsp_from_arch_block(arch, block); scratch_end(scratch); return result; @@ -1885,6 +2126,7 @@ ctrl_query_cached_rsp_from_thread(CTRL_EntityStore *store, CTRL_Handle handle) internal B32 ctrl_thread_write_reg_block(CTRL_Handle thread, void *block) { + // TODO(rjf): @callstacks immediately reflect this in the call stack cache B32 good = dmn_thread_write_reg_block(thread.dmn_handle, block); return good; } @@ -2021,6 +2263,26 @@ ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_Handle module_handle return result; } +internal String8 +ctrl_raddbg_data_from_module(Arena *arena, CTRL_Handle module_handle) +{ + String8 result = {0}; + U64 hash = ctrl_hash_from_handle(module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->module, module_handle)) + { + result = push_str8_copy(arena, n->raddbg_data); + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Unwinding Functions @@ -2075,7 +2337,7 @@ ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX } internal CTRL_UnwindStepResult -ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CTRL_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) +ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, U64 module_base_vaddr, REGS_RegBlockX64 *regs, U64 endt_us) { B32 is_stale = 0; B32 is_good = 1; @@ -2084,9 +2346,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT ////////////////////////////// //- rjf: unpack parameters // - CTRL_Entity *module = ctrl_entity_from_handle(store, module_handle); - CTRL_Entity *process = ctrl_entity_from_handle(store, process_handle); - U64 rip_voff = regs->rip.u64 - module->vaddr_range.min; + U64 rip_voff = regs->rip.u64 - module_base_vaddr; ////////////////////////////// //- rjf: rip_voff -> first pdata @@ -2116,7 +2376,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U8 inst[4] = {0}; if(read_vaddr + sizeof(inst) <= read_vaddr_opl) { - inst_good = ctrl_read_cached_process_memory(process_handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, inst, endt_us); + inst_good = ctrl_process_memory_read(process_handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, inst, endt_us); inst_good = inst_good && !is_stale; } if(!inst_good) @@ -2197,7 +2457,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U8 inst_byte = 0; if(read_vaddr + sizeof(inst_byte) <= read_vaddr_opl) { - inst_byte_good = ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + inst_byte_good = ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &inst_byte, endt_us); } if(!inst_byte_good || is_stale) { @@ -2213,7 +2473,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT check_vaddr = read_vaddr + 1; if(read_vaddr + sizeof(check_inst_byte) <= read_vaddr_opl) { - check_inst_byte_good = ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &check_inst_byte, endt_us); + check_inst_byte_good = ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &check_inst_byte, endt_us); } if(!check_inst_byte_good || is_stale) { @@ -2249,7 +2509,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT B32 imm_good = 0; if(read_vaddr + sizeof(imm) <= read_vaddr_opl) { - imm_good = ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm, endt_us); + imm_good = ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm, endt_us); } if(!imm_good || is_stale) { @@ -2258,7 +2518,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT if(imm_good) { U64 next_vaddr = (U64)(imm_vaddr + sizeof(imm) + imm); - U64 next_voff = next_vaddr - module->vaddr_range.min; // TODO(rjf): verify that this offset is from module base vaddr, not section + U64 next_voff = next_vaddr - module_base_vaddr; // TODO(rjf): verify that this offset is from module base vaddr, not section if(!(first_pdata->voff_first <= next_voff && next_voff < first_pdata->voff_one_past_last)) { keep_parsing = 0; @@ -2278,7 +2538,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT B32 next_inst_byte_good = 0; if(read_vaddr + sizeof(next_inst_byte) <= read_vaddr_opl) { - next_inst_byte_good = ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &next_inst_byte, endt_us); + next_inst_byte_good = ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &next_inst_byte, endt_us); } if(next_inst_byte_good) { @@ -2307,7 +2567,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT //- rjf: read next instruction byte U8 inst_byte = 0; - is_good = is_good && ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &inst_byte, endt_us); is_good = is_good && !is_stale; read_vaddr += 1; @@ -2316,7 +2576,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT if((inst_byte & 0xF0) == 0x40) { rex = inst_byte & 0xF; // rex prefix - is_good = is_good && ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &inst_byte, endt_us); is_good = is_good && !is_stale; read_vaddr += 1; } @@ -2337,7 +2597,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read value at rsp U64 sp = regs->rsp.u64; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp, &is_stale, &value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp, &is_stale, &value, endt_us) || is_stale) { is_good = 0; @@ -2362,7 +2622,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read the 4-byte immediate S32 imm = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm, endt_us) || is_stale) { is_good = 0; @@ -2385,7 +2645,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read the 4-byte immediate S8 imm = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm, endt_us) || is_stale) { is_good = 0; @@ -2405,7 +2665,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT { // rjf: read source register U8 modrm = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &modrm, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &modrm, endt_us) || is_stale) { is_good = 0; @@ -2423,7 +2683,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT if((modrm >> 6) == 1) { S8 imm8 = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm8, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm8, endt_us) || is_stale) { is_good = 0; @@ -2436,7 +2696,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read 4-byte immediate else { - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm, endt_us) || is_stale) { is_good = 0; @@ -2459,7 +2719,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp, &is_stale, &new_ip, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp, &is_stale, &new_ip, endt_us) || is_stale) { is_good = 0; @@ -2468,7 +2728,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read 2-byte immediate & advance stack pointer U16 imm = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, read_vaddr, &is_stale, &imm, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, read_vaddr, &is_stale, &imm, endt_us) || is_stale) { is_good = 0; @@ -2491,7 +2751,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp, &is_stale, &new_ip, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp, &is_stale, &new_ip, endt_us) || is_stale) { is_good = 0; @@ -2538,7 +2798,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT { U64 unwind_info_off = first_pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; - if(!ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, module_base_vaddr+unwind_info_off, &is_stale, &unwind_info, endt_us) || is_stale) { is_good = 0; @@ -2562,11 +2822,11 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT B32 good_unwind_info = 1; U64 unwind_info_off = pdata->voff_unwind_info; PE_UnwindInfo unwind_info = {0}; - good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + good_unwind_info = good_unwind_info && ctrl_process_memory_read_struct(process_handle, module_base_vaddr+unwind_info_off, &is_stale, &unwind_info, endt_us); PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); - good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), - module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), - &is_stale, unwind_codes, endt_us); + good_unwind_info = good_unwind_info && ctrl_process_memory_read(process_handle, r1u64(module_base_vaddr+unwind_info_off+sizeof(unwind_info), + module_base_vaddr+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), + &is_stale, unwind_codes, endt_us); good_unwind_info = good_unwind_info && !is_stale; //- rjf: bad unwind info -> abort @@ -2621,7 +2881,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read value from stack pointer U64 rsp = regs->rsp.u64; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, rsp, &is_stale, &value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, rsp, &is_stale, &value, endt_us) || is_stale) { keep_parsing = 0; @@ -2683,7 +2943,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U64 off = code_ptr[1].u16*8; U64 addr = frame_base + off; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, addr, &is_stale, &value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, addr, &is_stale, &value, endt_us) || is_stale) { keep_parsing = 0; @@ -2702,7 +2962,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); U64 addr = frame_base + off; U64 value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, addr, &is_stale, &value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, addr, &is_stale, &value, endt_us) || is_stale) { keep_parsing = 0; @@ -2733,7 +2993,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U8 buf[16]; U64 off = code_ptr[1].u16*16; U64 addr = frame_base + off; - if(!ctrl_read_cached_process_memory(process->handle, r1u64(addr, addr+sizeof(buf)), &is_stale, buf, endt_us)) + if(!ctrl_process_memory_read(process_handle, r1u64(addr, addr+sizeof(buf)), &is_stale, buf, endt_us)) { keep_parsing = 0; is_good = 0; @@ -2751,7 +3011,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U8 buf[16]; U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); U64 addr = frame_base + off; - if(!ctrl_read_cached_process_memory(process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us) || + if(!ctrl_process_memory_read(process_handle, r1u64(addr, addr+16), &is_stale, buf, endt_us) || is_stale) { keep_parsing = 0; @@ -2783,7 +3043,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT sp_adj += 8; } U64 ip_value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp_adj, &is_stale, &ip_value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp_adj, &is_stale, &ip_value, endt_us) || is_stale) { keep_parsing = 0; @@ -2792,7 +3052,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT } U64 sp_after_ip = sp_adj + 8; U16 ss_value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp_after_ip, &is_stale, &ss_value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp_after_ip, &is_stale, &ss_value, endt_us) || is_stale) { keep_parsing = 0; @@ -2801,7 +3061,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT } U64 sp_after_ss = sp_after_ip + 8; U64 rflags_value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp_after_ss, &is_stale, &rflags_value, endt_us) || is_stale) { keep_parsing = 0; @@ -2810,7 +3070,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT } U64 sp_after_rflags = sp_after_ss + 8; U64 sp_value = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, sp_after_rflags, &is_stale, &sp_value, endt_us) || is_stale) { keep_parsing = 0; @@ -2844,7 +3104,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; last_pdata = pdata; pdata = push_array(scratch.arena, PE_IntelPdata, 1); - if(!ctrl_read_cached_process_memory_struct(process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, module_base_vaddr+chained_pdata_off, &is_stale, pdata, endt_us) || is_stale) { is_good = 0; @@ -2862,7 +3122,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT // rjf: read rip from stack pointer U64 rsp = regs->rsp.u64; U64 new_rip = 0; - if(!ctrl_read_cached_process_memory_struct(process->handle, rsp, &is_stale, &new_rip, endt_us) || + if(!ctrl_process_memory_read_struct(process_handle, rsp, &is_stale, &new_rip, endt_us) || is_stale) { is_good = 0; @@ -2890,7 +3150,7 @@ ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CT //- rjf: abstracted unwind step internal CTRL_UnwindStepResult -ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle module, Arch arch, void *reg_block, U64 endt_us) +ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, U64 endt_us) { CTRL_UnwindStepResult result = {0}; switch(arch) @@ -2898,7 +3158,7 @@ ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle modul default:{}break; case Arch_x64: { - result = ctrl_unwind_step__pe_x64(store, process, module, (REGS_RegBlockX64 *)reg_block, endt_us); + result = ctrl_unwind_step__pe_x64(process, module, module_base_vaddr, (REGS_RegBlockX64 *)reg_block, endt_us); }break; } return result; @@ -2907,7 +3167,7 @@ ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle modul //- rjf: abstracted full unwind internal CTRL_Unwind -ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle thread, U64 endt_us) +ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U64 endt_us) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -2915,13 +3175,13 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle threa unwind.flags |= CTRL_UnwindFlag_Error; //- rjf: unpack args - CTRL_Entity *thread_entity = ctrl_entity_from_handle(store, thread); + CTRL_Entity *thread_entity = ctrl_entity_from_handle(ctx, thread); CTRL_Entity *process_entity = thread_entity->parent; Arch arch = thread_entity->arch; U64 arch_reg_block_size = regs_block_size_from_arch(arch); //- rjf: grab initial register block - void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, thread); + void *regs_block = ctrl_reg_block_from_thread(scratch.arena, ctx, thread); B32 regs_block_good = (arch != Arch_Null && regs_block != 0); //- rjf: loop & unwind @@ -2935,18 +3195,19 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle threa { // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); - CTRL_Handle module = {0}; + U64 rsp = regs_rsp_from_arch_block(arch, regs_block); + CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) { if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) { - module = m->handle; + module = m; break; } } - // rjf: cancel on 0 rip - if(rip == 0) + // rjf: cancel on 0 rip/rsp + if(rsp == 0 && rip == 0) { break; } @@ -2960,12 +3221,13 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle threa frame_node_count += 1; // rjf: unwind one step - CTRL_UnwindStepResult step = ctrl_unwind_step(store, process_entity->handle, module, arch, regs_block, endt_us); + CTRL_UnwindStepResult step = ctrl_unwind_step(process_entity->handle, module->handle, module->vaddr_range.min, arch, regs_block, endt_us); unwind.flags |= step.flags; if(step.flags & CTRL_UnwindFlag_Error || regs_rsp_from_arch_block(arch, regs_block) == 0 || regs_rip_from_arch_block(arch, regs_block) == 0 || - regs_rip_from_arch_block(arch, regs_block) == rip) + (regs_rsp_from_arch_block(arch, regs_block) == rsp && + regs_rip_from_arch_block(arch, regs_block) == rip)) { break; } @@ -2992,46 +3254,235 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle threa //~ rjf: Call Stack Building Functions internal CTRL_CallStack -ctrl_call_stack_from_unwind(Arena *arena, DI_Scope *di_scope, CTRL_Entity *process, CTRL_Unwind *base_unwind) +ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *base_unwind) { + Temp scratch = scratch_begin(&arena, 1); + DI_Scope *di_scope = di_scope_open(); Arch arch = process->arch; CTRL_CallStack result = {0}; - result.concrete_frame_count = base_unwind->frames.count; - result.total_frame_count = result.concrete_frame_count; - result.frames = push_array(arena, CTRL_CallStackFrame, result.concrete_frame_count); - for(U64 idx = 0; idx < result.concrete_frame_count; idx += 1) { - CTRL_UnwindFrame *src = &base_unwind->frames.v[idx]; - CTRL_CallStackFrame *dst = &result.frames[idx]; - U64 rip_vaddr = regs_rip_from_arch_block(arch, src->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); - RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff); - - // rjf: fill concrete frame info - dst->regs = src->regs; - dst->rdi = rdi; - dst->procedure = rdi_element_from_name_idx(rdi, Procedures, scope->proc_idx); - - // rjf: push inline frames - for(RDI_Scope *s = scope; - s->inline_site_idx != 0; - s = rdi_element_from_name_idx(rdi, Scopes, s->parent_scope_idx)) + typedef struct FrameNode FrameNode; + struct FrameNode { - RDI_InlineSite *site = rdi_element_from_name_idx(rdi, InlineSites, s->inline_site_idx); - CTRL_CallStackInlineFrame *inline_frame = push_array(arena, CTRL_CallStackInlineFrame, 1); - DLLPushFront(dst->first_inline_frame, dst->last_inline_frame, inline_frame); - inline_frame->inline_site = site; - dst->inline_frame_count += 1; - result.inline_frame_count += 1; - result.total_frame_count += 1; + FrameNode *next; + CTRL_CallStackFrame v; + }; + + //- rjf: gather all frames + FrameNode *first_frame = 0; + FrameNode *last_frame = 0; + U64 frame_count = 0; + for(U64 base_frame_idx = 0; base_frame_idx < base_unwind->frames.count; base_frame_idx += 1) + { + // rjf: unpack + CTRL_UnwindFrame *src = &base_unwind->frames.v[base_frame_idx]; + U64 rip_vaddr = regs_rip_from_arch_block(arch, src->regs); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff); + + // rjf: build inline frames (minus parent & inline depth) + FrameNode *first_inline_frame = 0; + FrameNode *last_inline_frame = 0; + U64 inline_frame_count = 0; + for(RDI_Scope *s = scope; + s->inline_site_idx != 0; + s = rdi_element_from_name_idx(rdi, Scopes, s->parent_scope_idx)) + { + FrameNode *dst_inline = push_array(scratch.arena, FrameNode, 1); + if(first_inline_frame == 0) + { + first_inline_frame = dst_inline; + } + last_inline_frame = dst_inline; + SLLQueuePush(first_frame, last_frame, dst_inline); + dst_inline->v.unwind_count = base_frame_idx; + dst_inline->v.regs = src->regs; + frame_count += 1; + inline_frame_count += 1; + } + + // rjf: build concrete frame + FrameNode *dst_base = push_array(scratch.arena, FrameNode, 1); + SLLQueuePush(first_frame, last_frame, dst_base); + dst_base->v.unwind_count = base_frame_idx; + dst_base->v.regs = src->regs; + frame_count += 1; + + // rjf: hook up inline frames to point to concrete frame, and to account for inline depth + U64 inline_frame_idx = 0; + for(FrameNode *inline_frame = first_inline_frame; inline_frame != 0; inline_frame = inline_frame->next, inline_frame_idx += 1) + { + inline_frame->v.inline_depth = inline_frame_count - inline_frame_idx; + if(inline_frame == last_inline_frame) + { + break; + } + } + } + + //- rjf: package + result.frames_count = frame_count; + result.frames = push_array(arena, CTRL_CallStackFrame, result.frames_count); + result.concrete_frames_count = base_unwind->frames.count; + result.concrete_frames = push_array(arena, CTRL_CallStackFrame *, result.concrete_frames_count); + { + U64 idx = 0; + U64 concrete_idx = 0; + for(FrameNode *n = first_frame; n != 0; n = n->next, idx += 1) + { + MemoryCopyStruct(&result.frames[idx], &n->v); + if(n->v.inline_depth == 0 && concrete_idx < result.concrete_frames_count) + { + result.concrete_frames[concrete_idx] = &result.frames[idx]; + concrete_idx += 1; + } + } } } + di_scope_close(di_scope); + scratch_end(scratch); return result; } +internal CTRL_CallStackFrame * +ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U64 unwind_count, U64 inline_depth) +{ + CTRL_CallStackFrame *f = 0; + { + U64 base_frame_idx = 0; + for(U64 idx = 0; idx < call_stack->frames_count; idx += 1) + { + if(call_stack->frames[idx].inline_depth == 0) + { + if(base_frame_idx == unwind_count) + { + f = &call_stack->frames[idx]; + break; + } + base_frame_idx += 1; + } + } + if(f != 0 && call_stack->frames + inline_depth < f) + { + f -= inline_depth; + } + } + return f; +} + +//////////////////////////////// +//~ rjf: Call Stack Cache Functions + +internal CTRL_CallStack +ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_Entity *thread, B32 high_priority, U64 endt_us) +{ + CTRL_CallStack call_stack = {0}; + CTRL_CallStackCache *cache = &ctrl_state->call_stack_cache; + + ////////////////////////////// + //- rjf: unpack thread + // + CTRL_Handle handle = thread->handle; + U64 hash = ctrl_hash_from_handle(handle); + U64 slot_idx = hash%cache->slots_count; + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_CallStackCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_CallStackCacheStripe *stripe = &cache->stripes[stripe_idx]; + U64 reg_gen = ctrl_reg_gen(); + U64 mem_gen = ctrl_mem_gen(); + + ////////////////////////////// + //- rjf: loop: try to grab cached call stack; request; wait + // + B32 can_request = !ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state); + B32 did_request = 0; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + //////////////////////////// + //- rjf: try to grab cached + // + B32 is_good = 0; + B32 is_stale = 1; + B32 is_working = 0; + CTRL_CallStackCacheNode *node = 0; + { + for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->thread, handle)) + { + node = n; + is_good = 1; + is_stale = (reg_gen > n->reg_gen || mem_gen > n->mem_gen); + is_working = (n->working_count > 0); + call_stack = n->call_stack; + ctrl_scope_touch_call_stack_node__stripe_r_guarded(scope, stripe, n); + break; + } + } + } + + //////////////////////////// + //- rjf: create node if needed + // + if(!is_good) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + node = 0; + for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->thread, handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(stripe->arena, CTRL_CallStackCacheNode, 1); + DLLPushBack(slot->first, slot->last, node); + node->thread = thread->handle; + } + } + + //////////////////////////// + //- rjf: request if needed + // + if(can_request && node != 0 && !is_working && is_stale) + { + if(ctrl_u2csb_enqueue_req(thread->handle, endt_us)) + { + did_request = 1; + is_working = 1; + ins_atomic_u64_inc_eval(&node->working_count); + async_push_work(ctrl_call_stack_build_work, .priority = high_priority ? ASYNC_Priority_High : ASYNC_Priority_Low); + } + } + + //////////////////////////// + //- rjf: good, or timeout? -> exit + // + if(!can_request || !is_stale || os_now_microseconds() >= endt_us) + { + break; + } + + //////////////////////////// + //- rjf: time to wait for new result? -> wait + // + if(did_request && !is_working) + { + break; + } + else if(did_request) + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + } + return call_stack; +} + //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -3150,7 +3601,10 @@ ctrl_c2u_push_events(CTRL_EventList *events) { if(events->count != 0) ProfScope("ctrl_c2u_push_events") { - ctrl_entity_store_apply_events(ctrl_state->ctrl_thread_entity_store, events); + OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + { + ctrl_entity_store_apply_events(ctrl_state->ctrl_thread_entity_store, events); + } for(CTRL_EventNode *n = events->first; n != 0; n = n ->next) { Temp scratch = scratch_begin(0, 0); @@ -3232,6 +3686,7 @@ ctrl_thread__entry_point(void *p) //- rjf: process messages DMN_CtrlExclusiveAccessScope { + ins_atomic_u64_eval_assign(&ctrl_state->ctrl_thread_run_state, 1); for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0; msg_n = msg_n->next) { CTRL_Msg *msg = &msg_n->v; @@ -3242,8 +3697,6 @@ ctrl_thread__entry_point(void *p) //- rjf: unpack per-message parameterizations & store { MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters); - arena_clear(ctrl_state->user_meta_eval_arena); - ctrl_state->user_meta_evals = *deep_copy_from_struct(ctrl_state->user_meta_eval_arena, CTRL_MetaEvalArray, &msg->meta_evals); } //- rjf: process message @@ -3273,12 +3726,13 @@ ctrl_thread__entry_point(void *p) }break; case CTRL_MsgKind_SetModuleDebugInfoPath: { + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; String8 path = msg->path; - CTRL_Entity *module = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, msg->entity); + CTRL_Entity *module = ctrl_entity_from_handle(entity_ctx, msg->entity); CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); DI_Key old_dbgi_key = {debug_info_path->string, debug_info_path->timestamp}; di_close(&old_dbgi_key); - ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path); + OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path); U64 new_dbgi_timestamp = os_properties_from_file_path(path).modified; debug_info_path->timestamp = new_dbgi_timestamp; DI_Key new_dbgi_key = {debug_info_path->string, new_dbgi_timestamp}; @@ -3309,6 +3763,7 @@ ctrl_thread__entry_point(void *p) }break; } } + ins_atomic_u64_eval_assign(&ctrl_state->ctrl_thread_run_state, 0); } //- rjf: gather & output logs @@ -3331,12 +3786,13 @@ ctrl_thread__entry_point(void *p) //- rjf: breakpoint resolution internal void -ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { if(user_bps->first == 0) { return; } Temp scratch = scratch_begin(&arena, 1); - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *module_entity = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, module); + DI_Scope *di_scope = eval_scope->di_scope; + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_Entity *module_entity = ctrl_entity_from_handle(entity_ctx, module); CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp}; RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); @@ -3399,49 +3855,60 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_Handle proc } }break; - //- rjf: symbol:voff-based breakpoints - case CTRL_UserBreakpointKind_SymbolNameAndOffset: + //- rjf: expression-based breakpoints + case CTRL_UserBreakpointKind_Expression: { - String8 symbol_name = bp->string; - U64 voff = bp->u64; - RDI_NameMap *mapptr = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); - RDI_ParsedNameMap map = {0}; - rdi_parsed_from_name_map(rdi, mapptr, &map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, symbol_name.str, symbol_name.size); - if(node != 0) + String8 expr = bp->string; + E_Value value = e_value_from_string(expr); + if(value.u64 != 0) { - U32 id_count = 0; - U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); - for(U32 match_i = 0; match_i < id_count; match_i += 1) - { - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, ids[match_i]); - U64 proc_voff = rdi_first_voff_from_procedure(rdi, procedure); - U64 proc_vaddr = proc_voff + base_vaddr; - DMN_Trap trap = {process.dmn_handle, proc_vaddr + voff, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); - } + DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp}; + trap.flags = ctrl_dmn_trap_flags_from_user_breakpoint_flags(bp->flags); + trap.size = bp->size; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); } }break; } } - di_scope_close(di_scope); scratch_end(scratch); } internal void -ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { CTRL_UserBreakpoint *bp = &n->v; - if(bp->kind == CTRL_UserBreakpointKind_VirtualAddress) + if(bp->kind == CTRL_UserBreakpointKind_Expression) { - DMN_Trap trap = {process.dmn_handle, bp->u64, (U64)bp}; - dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + String8 expr = bp->string; + E_Value value = e_value_from_string(expr); + if(value.u64 != 0) + { + DMN_Trap trap = {process.dmn_handle, value.u64, (U64)bp}; + trap.flags = ctrl_dmn_trap_flags_from_user_breakpoint_flags(bp->flags); + trap.size = bp->size; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } } } } +internal void +ctrl_thread__append_program_defined_bp_traps(Arena *arena, CTRL_Entity *bp, DMN_TrapChunkList *traps_out) +{ + CTRL_Entity *process = bp->parent; + DMN_Trap trap = + { + .process = process->handle.dmn_handle, + .vaddr = bp->vaddr_range.min, + .id = ((U64)bp|bit64), + .flags = ctrl_dmn_trap_flags_from_user_breakpoint_flags(bp->bp_flags), + .size = (U32)dim_1u64(bp->vaddr_range), + }; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); +} + //- rjf: module lifetime open/close work internal void @@ -3462,6 +3929,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U32 rdi_dbg_time = 0; Guid rdi_dbg_guid = {0}; String8 rdi_dbg_path = str8_zero(); + String8 raddbg_data = str8_zero(); + Rng1U64 raddbg_section_voff_range = r1u64(0, 0); ProfScope("unpack relevant PE info") { B32 is_valid = 1; @@ -3572,7 +4041,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ switch(file_header.machine) { default:{}break; - case COFF_Machine_X86: + case COFF_MachineType_X86: { PE_TLSHeader32 tls_header32 = {0}; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header32); @@ -3583,7 +4052,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; tls_header.characteristics = (U64)tls_header32.characteristics; }break; - case COFF_Machine_X64: + case COFF_MachineType_X64: { dmn_process_read_struct(process.dmn_handle, vaddr_range.min + tls_voff_range.min, &tls_header); }break; @@ -3655,6 +4124,36 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } } } + + // rjf: extract copy of module's raddbg data + { + Temp scratch = scratch_begin(0, 0); + U64 sec_array_off = opt_ext_off_range.max; + U64 sec_count = file_header.section_count; + COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec); + for EachIndex(idx, sec_count) + { + String8 section_name = str8_cstring((char *)sec[idx].name); + if(str8_match(section_name, str8_lit(".raddbg"), 0)) + { + raddbg_section_voff_range.min = sec[idx].voff; + raddbg_section_voff_range.max = sec[idx].voff + sec[idx].vsize; + } + } + raddbg_data.size = dim_1u64(raddbg_section_voff_range); + raddbg_data.str = push_array(arena, U8, raddbg_data.size); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + raddbg_section_voff_range.min, + vaddr_range.min + raddbg_section_voff_range.max), raddbg_data.str); + scratch_end(scratch); + } + + // rjf: if we have a raddbg section, mark the first byte as 1, to signify attachment + if(raddbg_section_voff_range.max != raddbg_section_voff_range.min) + { + U8 new_value = 1; + dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_section_voff_range.min, &new_value); + } } } @@ -3696,7 +4195,7 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ FileProperties props = os_properties_from_file_path(candidate_path); if(props.modified != 0 && props.size != 0) { - initial_debug_info_path = push_str8_copy(arena, candidate_path); + initial_debug_info_path = push_str8_copy(arena, path_normalized_from_string(scratch.arena, candidate_path)); break; } } @@ -3733,17 +4232,20 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ node->pdatas_count = pdatas_count; node->entry_point_voff = entry_point_voff; node->initial_debug_info_path = initial_debug_info_path; + node->raddbg_section_voff_range = raddbg_section_voff_range; + node->raddbg_data = raddbg_data; } } } } internal void -ctrl_thread__module_close(CTRL_Handle module) +ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_range) { ////////////////////////////// //- rjf: evict module image info from cache // + Rng1U64 raddbg_section_voff_range = {0}; { U64 hash = ctrl_hash_from_handle(module); U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; @@ -3763,11 +4265,21 @@ ctrl_thread__module_close(CTRL_Handle module) } if(node) { + raddbg_section_voff_range = node->raddbg_section_voff_range; DLLRemove(slot->first, slot->last, node); arena_release(node->arena); } } } + + ////////////////////////////// + //- rjf: write 0 into first byte of raddbg data section, to signify detachment + // + if(raddbg_section_voff_range.max != raddbg_section_voff_range.min) + { + U8 new_value = 0; + dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_section_voff_range.min, &new_value); + } } //- rjf: attached process running/event gathering @@ -3778,6 +4290,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, ProfBeginFunction(); DMN_Event *event = push_array(arena, DMN_Event, 1); Temp scratch = scratch_begin(&arena, 1); + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; //- rjf: loop -> try to get event, run, repeat U64 spoof_old_ip_value = 0; @@ -3850,7 +4363,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, ev->process)); + CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, ev->process)); CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) { @@ -3941,7 +4454,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, U64 size_of_spoof = 0; if(do_spoof) ProfScope("prep spoof") { - CTRL_Entity *spoof_process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, spoof->process)); + CTRL_Entity *spoof_process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, spoof->process)); Arch arch = spoof_process->arch; size_of_spoof = bit_size_from_arch(arch)/8; dmn_process_read(spoof_process->handle.dmn_handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); @@ -4007,7 +4520,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // simply been sent other debug events first if(spoof != 0) { - CTRL_Entity *thread = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, spoof->thread)); + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, spoof->thread)); Arch arch = thread->arch; void *regs_block = push_array(scratch.arena, U8, regs_block_size_from_arch(arch)); dmn_thread_read_reg_block(spoof->thread, regs_block); @@ -4099,13 +4612,14 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); CTRL_Handle module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module); + CTRL_Entity *module_ent = ctrl_entity_from_handle(entity_ctx, module_handle); + CTRL_Entity *process_ent = ctrl_process_from_entity(module_ent); String8 module_path = event->string; - ctrl_thread__module_close(module_handle); + ctrl_thread__module_close(process_ent->handle, module_handle, module_ent->vaddr_range); out_evt->kind = CTRL_EventKind_EndModule; out_evt->msg_id = msg->msg_id; out_evt->entity = module_handle; out_evt->string = module_path; - CTRL_Entity *module_ent = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, module_handle); CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); if(debug_info_path_ent != &ctrl_entity_nil) { @@ -4136,6 +4650,35 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, out_evt->string = event->string; out_evt->entity_id = event->code; }break; + case DMN_EventKind_SetThreadColor: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_ThreadColor; + out_evt->msg_id = msg->msg_id; + out_evt->entity = ctrl_handle_make(CTRL_MachineID_Local, event->thread); + out_evt->parent = ctrl_handle_make(CTRL_MachineID_Local, event->process); + out_evt->entity_id = event->code; + out_evt->rgba = event->user_data; + }break; + case DMN_EventKind_SetBreakpoint: + { + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_SetBreakpoint; + out_evt->entity = ctrl_handle_make(CTRL_MachineID_Local, event->thread); + out_evt->parent = ctrl_handle_make(CTRL_MachineID_Local, event->process); + out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); + out_evt->bp_flags = ctrl_user_breakpoint_flags_from_dmn_trap_flags(event->flags); + }break; + case DMN_EventKind_UnsetBreakpoint: + { + // TODO(rjf): this needs to be reflected in the resolved trap list too!!!!!!!! + CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + out_evt->kind = CTRL_EventKind_UnsetBreakpoint; + out_evt->entity = ctrl_handle_make(CTRL_MachineID_Local, event->thread); + out_evt->parent = ctrl_handle_make(CTRL_MachineID_Local, event->process); + out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); + out_evt->bp_flags = ctrl_user_breakpoint_flags_from_dmn_trap_flags(event->flags); + }break; } ctrl_c2u_push_events(&evts); @@ -4163,16 +4706,16 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // 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)) + (entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] > 256 || + entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] == 1)) { U64 endt_us = os_now_microseconds() + 1000000; //- rjf: unpack event CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process); CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module); - 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); + CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, process_handle); + CTRL_Entity *loaded_module = ctrl_entity_from_handle(entity_ctx, 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 @@ -4389,8 +4932,9 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) case CTRL_EntityKind_Thread: { Temp scratch = scratch_begin(0, 0); + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; U64 regs_size = regs_block_size_from_arch(entity->arch); - void *regs = ctrl_query_cached_reg_block_from_thread(scratch.arena, ctrl_state->ctrl_thread_entity_store, entity->handle); + void *regs = ctrl_reg_block_from_thread(scratch.arena, entity_ctx, entity->handle); Rng1U64 legal_range = r1u64(0, regs_size); Rng1U64 read_range = intersect_1u64(legal_range, range); U64 read_size = dim_1u64(read_range); @@ -4404,42 +4948,143 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) //- rjf: meta evaluations case CTRL_EvalSpaceKind_Meta: { - Temp scratch = scratch_begin(0, 0); - U64 meta_eval_idx = space.u64s[0]; - if(meta_eval_idx < ctrl_state->user_meta_evals.count) - { - CTRL_MetaEval *meval = &ctrl_state->user_meta_evals.v[meta_eval_idx]; - - // rjf: copy meta evaluation to scratch arena, to form range of legal reads - arena_push(scratch.arena, 0, 64); - String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); - U64 pos_min = arena_pos(scratch.arena); - CTRL_MetaEval *meval_read = struct_from_serialized(scratch.arena, CTRL_MetaEval, meval_srlzed); - U64 pos_opl = arena_pos(scratch.arena); - - // rjf: rebase all pointer values in meta evaluation to be relative to base pointer - struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); - - // rjf: perform actual read - Rng1U64 legal_range = r1u64(0, pos_opl-pos_min); - if(contains_1u64(legal_range, range.min)) - { - result = 1; - U64 range_dim = dim_1u64(range); - U64 bytes_to_read = Min(range_dim, (legal_range.max - range.min)); - MemoryCopy(out, ((U8 *)meval_read) + range.min, bytes_to_read); - if(bytes_to_read < range_dim) - { - MemoryZero((U8 *)out + bytes_to_read, range_dim - bytes_to_read); - } - } - } - scratch_end(scratch); + }break; } return result; } +//- rjf: control thread eval scopes + +internal CTRL_EvalScope * +ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread) +{ + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1); + scope->di_scope = di_scope_open(); + + ////////////////////////////// + //- rjf: unpack thread + // + Arch arch = thread->arch; + U64 thread_rip_vaddr = dmn_rip_from_thread(thread->handle.dmn_handle); + CTRL_Entity *process = ctrl_process_from_entity(thread); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); + U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); + + ////////////////////////////// + //- rjf: gather evaluation modules + // + U64 eval_modules_count = Max(1, entity_ctx->entity_kind_counts[CTRL_EntityKind_Module]); + E_Module *eval_modules = push_array(arena, E_Module, eval_modules_count); + E_Module *eval_modules_primary = &eval_modules[0]; + eval_modules_primary->rdi = &rdi_parsed_nil; + eval_modules_primary->vaddr_range = r1u64(0, max_U64); + { + U64 eval_module_idx = 0; + for(CTRL_Entity *machine = entity_ctx->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) + { + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; + process != &ctrl_entity_nil; + process = process->next) + { + if(process->kind != CTRL_EntityKind_Process) { continue; } + for(CTRL_Entity *mod = process->first; + mod != &ctrl_entity_nil; + mod = mod->next) + { + if(mod->kind != CTRL_EntityKind_Module) { continue; } + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + eval_modules[eval_module_idx].arch = arch; + eval_modules[eval_module_idx].rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, max_U64); + eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; + eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); + eval_modules[eval_module_idx].space.u64_0 = (U64)process; + if(mod == module) + { + eval_modules_primary = &eval_modules[eval_module_idx]; + } + eval_module_idx += 1; + } + } + } + } + + ////////////////////////////// + //- rjf: select evaluation cache + // + e_select_cache(ctrl_state->ctrl_thread_eval_cache); + + ////////////////////////////// + //- rjf: build base evaluation context + // + { + E_BaseCtx *ctx = &scope->base_ctx; + + //- rjf: fill instruction pointer info + ctx->thread_ip_vaddr = thread_rip_vaddr; + ctx->thread_ip_voff = thread_rip_voff; + ctx->thread_arch = thread->arch; + ctx->thread_reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); + ctx->thread_reg_space.u64_0 = (U64)thread; + + //- rjf: fill modules + ctx->modules = eval_modules; + ctx->modules_count = eval_modules_count; + ctx->primary_module = eval_modules_primary; + + //- rjf: fill space hooks + ctx->space_read = ctrl_eval_space_read; + } + e_select_base_ctx(&scope->base_ctx); + + ////////////////////////////// + //- rjf: build IR evaluation context + // + { + E_IRCtx *ctx = &scope->ir_ctx; + ctx->regs_map = ctrl_string2reg_from_arch(arch); + ctx->reg_alias_map = ctrl_string2alias_from_arch(arch); + ctx->locals_map = e_push_locals_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); + ctx->member_map = e_push_member_map_from_rdi_voff(arena, eval_modules_primary->rdi, thread_rip_voff); + ctx->macro_map = push_array(arena, E_String2ExprMap, 1); + ctx->macro_map[0] = e_string2expr_map_make(arena, 512); + ctx->auto_hook_map = push_array(arena, E_AutoHookMap, 1); + ctx->auto_hook_map[0] = e_auto_hook_map_make(arena, 512); + } + e_select_ir_ctx(&scope->ir_ctx); + + ////////////////////////////// + //- rjf: build eval interpretation context + // + { + E_InterpretCtx *ctx = &scope->interpret_ctx; + ctx->space_read = ctrl_eval_space_read; + ctx->primary_space = eval_modules_primary->space; + ctx->reg_arch = eval_modules_primary->arch; + ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); + ctx->reg_space.u64_0 = (U64)thread; + ctx->module_base = push_array(arena, U64, 1); + ctx->module_base[0]= module->vaddr_range.min; + ctx->frame_base = push_array(arena, U64, 1); + // TODO(rjf): need to compute this out here somehow... ctx->frame_base[0] = ; + ctx->tls_base = push_array(arena, U64, 1); + } + e_select_interpret_ctx(&scope->interpret_ctx, eval_modules_primary->rdi, thread_rip_voff); + + return scope; +} + +internal void +ctrl_thread__eval_scope_end(CTRL_EvalScope *scope) +{ + di_scope_close(scope->di_scope); +} + //- rjf: log flusher internal void @@ -4462,25 +5107,32 @@ ctrl_thread__end_and_flush_info_log(void) internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { + Temp scratch = scratch_begin(0, 0); + + //- rjf: produce full stdout/stderr/stdin paths + String8 stdout_path = path_absolute_dst_from_relative_dst_src(scratch.arena, msg->stdout_path, msg->path); + String8 stdin_path = path_absolute_dst_from_relative_dst_src(scratch.arena, msg->stdin_path, msg->path); + String8 stderr_path = path_absolute_dst_from_relative_dst_src(scratch.arena, msg->stderr_path, msg->path); + //- rjf: obtain stdout/stderr/stdin handles OS_Handle stdout_handle = {0}; OS_Handle stderr_handle = {0}; OS_Handle stdin_handle = {0}; - if(msg->stdout_path.size != 0) + if(stdout_path.size != 0) { - OS_Handle f = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, msg->stdout_path); + OS_Handle f = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, stdout_path); os_file_close(f); stdout_handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, msg->stdout_path); } - if(msg->stderr_path.size != 0) + if(stderr_path.size != 0) { - OS_Handle f = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, msg->stderr_path); + OS_Handle f = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, stderr_path); os_file_close(f); stderr_handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, msg->stderr_path); } - if(msg->stdin_path.size != 0) + if(stdin_path.size != 0) { - stdin_handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, msg->stdin_path); + stdin_handle = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, stdin_path); } //- rjf: launch @@ -4503,12 +5155,18 @@ ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) os_file_close(stdin_handle); //- rjf: record (id -> entry points), so that we know custom entry points for this PID - for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) + CTRL_EntityCtxRWStore *entity_ctx_rw_store = ctrl_state->ctrl_thread_entity_store; + OS_MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) { - String8 string = n->string; - CTRL_Entity *entry = ctrl_entity_alloc(ctrl_state->ctrl_thread_entity_store, ctrl_state->ctrl_thread_entity_store->root, CTRL_EntityKind_EntryPoint, Arch_Null, ctrl_handle_zero(), (U64)id); - ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, entry, string); + for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) + { + String8 string = n->string; + CTRL_Entity *entry = ctrl_entity_alloc(entity_ctx_rw_store, entity_ctx_rw_store->ctx.root, CTRL_EntityKind_EntryPoint, Arch_Null, ctrl_handle_zero(), (U64)id); + ctrl_entity_equip_string(entity_ctx_rw_store, entry, string); + } } + + scratch_end(scratch); } internal void @@ -4626,9 +5284,10 @@ ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); U32 exit_code = msg->exit_code; + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; //- rjf: gather all currently existing processes - CTRL_EntityList initial_processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray initial_processes = ctrl_entity_array_from_kind(entity_ctx, CTRL_EntityKind_Process); typedef struct Task Task; struct Task { @@ -4638,10 +5297,11 @@ ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) }; Task *first_task = 0; Task *last_task = 0; - for(CTRL_EntityNode *n = initial_processes.first; n != 0; n = n->next) + for EachIndex(idx, initial_processes.count) { + CTRL_Entity *entity = initial_processes.v[idx]; Task *t = push_array(scratch.arena, Task, 1); - t->process = n->v; + t->process = entity; DLLPushBack(first_task, last_task, t); } @@ -4672,7 +5332,7 @@ ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) 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)); + CTRL_Entity *new_process = ctrl_entity_from_handle(entity_ctx, 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); @@ -4682,7 +5342,7 @@ ctrl_thread__kill_all(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } // rjf: end if all processes are gone - CTRL_EntityList processes = ctrl_entity_list_from_kind(ctrl_state->ctrl_thread_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(entity_ctx, CTRL_EntityKind_Process); if(processes.count == 0) { done = 1; @@ -4761,9 +5421,10 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) Temp scratch = scratch_begin(0, 0); DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; + CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; CTRL_Handle target_thread = msg->entity; CTRL_Handle target_process = msg->parent; - CTRL_Entity *target_process_entity = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, target_process); + CTRL_Entity *target_process_entity = ctrl_entity_from_handle(entity_ctx, target_process); U64 spoof_ip_vaddr = 911; log_infof("ctrl_thread__run:\n{\n"); @@ -4771,25 +5432,37 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: gather all initial breakpoints // DMN_TrapChunkList user_traps = {0}; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; - machine != &ctrl_entity_nil; - machine = machine->next) { - if(machine->kind != CTRL_EntityKind_Machine) { continue; } - for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, target_thread); + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread); + for(CTRL_Entity *machine = entity_ctx->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { - if(process->kind != CTRL_EntityKind_Process) { continue; } - - // rjf: resolve module-dependent user bps - for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - if(module->kind != CTRL_EntityKind_Module) { continue; } - ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, process->handle, module->handle, &msg->user_bps, &user_traps); + if(process->kind != CTRL_EntityKind_Process) { continue; } + + // rjf: resolve module-dependent user bps + for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + { + if(module->kind != CTRL_EntityKind_Module) { continue; } + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, eval_scope, process->handle, module->handle, &msg->user_bps, &user_traps); + } + + // rjf: push process-declared breakpoins + for(CTRL_Entity *bp = process->first; bp != &ctrl_entity_nil; bp = bp->next) + { + if(bp->kind != CTRL_EntityKind_Breakpoint) { continue; } + ctrl_thread__append_program_defined_bp_traps(scratch.arena, bp, &user_traps); + } + + // rjf: push virtual-address user breakpoints per-process + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, eval_scope, process->handle, &msg->user_bps, &user_traps); } - - // rjf: push virtual-address user breakpoints per-process - ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, process->handle, &msg->user_bps, &user_traps); } + ctrl_thread__eval_scope_end(eval_scope); } ////////////////////////////// @@ -4819,7 +5492,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { // rjf: gather stuck threads DMN_HandleList stuck_threads = {0}; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + for(CTRL_Entity *machine = entity_ctx->root->first; machine != &ctrl_entity_nil; machine = machine->next) { @@ -4924,7 +5597,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: gather frozen threads // CTRL_EntityList frozen_threads = {0}; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + for(CTRL_Entity *machine = entity_ctx->root->first; machine != &ctrl_entity_nil; machine = machine->next) { @@ -5053,39 +5726,73 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) }break; case DMN_EventKind_CreateProcess: { - DMN_TrapChunkList new_traps = {0}; - ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, ctrl_handle_make(CTRL_MachineID_Local, event->process), &msg->user_bps, &new_traps); - log_infof("step_rule: create_process -> resolve traps\n"); - log_infof("new_traps:\n{\n"); - for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, &ctrl_entity_nil); { - for(U64 idx = 0; idx < n->count; idx += 1) + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), &msg->user_bps, &new_traps); + log_infof("step_rule: create_process -> resolve traps\n"); + log_infof("new_traps:\n{\n"); + for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) { - DMN_Trap *trap = &n->v[idx]; - log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + for(U64 idx = 0; idx < n->count; idx += 1) + { + DMN_Trap *trap = &n->v[idx]; + log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + } } + log_infof("}\n\n"); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); } - log_infof("}\n\n"); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + ctrl_thread__eval_scope_end(eval_scope); }break; case DMN_EventKind_LoadModule: { - DMN_TrapChunkList new_traps = {0}; - ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, ctrl_handle_make(CTRL_MachineID_Local, event->process), ctrl_handle_make(CTRL_MachineID_Local, event->module), &msg->user_bps, &new_traps); - log_infof("step_rule: load_module -> resolve traps\n"); - log_infof("new_traps:\n{\n"); - for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->thread)); + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(scratch.arena, thread); { - for(U64 idx = 0; idx < n->count; idx += 1) + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, eval_scope, ctrl_handle_make(CTRL_MachineID_Local, event->process), ctrl_handle_make(CTRL_MachineID_Local, event->module), &msg->user_bps, &new_traps); + log_infof("step_rule: load_module -> resolve traps\n"); + log_infof("new_traps:\n{\n"); + for(DMN_TrapChunkNode *n = new_traps.first; n != 0; n = n->next) { - DMN_Trap *trap = &n->v[idx]; - log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + for(U64 idx = 0; idx < n->count; idx += 1) + { + DMN_Trap *trap = &n->v[idx]; + log_infof("{process:[0x%I64x], vaddr:0x%I64x}\n", trap->process.u64[0], trap->vaddr); + } + } + log_infof("}\n\n"); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + } + ctrl_thread__eval_scope_end(eval_scope); + }break; + case DMN_EventKind_SetBreakpoint: + { + CTRL_Entity *bp = &ctrl_entity_nil; + { + CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process)); + for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == CTRL_EntityKind_Breakpoint && + child->vaddr_range.min == event->address && + child->vaddr_range.max == event->address + event->size && + child->bp_flags == ctrl_user_breakpoint_flags_from_dmn_trap_flags(event->flags)) + { + bp = child; + break; + } } } - log_infof("}\n\n"); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + if(bp != &ctrl_entity_nil) + { + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_program_defined_bp_traps(scratch.arena, bp, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + } }break; } @@ -5098,16 +5805,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) DI_Scope *di_scope = di_scope_open(); //- rjf: unpack process/module info - CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->process)); - CTRL_Entity *module = &ctrl_entity_nil; - for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) - { - if(child->kind == CTRL_EntityKind_Module) - { - module = child; - break; - } - } + CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process)); + CTRL_Entity *module = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Module); U64 module_base_vaddr = module->vaddr_range.min; CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; @@ -5144,10 +5843,45 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } } + //- rjf: add traps for module-baked entry points, if specified + if(!entries_found) + { + String8 raddbg_data = ctrl_raddbg_data_from_module(scratch.arena, module->handle); + U8 split_char = 0; + String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0); + for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next) + { + String8 text = text_n->string; + MD_Node *root = md_tree_from_string(scratch.arena, text); + if(str8_match(root->first->string, str8_lit("entry_point"), 0)) + { + String8 name = root->first->first->string; + U32 procedure_id = 0; + { + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, name.str, name.size); + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + if(id_count > 0) + { + procedure_id = ids[0]; + } + } + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, procedure_id); + U64 voff = rdi_first_voff_from_procedure(rdi, procedure); + if(voff != 0) + { + entries_found = 1; + DMN_Trap trap = {process->handle.dmn_handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + } + } + } + } + //- rjf: add traps for PID-correllated entry points if(!entries_found) { - for(CTRL_Entity *e = ctrl_state->ctrl_thread_entity_store->root->first; e != &ctrl_entity_nil; e = e->next) + for(CTRL_Entity *e = entity_ctx->root->first; e != &ctrl_entity_nil; e = e->next) { if(e->id == process->id) { @@ -5295,8 +6029,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ////////////////////////// //- rjf: unpack info about thread attached to event // - CTRL_Entity *thread = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->thread)); - CTRL_Entity *process = ctrl_entity_from_handle(ctrl_state->ctrl_thread_entity_store, ctrl_handle_make(CTRL_MachineID_Local, event->process)); + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->thread)); + CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process)); Arch arch = thread->arch; U64 thread_rip_vaddr = dmn_rip_from_thread(event->thread); CTRL_Entity *module = &ctrl_entity_nil; @@ -5383,21 +6117,27 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } // rjf: user breakpoints - for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) { - DMN_Trap *trap = n->v; - DMN_Trap *opl = n->v + n->count; - for(;trap < opl; trap += 1) + if(event->user_data != 0) { - if(dmn_handle_match(trap->process, event->process) && - trap->vaddr == event->instruction_pointer && - (!dmn_handle_match(event->thread, target_thread.dmn_handle) || !target_thread_is_on_user_bp_and_trap_net_trap)) + hit_user_bp = 1; + } + for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + { + DMN_Trap *trap = n->v; + DMN_Trap *opl = n->v + n->count; + for(;trap < opl; trap += 1) { - CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)trap->id; - hit_user_bp = 1; - if(user_bp != 0 && user_bp->condition.size != 0) + if(dmn_handle_match(trap->process, event->process) && + trap->vaddr == event->instruction_pointer && + (!dmn_handle_match(event->thread, target_thread.dmn_handle) || !target_thread_is_on_user_bp_and_trap_net_trap)) { - str8_list_push(temp.arena, &conditions, user_bp->condition); + CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)trap->id; + hit_user_bp = 1; + if(user_bp != 0 && !(trap->id & bit64) && user_bp->condition.size != 0) + { + str8_list_push(temp.arena, &conditions, user_bp->condition); + } } } } @@ -5406,122 +6146,14 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) ProfScope("evaluate hit stop conditions") { - DI_Scope *di_scope = di_scope_open(); - - // rjf: gather evaluation modules - U64 eval_modules_count = Max(1, ctrl_state->ctrl_thread_entity_store->entity_kind_counts[CTRL_EntityKind_Module]); - E_Module *eval_modules = push_array(temp.arena, E_Module, eval_modules_count); - E_Module *eval_modules_primary = &eval_modules[0]; - eval_modules_primary->rdi = &di_rdi_parsed_nil; - eval_modules_primary->vaddr_range = r1u64(0, max_U64); - { - U64 eval_module_idx = 0; - for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; - machine != &ctrl_entity_nil; - machine = machine->next) - { - if(machine->kind != CTRL_EntityKind_Machine) { continue; } - for(CTRL_Entity *process = machine->first; - process != &ctrl_entity_nil; - process = process->next) - { - if(process->kind != CTRL_EntityKind_Process) { continue; } - for(CTRL_Entity *mod = process->first; - mod != &ctrl_entity_nil; - mod = mod->next) - { - if(mod->kind != CTRL_EntityKind_Module) { continue; } - CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath); - DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; - eval_modules[eval_module_idx].arch = arch; - eval_modules[eval_module_idx].rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); - eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range; - eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity); - eval_modules[eval_module_idx].space.u64_0 = (U64)process; - if(mod == module) - { - eval_modules_primary = &eval_modules[eval_module_idx]; - } - eval_module_idx += 1; - } - } - } - } - - // rjf: loop through all conditions, check all + CTRL_EvalScope *eval_scope = ctrl_thread__eval_scope_begin(temp.arena, thread); for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { - // rjf: build eval type context - E_TypeCtx type_ctx = zero_struct; - { - E_TypeCtx *ctx = &type_ctx; - ctx->ip_vaddr = thread_rip_vaddr; - ctx->ip_voff = thread_rip_voff; - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - } - e_select_type_ctx(&type_ctx); - - // rjf: build eval parse context - E_ParseCtx parse_ctx = zero_struct; - ProfScope("build eval parse context") - { - E_ParseCtx *ctx = &parse_ctx; - ctx->ip_vaddr = thread_rip_vaddr; - ctx->ip_voff = thread_rip_voff; - ctx->ip_thread_space = e_space_make(CTRL_EvalSpaceKind_Entity); - ctx->ip_thread_space.u64_0 = (U64)thread; - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - ctx->regs_map = ctrl_string2reg_from_arch(arch); - ctx->reg_alias_map = ctrl_string2alias_from_arch(arch); - ctx->locals_map = e_push_locals_map_from_rdi_voff(temp.arena, eval_modules_primary->rdi, thread_rip_voff); - ctx->member_map = e_push_member_map_from_rdi_voff(temp.arena, eval_modules_primary->rdi, thread_rip_voff); - } - e_select_parse_ctx(&parse_ctx); - - // rjf: build eval IR context - E_IRCtx ir_ctx = zero_struct; - { - E_IRCtx *ctx = &ir_ctx; - ctx->macro_map = push_array(temp.arena, E_String2ExprMap, 1); - ctx->macro_map[0] = e_string2expr_map_make(temp.arena, 512); - E_TypeKey meval_type_key = e_type_key_cons_base(type(CTRL_MetaEval)); - for EachIndex(idx, ctrl_state->user_meta_evals.count) - { - E_Space space = e_space_make(CTRL_EvalSpaceKind_Meta); - E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); - expr->space = space; - expr->mode = E_Mode_Offset; - expr->type_key = meval_type_key; - e_string2expr_map_insert(temp.arena, ctx->macro_map, ctrl_state->user_meta_evals.v[idx].label, expr); - } - } - e_select_ir_ctx(&ir_ctx); - - // rjf: build eval interpretation context - E_InterpretCtx interpret_ctx = zero_struct; - { - E_InterpretCtx *ctx = &interpret_ctx; - ctx->space_rw_user_data = ctrl_state->ctrl_thread_entity_store; - ctx->space_read = ctrl_eval_space_read; - ctx->primary_space = eval_modules_primary->space; - ctx->reg_arch = eval_modules_primary->arch; - ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity); - ctx->reg_space.u64_0 = (U64)thread; - ctx->module_base = push_array(temp.arena, U64, 1); - ctx->module_base[0]= module->vaddr_range.min; - ctx->tls_base = push_array(temp.arena, U64, 1); - } - e_select_interpret_ctx(&interpret_ctx); - // rjf: evaluate E_Eval eval = zero_struct; ProfScope("evaluate expression") { - eval = e_eval_from_string(temp.arena, condition_n->string); + eval = e_eval_from_string(condition_n->string); } // rjf: interpret evaluation @@ -5539,7 +6171,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) break; } } - di_scope_close(di_scope); + ctrl_thread__eval_scope_end(eval_scope); } // rjf: gather trap net hits @@ -5847,8 +6479,17 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) event->entity = ctrl_handle_make(CTRL_MachineID_Local, stop_event->thread); event->parent = ctrl_handle_make(CTRL_MachineID_Local, stop_event->process); event->exception_code = stop_event->code; + event->exception_kind = ctrl_exception_kind_from_dmn(stop_event->exception_kind); event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; + if(stop_cause == CTRL_EventCause_UserBreakpoint && stop_event->user_data != 0) + { + if(!(stop_event->user_data & bit64)) + { + CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)stop_event->user_data; + event->u64_code = user_bp->id; + } + } ctrl_c2u_push_events(&evts); } @@ -5921,6 +6562,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) event->entity = ctrl_handle_make(CTRL_MachineID_Local, stop_event->thread); event->parent = ctrl_handle_make(CTRL_MachineID_Local, stop_event->process); event->exception_code = stop_event->code; + event->exception_kind = ctrl_exception_kind_from_dmn(stop_event->exception_kind); event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; } @@ -5932,21 +6574,22 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } //////////////////////////////// -//~ rjf: Memory-Stream-Thread-Only Functions +//~ rjf: Asynchronous Memory Streaming Functions //- rjf: user -> memory stream communication internal B32 -ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) +ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us) { B32 good = 0; OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; U64 available_size = ctrl_state->u2ms_ring_size-unconsumed_size; - if(available_size >= sizeof(process)+sizeof(vaddr_range)+sizeof(zero_terminated)) + if(available_size >= sizeof(key)+sizeof(process)+sizeof(vaddr_range)+sizeof(zero_terminated)) { good = 1; + ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &key); ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &process); ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &vaddr_range); ctrl_state->u2ms_ring_write_pos += ring_write_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_write_pos, &zero_terminated); @@ -5960,13 +6603,14 @@ ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_termina } internal void -ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) +ctrl_u2ms_dequeue_req(HS_Key *out_key, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated) { OS_MutexScope(ctrl_state->u2ms_ring_mutex) for(;;) { U64 unconsumed_size = ctrl_state->u2ms_ring_write_pos-ctrl_state->u2ms_ring_read_pos; - if(unconsumed_size >= sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated)) + if(unconsumed_size >= sizeof(*out_key)+sizeof(*out_process)+sizeof(*out_vaddr_range)+sizeof(*out_zero_terminated)) { + ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_key); ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_process); ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_vaddr_range); ctrl_state->u2ms_ring_read_pos += ring_read_struct(ctrl_state->u2ms_ring_base, ctrl_state->u2ms_ring_size, ctrl_state->u2ms_ring_read_pos, out_zero_terminated); @@ -5983,51 +6627,31 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) { ProfBeginFunction(); CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + //- rjf: unpack next request + HS_Key key = {0}; 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); + ctrl_u2ms_dequeue_req(&key, &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)); + //- rjf: unpack process key + U64 process_hash = ctrl_hash_from_handle(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)); + U64 range_hash = hs_little_hash_from_data(str8_struct(&key.id)); - //- 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: clamp vaddr range + Rng1U64 vaddr_range_clamped = vaddr_range; { - 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) - { - 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:; + vaddr_range_clamped.max = Max(vaddr_range_clamped.max, vaddr_range_clamped.min); + U64 max_size_cap = Min(max_U64-vaddr_range_clamped.min, GB(1)); + vaddr_range_clamped.max = Min(vaddr_range_clamped.max, vaddr_range_clamped.min+max_size_cap); } //- rjf: task was taken -> read memory @@ -6035,9 +6659,8 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; - U64 pre_read_mem_gen = dmn_mem_gen(); + U64 pre_read_mem_gen = ctrl_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; @@ -6102,7 +6725,7 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) //- rjf: read successful -> submit to hash store U128 hash = {0}; - if(got_task && range_base != 0 && pre_read_mem_gen == post_read_mem_gen) + if(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)); } @@ -6111,8 +6734,8 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) arena_release(range_arena); } - //- rjf: commit hash to cache - if(got_task) OS_MutexScopeW(process_stripe->rw_mutex) + //- rjf: commit new info to cache + OS_MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { @@ -6122,14 +6745,12 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) 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(hs_id_match(range_n->id, key.id)) { 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; } } @@ -6144,3 +6765,247 @@ ASYNC_WORK_DEF(ctrl_mem_stream_work) ProfEnd(); return 0; } + +//////////////////////////////// +//~ rjf: Asynchronous Unwinding Functions + +//- rjf: user -> memory stream communication + +internal B32 +ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us) +{ + B32 good = 0; + OS_MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; + U64 available_size = ctrl_state->u2csb_ring_size - unconsumed_size; + if(available_size >= sizeof(thread)) + { + good = 1; + ctrl_state->u2csb_ring_write_pos += ring_write_struct(ctrl_state->u2csb_ring_base, ctrl_state->u2csb_ring_size, ctrl_state->u2csb_ring_write_pos, &thread); + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(ctrl_state->u2csb_ring_cv); + } + return good; +} + +internal void +ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread) +{ + OS_MutexScope(ctrl_state->u2csb_ring_mutex) for(;;) + { + U64 unconsumed_size = ctrl_state->u2csb_ring_write_pos - ctrl_state->u2csb_ring_read_pos; + if(unconsumed_size >= sizeof(*out_thread)) + { + ctrl_state->u2csb_ring_read_pos += ring_read_struct(ctrl_state->u2csb_ring_base, ctrl_state->u2csb_ring_size, ctrl_state->u2csb_ring_read_pos, out_thread); + break; + } + os_condition_variable_wait(ctrl_state->u2csb_ring_cv, ctrl_state->u2csb_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ctrl_state->u2csb_ring_cv); +} + +//- rjf: entry point + +ASYNC_WORK_DEF(ctrl_call_stack_build_work) +{ + Temp scratch = scratch_begin(0, 0); + CTRL_CallStackCache *cache = &ctrl_state->call_stack_cache; + + //- rjf: get next request & unpack + CTRL_Handle thread_handle = {0}; + ctrl_u2csb_dequeue_req(&thread_handle); + U64 hash = ctrl_hash_from_handle(thread_handle); + U64 slot_idx = hash%cache->slots_count; + U64 stripe_idx = hash%cache->stripes_count; + CTRL_CallStackCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_CallStackCacheStripe *stripe = &cache->stripes[stripe_idx]; + + //- rjf: produce mini entity context for just this process + CTRL_EntityCtx *entity_ctx = push_array(scratch.arena, CTRL_EntityCtx, 1); + OS_MutexScopeR(ctrl_state->ctrl_thread_entity_ctx_rw_mutex) + { + CTRL_EntityCtx *src_ctx = &ctrl_state->ctrl_thread_entity_store->ctx; + CTRL_EntityCtx *dst_ctx = entity_ctx; + { + dst_ctx->root = &ctrl_entity_nil; + dst_ctx->hash_slots_count = 1024; + dst_ctx->hash_slots = push_array(scratch.arena, CTRL_EntityHashSlot, dst_ctx->hash_slots_count); + MemoryCopyArray(dst_ctx->entity_kind_counts, src_ctx->entity_kind_counts); + MemoryCopyArray(dst_ctx->entity_kind_alloc_gens, src_ctx->entity_kind_alloc_gens); + } + CTRL_Entity *src_thread = ctrl_entity_from_handle(src_ctx, thread_handle); + CTRL_Entity *src_process = ctrl_process_from_entity(src_thread); + { + CTRL_EntityRec rec = {0}; + CTRL_Entity *dst_parent = &ctrl_entity_nil; + for(CTRL_Entity *src_e = src_process; src_e != &ctrl_entity_nil; src_e = rec.next) + { + rec = ctrl_entity_rec_depth_first_pre(src_e, src_process); + + // rjf: copy this entity + CTRL_Entity *dst_e = push_array(scratch.arena, CTRL_Entity, 1); + { + dst_e->first = dst_e->last = dst_e->next = dst_e->prev = &ctrl_entity_nil; + dst_e->parent = dst_parent; + dst_e->kind = src_e->kind; + dst_e->arch = src_e->arch; + dst_e->is_frozen = src_e->is_frozen; + dst_e->is_soloed = src_e->is_soloed; + dst_e->rgba = src_e->rgba; + dst_e->handle = src_e->handle; + dst_e->id = src_e->id; + dst_e->vaddr_range = src_e->vaddr_range; + dst_e->stack_base = src_e->stack_base; + dst_e->timestamp = src_e->timestamp; + dst_e->bp_flags = src_e->bp_flags; + dst_e->string = push_str8_copy(scratch.arena, src_e->string); + } + if(dst_parent == &ctrl_entity_nil) + { + dst_ctx->root = dst_e; + } + else + { + DLLPushBack_NPZ(&ctrl_entity_nil, dst_parent->first, dst_parent->last, dst_e, next, prev); + } + + // rjf: insert into hash map + { + U64 hash = ctrl_hash_from_handle(dst_e->handle); + U64 slot_idx = hash%dst_ctx->hash_slots_count; + CTRL_EntityHashSlot *slot = &dst_ctx->hash_slots[slot_idx]; + CTRL_EntityHashNode *node = 0; + for(CTRL_EntityHashNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->entity->handle, dst_e->handle)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(scratch.arena, CTRL_EntityHashNode, 1); + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->entity = dst_e; + } + } + + // rjf: push/pop + if(rec.push_count) + { + dst_parent = dst_e; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_parent = dst_parent->parent; + } + } + } + } + + //- rjf: do task + { + CTRL_Entity *thread = ctrl_entity_from_handle(entity_ctx, thread_handle); + CTRL_Entity *process = ctrl_process_from_entity(thread); + + //- rjf: compute unwind to find list of all concrete frames, then + // call stack, to determine list of all concrete & inline frames + Arena *arena = arena_alloc(); + U64 pre_reg_gen = 0; + U64 post_reg_gen = 0; + U64 pre_mem_gen = 0; + U64 post_mem_gen = 0; + CTRL_Unwind unwind = {0}; + CTRL_CallStack call_stack = {0}; + { + pre_reg_gen = ctrl_reg_gen(); + pre_mem_gen = ctrl_mem_gen(); + unwind = ctrl_unwind_from_thread(arena, entity_ctx, thread_handle, os_now_microseconds()+5000); + call_stack = ctrl_call_stack_from_unwind(arena, process, &unwind); + post_reg_gen = ctrl_reg_gen(); + post_mem_gen = ctrl_mem_gen(); + } + + //- rjf: store new results in cache + Arena *last_arena = arena; + if(pre_reg_gen == post_reg_gen && + pre_mem_gen == post_mem_gen) + { + B32 found = 0; + B32 committed = 0; + OS_MutexScopeW(stripe->rw_mutex) for(;;) + { + // rjf: try to find node & commit + for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->thread, thread_handle)) + { + found = 1; + if(n->scope_touch_count == 0) + { + committed = 1; + if(unwind.flags == 0 || call_stack.frames_count >= n->call_stack.frames_count) + { + last_arena = n->arena; + n->arena = arena; + n->call_stack = call_stack; + } + if(unwind.flags == 0) + { + n->reg_gen = pre_reg_gen; + n->mem_gen = pre_mem_gen; + } + } + break; + } + } + + // rjf: not found, or committed? -> abort + if(!found || committed) + { + break; + } + + // rjf: found, not committed? -> wait & retry + if(found && !committed) + { + os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+10); + } + } + } + + //- rjf: release last results + if(last_arena != 0) + { + arena_release(last_arena); + } + + //- rjf: mark work as done + OS_MutexScopeW(stripe->rw_mutex) for(CTRL_CallStackCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ctrl_handle_match(n->thread, thread_handle)) + { + ins_atomic_u64_dec_eval(&n->working_count); + break; + } + } + + //- rjf: broadcast update + os_condition_variable_broadcast(stripe->cv); + } + + scratch_end(scratch); + return 0; +} diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 3540e87f..1eb83b5e 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -13,227 +13,51 @@ typedef U64 CTRL_MachineID; #define CTRL_MachineID_Local (1) //////////////////////////////// -//~ rjf: Meta Evaluation Types +//~ rjf: User Breakpoint Types -//- rjf: auto-checkbox b32s - -typedef struct CTRL_CheckB32 CTRL_CheckB32; -struct CTRL_CheckB32 +typedef U32 CTRL_UserBreakpointFlags; +enum { - B32 b32; + CTRL_UserBreakpointFlag_BreakOnWrite = (1<<0), + CTRL_UserBreakpointFlag_BreakOnRead = (1<<1), + CTRL_UserBreakpointFlag_BreakOnExecute = (1<<2), }; -struct_members(CTRL_CheckB32) +typedef enum CTRL_UserBreakpointKind { - member_lit_comp(CTRL_CheckB32, type(B32), b32), -}; -struct_type(CTRL_CheckB32); + CTRL_UserBreakpointKind_Null, + CTRL_UserBreakpointKind_FileNameAndLineColNumber, + CTRL_UserBreakpointKind_Expression, + CTRL_UserBreakpointKind_COUNT +} +CTRL_UserBreakpointKind; -//- rjf: styled string types - -ptr_type(CTRL_PlainString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPlainText,.count_delimiter_name = str8_lit_comp("size")); -ptr_type(CTRL_CodeString8__str_ptr_type, type(U8), .flags = TypeFlag_IsCodeText, .count_delimiter_name = str8_lit_comp("size")); -ptr_type(CTRL_PathString8__str_ptr_type, type(U8), .flags = TypeFlag_IsPathText, .count_delimiter_name = str8_lit_comp("size")); -Member CTRL_PlainString8__members[] = +typedef struct CTRL_UserBreakpoint CTRL_UserBreakpoint; +struct CTRL_UserBreakpoint { - member_lit_comp(String8, &CTRL_PlainString8__str_ptr_type, str, .pretty_name = str8_lit_comp("Contents")), - member_lit_comp(String8, type(U64), size, .pretty_name = str8_lit_comp("Size")), -}; -Member CTRL_CodeString8__members[] = -{ - member_lit_comp(String8, &CTRL_CodeString8__str_ptr_type, str, .pretty_name = str8_lit_comp("Contents")), - member_lit_comp(String8, type(U64), size, .pretty_name = str8_lit_comp("Size")), -}; -Member CTRL_PathString8__members[] = -{ - member_lit_comp(String8, &CTRL_PathString8__str_ptr_type, str, .pretty_name = str8_lit_comp("Contents")), - member_lit_comp(String8, type(U64), size, .pretty_name = str8_lit_comp("Size")), -}; -named_struct_type(CTRL_PlainString8, String8, .name = str8_lit_comp("string")); -named_struct_type(CTRL_CodeString8, String8, .name = str8_lit_comp("string")); -named_struct_type(CTRL_PathString8, String8, .name = str8_lit_comp("string")); - -//- rjf: meta evaluation callstack types - -typedef struct CTRL_MetaEvalFrame CTRL_MetaEvalFrame; -struct CTRL_MetaEvalFrame -{ - U64 vaddr; - U64 inline_depth; -}; -ptr_type(CTRL_MetaEvalFrame__vaddr_type, type(void), .flags = TypeFlag_IsExternal, .size = sizeof(U64)); -struct_members(CTRL_MetaEvalFrame) -{ - member_lit_comp(CTRL_MetaEvalFrame, &CTRL_MetaEvalFrame__vaddr_type, vaddr), - member_lit_comp(CTRL_MetaEvalFrame, type(U64), inline_depth), -}; -struct_type(CTRL_MetaEvalFrame, .name = str8_lit_comp("callstack_frame")); -typedef struct CTRL_MetaEvalFrameArray CTRL_MetaEvalFrameArray; -struct CTRL_MetaEvalFrameArray -{ - U64 count; - CTRL_MetaEvalFrame *v; -}; -ptr_type(CTRL_MetaEvalFrameArray__v_ptr_type, type(CTRL_MetaEvalFrame), .count_delimiter_name = str8_lit_comp("count")); -struct_members(CTRL_MetaEvalFrameArray) -{ - member_lit_comp(CTRL_MetaEvalFrameArray, type(U64), count, .pretty_name = str8_lit_comp("Frame Count")), - {str8_lit_comp("v"), str8_lit_comp("Frame Addresses"), &CTRL_MetaEvalFrameArray__v_ptr_type, OffsetOf(CTRL_MetaEvalFrameArray, v)}, -}; -struct_type(CTRL_MetaEvalFrameArray, .name = str8_lit_comp("callstack_frames")); - -//- rjf: meta evaluation instance types - -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(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")\ -Y(String8, type(CTRL_PlainString8), args, "Arguments")\ -Y(String8, type(CTRL_PathString8), working_directory, "Working Directory")\ -Y(String8, type(CTRL_CodeString8), entry_point, "Custom Entry Point")\ -Y(String8, type(CTRL_PathString8), stdout_path, "Standard Output Path")\ -Y(String8, type(CTRL_PathString8), stderr_path, "Standard Error Path")\ -Y(String8, type(CTRL_PathString8), stdin_path, "Standard Input Path")\ -Y(String8, type(CTRL_PathString8), source_location, "Source Location")\ -Y(String8, type(CTRL_CodeString8), function_location, "Function Location")\ -Y(String8, type(CTRL_CodeString8), address_location, "Address Location")\ -Y(String8, type(CTRL_PathString8), source_path, "Source Path")\ -Y(String8, type(CTRL_PathString8), destination_path, "Destination Path")\ -Y(String8, type(CTRL_CodeString8), type, "Type")\ -Y(String8, type(CTRL_CodeString8), view_rule, "View Rule")\ -Y(String8, type(CTRL_CodeString8), condition, "Condition")\ -X(CTRL_MetaEvalFrameArray, callstack, "Call Stack") -#define X(T, name, pretty_name) T name; -#define Y(T, ti, name, pretty_name) T name; - CTRL_MetaEval_MemberXList -#undef X -#undef Y -}; -struct_members(CTRL_MetaEval) -{ -#define X(T, name, pretty_name_) member_lit_comp(CTRL_MetaEval, type(T), name, .pretty_name = str8_lit_comp(pretty_name_)), -#define Y(T, ti, name, pretty_name_) member_lit_comp(CTRL_MetaEval, (ti), name, .pretty_name = str8_lit_comp(pretty_name_)), - CTRL_MetaEval_MemberXList -#undef X -#undef Y -}; -struct_type(CTRL_MetaEval); - -//- rjf: filters on main meta evaluation bundle - -struct_members(CTRL_BreakpointMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(B32), enabled, .pretty_name = str8_lit_comp("Enabled")), - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(U64), hit_count, .pretty_name = str8_lit_comp("Hit Count")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Label")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), condition, .pretty_name = str8_lit_comp("Condition")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), source_location, .pretty_name = str8_lit_comp("Source Location")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), function_location, .pretty_name = str8_lit_comp("Function Location")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), address_location, .pretty_name = str8_lit_comp("Address Location")), + CTRL_UserBreakpointKind kind; + CTRL_UserBreakpointFlags flags; + U64 id; + String8 string; + TxtPt pt; + U64 size; + String8 condition; }; -struct_members(CTRL_TargetMetaEval) +typedef struct CTRL_UserBreakpointNode CTRL_UserBreakpointNode; +struct CTRL_UserBreakpointNode { - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Label")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), exe, .pretty_name = str8_lit_comp("Executable")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PlainString8),args, .pretty_name = str8_lit_comp("Arguments")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), working_directory, .pretty_name = str8_lit_comp("Working Directory")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), entry_point, .pretty_name = str8_lit_comp("Custom Entry Point")), - 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")), + CTRL_UserBreakpointNode *next; + CTRL_UserBreakpoint v; }; -struct_members(CTRL_PinMetaEval) +typedef struct CTRL_UserBreakpointList CTRL_UserBreakpointList; +struct CTRL_UserBreakpointList { - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Expression")), - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), source_location, .pretty_name = str8_lit_comp("Source Location")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), address_location, .pretty_name = str8_lit_comp("Address Location")), -}; - -struct_members(CTRL_FilePathMapMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), source_path, .pretty_name = str8_lit_comp("Source Path")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), destination_path, .pretty_name = str8_lit_comp("Destination Path")), -}; - -struct_members(CTRL_AutoViewRuleMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), type, .pretty_name = str8_lit_comp("Type")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), view_rule, .pretty_name = str8_lit_comp("View Rule")), -}; - -struct_members(CTRL_MachineMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(B32), frozen, .pretty_name = str8_lit_comp("Frozen")), - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Name")), -}; - -struct_members(CTRL_ProcessMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(B32), frozen, .pretty_name = str8_lit_comp("Frozen")), - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Name")), - member_lit_comp(CTRL_MetaEval, type(U64), id, .pretty_name = str8_lit_comp("ID")), -}; - -struct_members(CTRL_ModuleMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Name")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), exe, .pretty_name = str8_lit_comp("Executable Path")), - member_lit_comp(CTRL_MetaEval, type(CTRL_PathString8), dbg, .pretty_name = str8_lit_comp("Debug Info Path")), - member_lit_comp(CTRL_MetaEval, type(Rng1U64), vaddr_range, .pretty_name = str8_lit_comp("Address Range")), -}; - -struct_members(CTRL_ThreadMetaEval) -{ - member_lit_comp(CTRL_MetaEval, type(B32), frozen, .pretty_name = str8_lit_comp("Frozen")), - member_lit_comp(CTRL_MetaEval, type(U32), color, .pretty_name = str8_lit_comp("Color")), - member_lit_comp(CTRL_MetaEval, type(CTRL_CodeString8), label, .pretty_name = str8_lit_comp("Name")), - member_lit_comp(CTRL_MetaEval, type(U64), id, .pretty_name = str8_lit_comp("ID")), - member_lit_comp(CTRL_MetaEval, type(CTRL_MetaEvalFrameArray), callstack, .pretty_name = str8_lit_comp("Call Stack")), -}; - -named_struct_type(CTRL_BreakpointMetaEval, CTRL_MetaEval, .name = str8_lit_comp("breakpoint")); -named_struct_type(CTRL_TargetMetaEval, CTRL_MetaEval, .name = str8_lit_comp("target")); -named_struct_type(CTRL_PinMetaEval, CTRL_MetaEval, .name = str8_lit_comp("pin")); -named_struct_type(CTRL_FilePathMapMetaEval, CTRL_MetaEval, .name = str8_lit_comp("file_path_map")); -named_struct_type(CTRL_AutoViewRuleMetaEval,CTRL_MetaEval, .name = str8_lit_comp("auto_view_rule")); -named_struct_type(CTRL_MachineMetaEval, CTRL_MetaEval, .name = str8_lit_comp("machine")); -named_struct_type(CTRL_ProcessMetaEval, CTRL_MetaEval, .name = str8_lit_comp("process")); -named_struct_type(CTRL_ModuleMetaEval, CTRL_MetaEval, .name = str8_lit_comp("module")); -named_struct_type(CTRL_ThreadMetaEval, CTRL_MetaEval, .name = str8_lit_comp("thread")); - -//- rjf: meta evaluation array - -typedef struct CTRL_MetaEvalArray CTRL_MetaEvalArray; -struct CTRL_MetaEvalArray -{ - CTRL_MetaEval *v; + CTRL_UserBreakpointNode *first; + CTRL_UserBreakpointNode *last; U64 count; }; -ptr_type(CTRL_MetaEvalArray__v_ptr_type, type(CTRL_BreakpointMetaEval), .count_delimiter_name = str8_lit_comp("count")); -struct_members(CTRL_MetaEvalArray) -{ - {str8_lit_comp("v"), {0}, &CTRL_MetaEvalArray__v_ptr_type, OffsetOf(CTRL_MetaEvalArray, v)}, - member_lit_comp(CTRL_MetaEvalArray, type(U64), count), -}; -struct_type(CTRL_MetaEvalArray); //////////////////////////////// //~ rjf: Entity Handle Types @@ -279,12 +103,14 @@ struct CTRL_Entity CTRL_EntityKind kind; Arch arch; B32 is_frozen; + B32 is_soloed; U32 rgba; CTRL_Handle handle; U64 id; Rng1U64 vaddr_range; U64 stack_base; U64 timestamp; + CTRL_UserBreakpointFlags bp_flags; String8 string; }; @@ -340,21 +166,45 @@ struct CTRL_EntityStringChunkNode U64 size; }; -typedef struct CTRL_EntityStore CTRL_EntityStore; -struct CTRL_EntityStore +read_only global U64 ctrl_entity_string_bucket_chunk_sizes[] = +{ + 16, + 64, + 256, + 1024, + 4096, + 16384, + 65536, + 0xffffffffffffffffull, +}; + +typedef struct CTRL_EntityCtx CTRL_EntityCtx; +struct CTRL_EntityCtx +{ + CTRL_Entity *root; + U64 hash_slots_count; + CTRL_EntityHashSlot *hash_slots; + U64 entity_kind_counts[CTRL_EntityKind_COUNT]; + U64 entity_kind_alloc_gens[CTRL_EntityKind_COUNT]; +}; + +typedef struct CTRL_EntityCtxRWStore CTRL_EntityCtxRWStore; +struct CTRL_EntityCtxRWStore { Arena *arena; - CTRL_Entity *root; + CTRL_EntityCtx ctx; CTRL_Entity *free; - CTRL_EntityHashSlot *hash_slots; CTRL_EntityHashNode *hash_node_free; - U64 hash_slots_count; - CTRL_EntityStringChunkNode *free_string_chunks[8]; - U64 entity_kind_counts[CTRL_EntityKind_COUNT]; - Arena *entity_kind_lists_arenas[CTRL_EntityKind_COUNT]; - U64 entity_kind_lists_gens[CTRL_EntityKind_COUNT]; - U64 entity_kind_alloc_gens[CTRL_EntityKind_COUNT]; - CTRL_EntityList entity_kind_lists[CTRL_EntityKind_COUNT]; + CTRL_EntityStringChunkNode *free_string_chunks[ArrayCount(ctrl_entity_string_bucket_chunk_sizes)]; +}; + +typedef struct CTRL_EntityCtxLookupAccel CTRL_EntityCtxLookupAccel; +struct CTRL_EntityCtxLookupAccel +{ + Arena *arena; + Arena *entity_kind_arrays_arenas[CTRL_EntityKind_COUNT]; + CTRL_EntityArray entity_kind_arrays[CTRL_EntityKind_COUNT]; + U64 entity_kind_arrays_gens[CTRL_EntityKind_COUNT]; }; //////////////////////////////// @@ -404,32 +254,21 @@ struct CTRL_Unwind //////////////////////////////// //~ rjf: Call Stack Types -typedef struct CTRL_CallStackInlineFrame CTRL_CallStackInlineFrame; -struct CTRL_CallStackInlineFrame -{ - CTRL_CallStackInlineFrame *next; - CTRL_CallStackInlineFrame *prev; - RDI_InlineSite *inline_site; -}; - typedef struct CTRL_CallStackFrame CTRL_CallStackFrame; struct CTRL_CallStackFrame { - CTRL_CallStackInlineFrame *first_inline_frame; - CTRL_CallStackInlineFrame *last_inline_frame; - U64 inline_frame_count; + U64 unwind_count; + U64 inline_depth; void *regs; - RDI_Parsed *rdi; - RDI_Procedure *procedure; }; typedef struct CTRL_CallStack CTRL_CallStack; struct CTRL_CallStack { CTRL_CallStackFrame *frames; - U64 concrete_frame_count; - U64 inline_frame_count; - U64 total_frame_count; + U64 frames_count; + CTRL_CallStackFrame **concrete_frames; + U64 concrete_frames_count; }; //////////////////////////////// @@ -476,44 +315,6 @@ struct CTRL_Spoof U64 new_ip_value; }; -//////////////////////////////// -//~ rjf: User Breakpoint Types - -typedef enum CTRL_UserBreakpointKind -{ - CTRL_UserBreakpointKind_Null, - CTRL_UserBreakpointKind_FileNameAndLineColNumber, - CTRL_UserBreakpointKind_SymbolNameAndOffset, - CTRL_UserBreakpointKind_VirtualAddress, - CTRL_UserBreakpointKind_COUNT -} -CTRL_UserBreakpointKind; - -typedef struct CTRL_UserBreakpoint CTRL_UserBreakpoint; -struct CTRL_UserBreakpoint -{ - CTRL_UserBreakpointKind kind; - String8 string; - TxtPt pt; - U64 u64; - String8 condition; -}; - -typedef struct CTRL_UserBreakpointNode CTRL_UserBreakpointNode; -struct CTRL_UserBreakpointNode -{ - CTRL_UserBreakpointNode *next; - CTRL_UserBreakpoint v; -}; - -typedef struct CTRL_UserBreakpointList CTRL_UserBreakpointList; -struct CTRL_UserBreakpointList -{ - CTRL_UserBreakpointNode *first; - CTRL_UserBreakpointNode *last; - U64 count; -}; - //////////////////////////////// //~ rjf: Evaluation Spaces @@ -573,7 +374,6 @@ struct CTRL_Msg String8 stdin_path; CTRL_TrapList traps; CTRL_UserBreakpointList user_bps; - CTRL_MetaEvalArray meta_evals; }; typedef struct CTRL_MsgNode CTRL_MsgNode; @@ -618,10 +418,12 @@ typedef enum CTRL_EventKind //- rjf: debug info changes CTRL_EventKind_ModuleDebugInfoPathChange, - //- rjf: debug strings / decorations + //- rjf: debug strings / decorations / markup CTRL_EventKind_DebugString, CTRL_EventKind_ThreadName, CTRL_EventKind_ThreadColor, + CTRL_EventKind_SetBreakpoint, + CTRL_EventKind_UnsetBreakpoint, //- rjf: memory CTRL_EventKind_MemReserve, @@ -677,6 +479,7 @@ struct CTRL_Event U64 timestamp; U32 exception_code; U32 rgba; + CTRL_UserBreakpointFlags bp_flags; String8 string; }; @@ -702,13 +505,19 @@ typedef struct CTRL_ProcessMemoryRangeHashNode CTRL_ProcessMemoryRangeHashNode; struct CTRL_ProcessMemoryRangeHashNode { CTRL_ProcessMemoryRangeHashNode *next; + + // rjf: key Rng1U64 vaddr_range; B32 zero_terminated; - Rng1U64 vaddr_range_clamped; - U128 hash; + HS_ID id; + + // rjf: staleness info U64 mem_gen; + + // rjf: metadata + U64 working_count; U64 last_time_requested_us; - B32 is_taken; + U64 last_user_clock_idx_touched; }; typedef struct CTRL_ProcessMemoryRangeHashSlot CTRL_ProcessMemoryRangeHashSlot; @@ -725,6 +534,7 @@ struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode *prev; Arena *arena; CTRL_Handle handle; + HS_Root root; U64 range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; }; @@ -800,6 +610,53 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; +//////////////////////////////// +//~ rjf: Call Stack Cache Types + +typedef struct CTRL_CallStackCacheNode CTRL_CallStackCacheNode; +struct CTRL_CallStackCacheNode +{ + CTRL_CallStackCacheNode *next; + CTRL_CallStackCacheNode *prev; + + // rjf: key + CTRL_Handle thread; + U64 reg_gen; + U64 mem_gen; + + // rjf: counters + U64 scope_touch_count; + U64 working_count; + + // rjf: value + Arena *arena; + CTRL_CallStack call_stack; +}; + +typedef struct CTRL_CallStackCacheSlot CTRL_CallStackCacheSlot; +struct CTRL_CallStackCacheSlot +{ + CTRL_CallStackCacheNode *first; + CTRL_CallStackCacheNode *last; +}; + +typedef struct CTRL_CallStackCacheStripe CTRL_CallStackCacheStripe; +struct CTRL_CallStackCacheStripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +typedef struct CTRL_CallStackCache CTRL_CallStackCache; +struct CTRL_CallStackCache +{ + U64 slots_count; + CTRL_CallStackCacheSlot *slots; + U64 stripes_count; + CTRL_CallStackCacheStripe *stripes; +}; + //////////////////////////////// //~ rjf: Module Image Info Cache Types @@ -815,6 +672,8 @@ struct CTRL_ModuleImageInfoCacheNode U64 entry_point_voff; Rng1U64 tls_vaddr_range; String8 initial_debug_info_path; + Rng1U64 raddbg_section_voff_range; + String8 raddbg_data; }; typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; @@ -857,6 +716,45 @@ struct CTRL_DbgDirNode U64 module_direct_count; }; +//////////////////////////////// +//~ rjf: Control Thread Evaluation Scopes + +typedef struct CTRL_EvalScope CTRL_EvalScope; +struct CTRL_EvalScope +{ + DI_Scope *di_scope; + E_BaseCtx base_ctx; + E_IRCtx ir_ctx; + E_InterpretCtx interpret_ctx; +}; + +//////////////////////////////// +//~ rjf: Control Cache Accessing Scopes + +typedef struct CTRL_ScopeCallStackTouch CTRL_ScopeCallStackTouch; +struct CTRL_ScopeCallStackTouch +{ + CTRL_ScopeCallStackTouch *next; + CTRL_CallStackCacheStripe *stripe; + CTRL_CallStackCacheNode *node; +}; + +typedef struct CTRL_Scope CTRL_Scope; +struct CTRL_Scope +{ + CTRL_Scope *next; + CTRL_ScopeCallStackTouch *first_call_stack_touch; + CTRL_ScopeCallStackTouch *last_call_stack_touch; +}; + +typedef struct CTRL_TCTX CTRL_TCTX; +struct CTRL_TCTX +{ + Arena *arena; + CTRL_Scope *free_scope; + CTRL_ScopeCallStackTouch *free_call_stack_touch; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -879,6 +777,7 @@ struct CTRL_State // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; + CTRL_CallStackCache call_stack_cache; CTRL_ModuleImageInfoCache module_image_info_cache; // rjf: user -> ctrl msg ring buffer @@ -899,18 +798,19 @@ struct CTRL_State OS_Handle c2u_ring_cv; // rjf: ctrl thread state + U64 ctrl_thread_run_state; String8 ctrl_thread_log_path; OS_Handle ctrl_thread; Log *ctrl_thread_log; - CTRL_EntityStore *ctrl_thread_entity_store; + OS_Handle ctrl_thread_entity_ctx_rw_mutex; + CTRL_EntityCtxRWStore *ctrl_thread_entity_store; + E_Cache *ctrl_thread_eval_cache; Arena *dmn_event_arena; DMN_EventNode *first_dmn_event_node; DMN_EventNode *last_dmn_event_node; DMN_EventNode *free_dmn_event_node; Arena *user_entry_point_arena; String8List user_entry_points; - Arena *user_meta_eval_arena; - CTRL_MetaEvalArray user_meta_evals; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; U64 process_counter; Arena *dbg_dir_arena; @@ -923,6 +823,14 @@ struct CTRL_State U64 u2ms_ring_read_pos; OS_Handle u2ms_ring_mutex; OS_Handle u2ms_ring_cv; + + // rjf: user -> call stack builder ring buffer + U64 u2csb_ring_size; + U8 *u2csb_ring_base; + U64 u2csb_ring_write_pos; + U64 u2csb_ring_read_pos; + OS_Handle u2csb_ring_mutex; + OS_Handle u2csb_ring_cv; }; //////////////////////////////// @@ -937,6 +845,8 @@ read_only global CTRL_Entity ctrl_entity_nil = &ctrl_entity_nil, &ctrl_entity_nil, }; +thread_static CTRL_TCTX *ctrl_tctx = 0; +thread_static CTRL_EntityCtxLookupAccel *ctrl_entity_ctx_lookup_accel = 0; //////////////////////////////// //~ rjf: Logging Markup @@ -949,8 +859,12 @@ read_only global CTRL_Entity ctrl_entity_nil = internal U64 ctrl_hash_from_string(String8 string); internal U64 ctrl_hash_from_handle(CTRL_Handle handle); internal CTRL_EventCause ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind); +internal CTRL_ExceptionKind ctrl_exception_kind_from_dmn(DMN_ExceptionKind kind); internal String8 ctrl_string_from_event_kind(CTRL_EventKind kind); internal String8 ctrl_string_from_msg_kind(CTRL_MsgKind kind); +internal CTRL_EntityKind ctrl_entity_kind_from_string(String8 string); +internal DMN_TrapFlags ctrl_dmn_trap_flags_from_user_breakpoint_flags(CTRL_UserBreakpointFlags flags); +internal CTRL_UserBreakpointFlags ctrl_user_breakpoint_flags_from_dmn_trap_flags(DMN_TrapFlags flags); //////////////////////////////// //~ rjf: Handle Type Functions @@ -960,6 +874,8 @@ internal CTRL_Handle ctrl_handle_make(CTRL_MachineID machine_id, DMN_Handle dmn_ internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b); internal void ctrl_handle_list_push(Arena *arena, CTRL_HandleList *list, CTRL_Handle *pair); internal CTRL_HandleList ctrl_handle_list_copy(Arena *arena, CTRL_HandleList *src); +internal String8 ctrl_string_from_handle(Arena *arena, CTRL_Handle handle); +internal CTRL_Handle ctrl_handle_from_string(String8 string); //////////////////////////////// //~ rjf: Trap Type Functions @@ -1004,38 +920,21 @@ internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 stri //- rjf: entity list data structures internal void ctrl_entity_list_push(Arena *arena, CTRL_EntityList *list, CTRL_Entity *entity); -internal CTRL_EntityList ctrl_entity_list_from_handle_list(Arena *arena, CTRL_EntityStore *store, CTRL_HandleList *list); +internal CTRL_EntityList ctrl_entity_list_from_handle_list(Arena *arena, CTRL_EntityCtx *ctx, CTRL_HandleList *list); #define ctrl_entity_list_first(list) ((list)->first ? (list)->first->v : &ctrl_entity_nil) //- rjf: entity array data structure internal CTRL_EntityArray ctrl_entity_array_from_list(Arena *arena, CTRL_EntityList *list); +#define ctrl_entity_array_first(array) ((array)->count != 0 ? (array)->v[0] : &ctrl_entity_nil) -//- rjf: cache creation/destruction -internal CTRL_EntityStore *ctrl_entity_store_alloc(void); -internal void ctrl_entity_store_release(CTRL_EntityStore *store); - -//- rjf: string allocation/deletion -internal U64 ctrl_name_bucket_idx_from_string_size(U64 size); -internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string); -internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string); - -//- rjf: entity construction/deletion -internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Arch arch, CTRL_Handle handle, U64 id); -internal void ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity); - -//- rjf: entity equipment -internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string); - -//- rjf: entity store lookups -internal CTRL_Entity *ctrl_entity_from_handle(CTRL_EntityStore *store, CTRL_Handle handle); +//- rjf: entity context (entity group read-only) functions +internal CTRL_Entity *ctrl_entity_from_handle(CTRL_EntityCtx *ctx, CTRL_Handle handle); internal CTRL_Entity *ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_EntityKind kind); internal CTRL_Entity *ctrl_entity_ancestor_from_kind(CTRL_Entity *entity, CTRL_EntityKind kind); internal CTRL_Entity *ctrl_process_from_entity(CTRL_Entity *entity); internal CTRL_Entity *ctrl_module_from_process_vaddr(CTRL_Entity *process, U64 vaddr); internal DI_Key ctrl_dbgi_key_from_module(CTRL_Entity *module); -internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityStore *store, DI_Key *dbgi_key); -internal CTRL_Entity *ctrl_module_from_thread_candidates(CTRL_EntityStore *store, CTRL_Entity *thread, CTRL_EntityList *candidates); -internal CTRL_EntityList ctrl_entity_list_from_kind(CTRL_EntityStore *store, CTRL_EntityKind kind); +internal CTRL_Entity *ctrl_module_from_thread_candidates(CTRL_EntityCtx *ctx, CTRL_Entity *thread, CTRL_EntityList *candidates); internal U64 ctrl_vaddr_from_voff(CTRL_Entity *module, U64 voff); internal U64 ctrl_voff_from_vaddr(CTRL_Entity *module, U64 vaddr); internal Rng1U64 ctrl_vaddr_range_from_voff_range(CTRL_Entity *module, Rng1U64 voff_range); @@ -1047,8 +946,37 @@ internal CTRL_EntityRec ctrl_entity_rec_depth_first(CTRL_Entity *entity, CTRL_En #define ctrl_entity_rec_depth_first_pre(entity, subtree_root) ctrl_entity_rec_depth_first((entity), (subtree_root), OffsetOf(CTRL_Entity, next), OffsetOf(CTRL_Entity, first)) #define ctrl_entity_rec_depth_first_post(entity, subtree_root) ctrl_entity_rec_depth_first((entity), (subtree_root), OffsetOf(CTRL_Entity, prev), OffsetOf(CTRL_Entity, last)) +//- rjf: entity ctx r/w store state functions +internal CTRL_EntityCtxRWStore *ctrl_entity_ctx_rw_store_alloc(void); +internal void ctrl_entity_ctx_rw_store_release(CTRL_EntityCtxRWStore *store); + +//- rjf: string allocation/deletion +internal U64 ctrl_name_bucket_num_from_string_size(U64 size); +internal String8 ctrl_entity_string_alloc(CTRL_EntityCtxRWStore *store, String8 string); +internal void ctrl_entity_string_release(CTRL_EntityCtxRWStore *store, String8 string); + +//- rjf: entity construction/deletion +internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityCtxRWStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Arch arch, CTRL_Handle handle, U64 id); +internal void ctrl_entity_release(CTRL_EntityCtxRWStore *store, CTRL_Entity *entity); + +//- rjf: entity equipment +internal void ctrl_entity_equip_string(CTRL_EntityCtxRWStore *store, CTRL_Entity *entity, String8 string); + +//- rjf: accelerated entity context lookups +internal CTRL_EntityCtxLookupAccel *ctrl_thread_entity_ctx_lookup_accel(void); +internal CTRL_EntityArray ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind); +internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key); +internal CTRL_Entity *ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id); + //- rjf: applying events to entity caches -internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list); +internal void ctrl_entity_store_apply_events(CTRL_EntityCtxRWStore *store, CTRL_EventList *list); + +//////////////////////////////// +//~ rjf: Cache Accessing Scopes + +internal CTRL_Scope *ctrl_scope_open(void); +internal void ctrl_scope_close(CTRL_Scope *scope); +internal void ctrl_scope_touch_call_stack_node__stripe_r_guarded(CTRL_Scope *scope, CTRL_CallStackCacheStripe *stripe, CTRL_CallStackCacheNode *node); //////////////////////////////// //~ rjf: Main Layer Initialization @@ -1063,18 +991,13 @@ internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); //////////////////////////////// //~ rjf: Process Memory Functions -//- rjf: process memory cache interaction -internal U128 ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated); -internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us); - -//- rjf: bundled key/stream helper -internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 range, B32 zero_terminated); +//- rjf: process memory cache key reading +internal HS_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale); //- rjf: process memory cache reading helpers -internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); -internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us); -internal B32 ctrl_read_cached_process_memory(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); -#define ctrl_read_cached_process_memory_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_read_cached_process_memory((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) +internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us); +internal B32 ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); +#define ctrl_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) //- rjf: process memory writing internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); @@ -1083,10 +1006,10 @@ internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src); //~ rjf: Thread Register Functions //- rjf: thread register cache reading -internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle handle); -internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_Handle handle); -internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_Handle handle); -internal U64 ctrl_query_cached_rsp_from_thread(CTRL_EntityStore *store, CTRL_Handle handle); +internal void *ctrl_reg_block_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle handle); +internal U64 ctrl_tls_root_vaddr_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle); +internal U64 ctrl_rip_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle); +internal U64 ctrl_rsp_from_thread(CTRL_EntityCtx *ctx, CTRL_Handle handle); //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_Handle thread, void *block); @@ -1099,6 +1022,7 @@ internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_Han internal U64 ctrl_entry_point_voff_from_module(CTRL_Handle module_handle); internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_Handle module_handle); internal String8 ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_Handle module_handle); +internal String8 ctrl_raddbg_data_from_module(Arena *arena, CTRL_Handle module_handle); //////////////////////////////// //~ rjf: Unwinding Functions @@ -1108,18 +1032,24 @@ internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Arch arch, CTRL_Unwind //- rjf: [x64] internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); -internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_Handle process_handle, CTRL_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_Handle process_handle, CTRL_Handle module_handle, U64 module_base_vaddr, REGS_RegBlockX64 *regs, U64 endt_us); //- rjf: abstracted unwind step -internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_Handle process, CTRL_Handle module, Arch arch, void *reg_block, U64 endt_us); +internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_Handle process, CTRL_Handle module, U64 module_base_vaddr, Arch arch, void *reg_block, U64 endt_us); //- rjf: abstracted full unwind -internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_Handle thread, U64 endt_us); +internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityCtx *ctx, CTRL_Handle thread, U64 endt_us); //////////////////////////////// //~ rjf: Call Stack Building Functions -internal CTRL_CallStack ctrl_call_stack_from_unwind(Arena *arena, DI_Scope *di_scope, CTRL_Entity *process, CTRL_Unwind *base_unwind); +internal CTRL_CallStack ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *base_unwind); +internal CTRL_CallStackFrame *ctrl_call_stack_frame_from_unwind_and_inline_depth(CTRL_CallStack *call_stack, U64 unwind_count, U64 inline_depth); + +//////////////////////////////// +//~ rjf: Call Stack Cache Functions + +internal CTRL_CallStack ctrl_call_stack_from_thread(CTRL_Scope *scope, CTRL_EntityCtx *entity_ctx, CTRL_Entity *thread, B32 high_priority, U64 endt_us); //////////////////////////////// //~ rjf: Halting All Attached Processes @@ -1153,12 +1083,13 @@ internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); internal void ctrl_thread__entry_point(void *p); //- rjf: breakpoint resolution -internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); -internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_EvalScope *eval_scope, CTRL_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_program_defined_bp_traps(Arena *arena, CTRL_Entity *bp, DMN_TrapChunkList *traps_out); //- rjf: module lifetime open/close work internal void ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_range, String8 path); -internal void ctrl_thread__module_close(CTRL_Handle module); +internal void ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_range); //- rjf: attached process running/event gathering internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); @@ -1166,6 +1097,10 @@ internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ //- rjf: eval helpers internal B32 ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 vaddr_range); +//- rjf: control thread eval scopes +internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_Entity *thread); +internal void ctrl_thread__eval_scope_end(CTRL_EvalScope *scope); + //- rjf: log flusher internal void ctrl_thread__flush_info_log(String8 string); internal void ctrl_thread__end_and_flush_info_log(void); @@ -1180,14 +1115,23 @@ 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); //////////////////////////////// -//~ rjf: Memory-Stream Thread Functions +//~ rjf: Asynchronous Memory Streaming Functions //- rjf: user -> memory stream communication -internal B32 ctrl_u2ms_enqueue_req(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); -internal void ctrl_u2ms_dequeue_req(CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); +internal B32 ctrl_u2ms_enqueue_req(HS_Key key, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); +internal void ctrl_u2ms_dequeue_req(HS_Key *out_key, 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); + +//////////////////////////////// +//~ rjf: Asynchronous Call Stack Building Functions + +//- rjf: user -> memory stream communication +internal B32 ctrl_u2csb_enqueue_req(CTRL_Handle thread, U64 endt_us); +internal void ctrl_u2csb_dequeue_req(CTRL_Handle *out_thread); + +//- rjf: entry point +ASYNC_WORK_DEF(ctrl_call_stack_build_work); #endif // CTRL_CORE_H diff --git a/src/ctrl/ctrl_inc.c b/src/ctrl/ctrl_inc.c index ce59e6dc..d2dcdb61 100644 --- a/src/ctrl/ctrl_inc.c +++ b/src/ctrl/ctrl_inc.c @@ -1,4 +1,7 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0x969696ff + #include "ctrl_core.c" diff --git a/src/ctrl/generated/ctrl.meta.c b/src/ctrl/generated/ctrl.meta.c index 019fde09..c7d5dd88 100644 --- a/src/ctrl/generated/ctrl.meta.c +++ b/src/ctrl/generated/ctrl.meta.c @@ -4,7 +4,22 @@ //- GENERATED CODE C_LINKAGE_BEGIN -String8 ctrl_entity_kind_display_string_table[9] = +String8 ctrl_entity_kind_code_name_table[11] = +{ +{0}, +str8_lit_comp("root"), +str8_lit_comp("machine"), +str8_lit_comp("process"), +str8_lit_comp("thread"), +str8_lit_comp("module"), +str8_lit_comp("entry_point"), +str8_lit_comp("debug_info_path"), +str8_lit_comp("pending_thread_name"), +str8_lit_comp("pending_thread_color"), +str8_lit_comp("breakpoint"), +}; + +String8 ctrl_entity_kind_display_string_table[11] = { {0}, str8_lit_comp("Root"), @@ -15,6 +30,8 @@ str8_lit_comp("Module"), str8_lit_comp("EntryPoint"), str8_lit_comp("DebugInfoPath"), str8_lit_comp("PendingThreadName"), +str8_lit_comp("PendingThreadColor"), +str8_lit_comp("Breakpoint"), }; U32 ctrl_exception_code_kind_code_table[38] = diff --git a/src/ctrl/generated/ctrl.meta.h b/src/ctrl/generated/ctrl.meta.h index 9192b4de..56f7b8db 100644 --- a/src/ctrl/generated/ctrl.meta.h +++ b/src/ctrl/generated/ctrl.meta.h @@ -17,6 +17,8 @@ CTRL_EntityKind_Module, CTRL_EntityKind_EntryPoint, CTRL_EntityKind_DebugInfoPath, CTRL_EntityKind_PendingThreadName, +CTRL_EntityKind_PendingThreadColor, +CTRL_EntityKind_Breakpoint, CTRL_EntityKind_COUNT, } CTRL_EntityKind; @@ -64,7 +66,8 @@ CTRL_ExceptionCodeKind_COUNT, } CTRL_ExceptionCodeKind; C_LINKAGE_BEGIN -extern String8 ctrl_entity_kind_display_string_table[9]; +extern String8 ctrl_entity_kind_code_name_table[11]; +extern String8 ctrl_entity_kind_display_string_table[11]; extern U32 ctrl_exception_code_kind_code_table[38]; extern String8 ctrl_exception_code_kind_display_string_table[38]; extern String8 ctrl_exception_code_kind_lowercase_code_string_table[38]; diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index a8aa6776..26d6df9f 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xe34cd4ff + //////////////////////////////// //~ rjf: Instruction Decoding/Disassembling Type Functions @@ -342,10 +345,13 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) DASM_Info info = {0}; if(!u128_match(hash, u128_zero())) { + //- 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: try to get existing results B32 found = 0; OS_MutexScopeR(stripe->rw_mutex) { @@ -360,9 +366,13 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } } } - B32 node_is_new = 0; + + //- rjf: miss -> kick off work to fill cache if(!found) { + B32 node_is_new = 0; + U64 *node_working_count = 0; + HS_Root root = {0}; OS_MutexScopeW(stripe->rw_mutex) { DASM_Node *node = 0; @@ -376,16 +386,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } if(node == 0) { - LogInfoNamedBlockF("dasm_new_node") - { - log_infof("hash: [0x%I64x 0x%I64x]\n", hash.u64[0], hash.u64[1]); - log_infof("vaddr: 0x%I64x\n", params->vaddr); - log_infof("arch: %S\n", string_from_arch(params->arch)); - log_infof("style_flags: 0x%x\n", params->style_flags); - log_infof("syntax: %i\n", params->syntax); - log_infof("base_vaddr: 0x%I64x\n", params->base_vaddr); - log_infof("dbgi_key: [%S 0x%I64x]\n", params->dbgi_key.path, params->dbgi_key.min_timestamp); - } + // rjf: allocate node node = stripe->free_node; if(node) { @@ -396,26 +397,34 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) node = push_array_no_zero(stripe->arena, DASM_Node, 1); } MemoryZeroStruct(node); + + // rjf: fill node DLLPushBack(slot->first, slot->last, node); node->hash = hash; MemoryCopyStruct(&node->params, params); + node->root = hs_root_alloc(); // TODO(rjf): need to make this releasable - currently all exe_paths just leak node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); + + // rjf: gather work kickoff params node_is_new = 1; + ins_atomic_u64_inc_eval(&node->working_count); + node_working_count = &node->working_count; + root = node->root; } } - } - if(node_is_new) - { - dasm_u2p_enqueue_req(hash, params, max_U64); - async_push_work(dasm_parse_work); + if(node_is_new) + { + dasm_u2p_enqueue_req(root, hash, params, max_U64); + async_push_work(dasm_parse_work, .working_counter = node_working_count); + } } } return info; } internal DASM_Info -dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out) +dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out) { DASM_Info result = {0}; for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) @@ -438,16 +447,17 @@ dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 //~ rjf: Parse Threads internal B32 -dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) +dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us) { B32 good = 0; OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64)) + if(available_size >= sizeof(root)+sizeof(hash)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64)) { good = 1; + 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, &root); 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, &hash); 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->vaddr); 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->arch); @@ -473,13 +483,14 @@ 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) +dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out) { OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Arch)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64)) { + 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, root_out); 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, hash_out); 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->vaddr); 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->arch); @@ -506,9 +517,10 @@ ASYNC_WORK_DEF(dasm_parse_work) TXT_Scope *txt_scope = txt_scope_open(); //- rjf: get next request + HS_Root root = {0}; U128 hash = {0}; DASM_Params params = {0}; - dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms); + dasm_u2p_dequeue_req(scratch.arena, &root, &hash, ¶ms); U64 change_gen = fs_change_gen(); //- rjf: unpack hash @@ -517,38 +529,19 @@ ASYNC_WORK_DEF(dasm_parse_work) 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) - { - 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; - } - } - } - //- rjf: get dbg info - RDI_Parsed *rdi = &di_rdi_parsed_nil; - if(got_task && params.dbgi_key.path.size != 0) + RDI_Parsed *rdi = &rdi_parsed_nil; + if(params.dbgi_key.path.size != 0) { rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64); } //- rjf: hash -> data - String8 data = {0}; - if(got_task) - { - data = hs_data_from_hash(hs_scope, hash); - } + String8 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) { @@ -573,7 +566,7 @@ ASYNC_WORK_DEF(dasm_parse_work) // rjf: push strings derived from voff -> line info if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines)) { - if(rdi != &di_rdi_parsed_nil) + if(rdi != &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); @@ -618,7 +611,7 @@ ASYNC_WORK_DEF(dasm_parse_work) { // 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)); + HS_Key key = fs_key_from_path_range(file_normalized_full_path, r1u64(0, max_U64), 0); TXT_LangKind lang_kind = txt_lang_kind_from_extension(file_normalized_full_path); U64 endt_us = max_U64; U128 hash = {0}; @@ -655,7 +648,7 @@ ASYNC_WORK_DEF(dasm_parse_work) 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); + addr_part = push_str8f(scratch.arena, "%s0x%016I64x ", rdi != &rdi_parsed_nil ? " " : "", params.vaddr+off); } String8 code_bytes_part = {0}; if(params.style_flags & DASM_StyleFlag_CodeBytes) @@ -677,7 +670,7 @@ ASYNC_WORK_DEF(dasm_parse_work) 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) + if(inst.jump_dest_vaddr != 0 && rdi != &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) @@ -709,7 +702,6 @@ ASYNC_WORK_DEF(dasm_parse_work) //- rjf: artifacts -> value bundle Arena *info_arena = 0; DASM_Info info = {0}; - if(got_task) { //- rjf: produce joined text Arena *text_arena = arena_alloc(); @@ -718,21 +710,7 @@ ASYNC_WORK_DEF(dasm_parse_work) 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))); - } + HS_Key text_key = hs_key_make(root, hs_id_make(0, 0)); //- rjf: submit text data to hash store U128 text_hash = hs_submit_data(text_key, &text_arena, text); @@ -744,7 +722,7 @@ ASYNC_WORK_DEF(dasm_parse_work) } //- rjf: commit results to cache - if(got_task) OS_MutexScopeW(stripe->rw_mutex) + OS_MutexScopeW(stripe->rw_mutex) { for(DASM_Node *n = slot->first; n != 0; n = n->next) { @@ -752,7 +730,7 @@ ASYNC_WORK_DEF(dasm_parse_work) { n->info_arena = info_arena; MemoryCopyStruct(&n->info, &info); - if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) + if(rdi != &rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) { n->change_gen = change_gen; } @@ -760,8 +738,6 @@ ASYNC_WORK_DEF(dasm_parse_work) { n->change_gen = 0; } - ins_atomic_u32_eval_assign(&n->is_working, 0); - ins_atomic_u64_inc_eval(&n->load_count); break; } } @@ -804,8 +780,7 @@ dasm_evictor_detector_thread__entry_point(void *p) if(n->scope_ref_count == 0 && n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) + ins_atomic_u64_eval(&n->working_count) == 0) { slot_has_work = 1; break; @@ -827,8 +802,7 @@ dasm_evictor_detector_thread__entry_point(void *p) if(n->scope_ref_count == 0 && n->last_time_touched_us+evict_threshold_us <= check_time_us && n->last_user_clock_idx_touched+evict_threshold_user_clocks <= check_time_user_clocks && - n->load_count != 0 && - n->is_working == 0) + ins_atomic_u64_eval(&n->working_count) == 0) { DLLRemove(slot->first, slot->last, n); if(n->info_arena != 0) @@ -841,7 +815,7 @@ dasm_evictor_detector_thread__entry_point(void *p) n->last_time_requested_us+retry_threshold_us <= check_time_us && n->last_user_clock_idx_requested+retry_threshold_user_clocks <= check_time_user_clocks) { - if(dasm_u2p_enqueue_req(n->hash, &n->params, max_U64)) + if(dasm_u2p_enqueue_req(n->root, n->hash, &n->params, max_U64)) { async_push_work(dasm_parse_work); n->last_time_requested_us = os_now_microseconds(); diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 2d670111..25a222fe 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -159,7 +159,7 @@ struct DASM_Result typedef struct DASM_Info DASM_Info; struct DASM_Info { - U128 text_key; + HS_Key text_key; DASM_LineArray lines; }; @@ -177,6 +177,9 @@ struct DASM_Node U128 hash; DASM_Params params; + // rjf: root + HS_Root root; + // rjf: generations U64 change_gen; @@ -185,11 +188,10 @@ struct DASM_Node DASM_Info info; // rjf: metadata - B32 is_working; + U64 working_count; U64 scope_ref_count; U64 last_time_touched_us; U64 last_user_clock_idx_touched; - U64 load_count; U64 last_time_requested_us; U64 last_user_clock_idx_requested; }; @@ -309,13 +311,13 @@ internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_No //~ rjf: Cache Lookups internal DASM_Info dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params); -internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, U128 key, DASM_Params *params, U128 *hash_out); +internal DASM_Info dasm_info_from_key_params(DASM_Scope *scope, HS_Key key, DASM_Params *params, U128 *hash_out); //////////////////////////////// //~ rjf: Parse Threads -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 B32 dasm_u2p_enqueue_req(HS_Root root, U128 hash, DASM_Params *params, U64 endt_us); +internal void dasm_u2p_dequeue_req(Arena *arena, HS_Root *root_out, U128 *hash_out, DASM_Params *params_out); ASYNC_WORK_DEF(dasm_parse_work); //////////////////////////////// diff --git a/src/dbg_engine/dbg_engine.mdesk b/src/dbg_engine/dbg_engine.mdesk index 8dc7469c..cbfe3352 100644 --- a/src/dbg_engine/dbg_engine.mdesk +++ b/src/dbg_engine/dbg_engine.mdesk @@ -4,53 +4,52 @@ //////////////////////////////// //~ rjf: Built-In Command Tables -@table(name ui_vis ipc_docs_vis q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_required canonical_icon string display_name desc search_tags ) -// / | | | \___ _________________________________/ | | | | | -// / | | | \ / | | | | | -D_CmdTable: // | | | | | | | | | | +@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter) +// / | | | | | | \___ _________________________________/ | | | | | | +// / | | | | | | \ / | | | | | | +D_CmdTable: // | | | | | | | | | | | | | | { //- rjf: low-level target control operations - {LaunchAndRun 1 1 Entity null Target Null 0 0 0 0 0 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" } - {LaunchAndInit 1 1 Entity null Target Null 0 0 0 0 0 1 PlayStepForward "launch_and_init" "Launch and Initialize" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" } - {Kill 1 1 Process null Nil Process 0 0 0 0 0 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" } - {KillAll 1 1 Null null Nil Null 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" } - {Detach 1 1 Process null Nil Process 0 0 0 0 0 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" } - {Continue 1 1 Null null Nil Null 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" } - {StepIntoInst 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" } - {StepOverInst 1 1 Null null Nil Null 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" } - {StepIntoLine 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" } - {StepOverLine 1 1 Null null Nil Null 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" } - {StepOut 1 1 Null null Nil Null 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" } - {Halt 1 1 Null null Nil Null 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" } - {SoftHaltRefresh 1 1 Null null Nil Null 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" } - {SetThreadIP 0 1 Vaddr null Nil Null 0 0 0 0 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" } + {LaunchAndRun 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Play "launch_and_run" "Launch and Run" "Starts debugging a new instance of a target, then runs." "launch,start,run,target" "" } + {LaunchAndStepInto 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 PlayStepForward "launch_and_step_into" "Launch and Step Into" "Starts debugging a new instance of a target, then stops at the program's entry point." "launch,start,entry,point" "" } + {Kill 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 X "kill" "Kill" "Kills the specified existing attached process(es)." "stop,kill" "" } + {KillAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Stop "kill_all" "Kill All" "Kills all attached processes." "stop,kill,all" "" } + {Detach 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Null "detach" "Detach" "Detaches the specified attached process(es)." "detach" "" } + {Continue 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "continue" "Continue" "Continues executing all attached processes." "" "" } + {StepIntoInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_inst" "Step Into (Assembly)" "Performs a step that goes into calls, at the instruction level." "single,step,thread" "" } + {StepOverInst 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_inst" "Step Over (Assembly)" "Performs a step that skips calls, at the instruction level." "single,step,thread" "" } + {StepIntoLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into_line" "Step Into (Line)" "Performs a step that goes into calls, at the source code line level." "step,thread" "" } + {StepOverLine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over_line" "Step Over (Line)" "Performs a step that skips calls, at the source code line level." "step,thread" "" } + {StepOut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOut "step_out" "Step Out" "Runs to the end of the current function and exits it." "" "" } + {Halt 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pause "halt" "Halt" "Halts all attached processes." "pause" "" } + {SoftHaltRefresh 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Refresh "soft_halt_refresh" "Soft Halt Refresh" "Interrupts all attached processes to collect data, and then resumes them." "" "" } + {SetThreadIP 0 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 1 1 Null "set_thread_ip" "Set Thread IP" "Sets the specified thread's instruction pointer at the specified address." "" "" } //- rjf: high-level composite target control operations - {RunToLine 0 1 Null null Nil Null 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" } - {RunToAddress 1 1 Vaddr null Nil Null 0 0 0 0 1 1 PlayStepForward "run_to_address" "Run To Address" "Runs until a particular address is hit." "" } - {Run 1 1 Null null Nil Null 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" } - {Restart 1 1 Null null Nil Null 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" } - {StepInto 1 1 Null null Nil Null 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" } - {StepOver 1 1 Null null Nil Null 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" } + {RunToLine 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run_to_line" "Run To Line" "Runs until a particular source line is hit." "" "$text_pt," } + {Run 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Play "run" "Run" "Runs all targets after starting them if they have not been started yet." "play" "" } + {Restart 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "restart" "Restart" "Kills all attached processes, then launches all active targets." "restart,retry" "" } + {StepInto 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepInto "step_into" "Step Into" "Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)." "" "" } + {StepOver 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 StepOver "step_over" "Step Over" "Steps once, always over function calls, for either source lines or instructions." "" "" } //- rjf: debug control context management operations - {FreezeThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" } - {ThawThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" } - {FreezeProcess 1 1 Process null Nil Process 0 0 0 0 0 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" } - {ThawProcess 1 1 Process null Nil Process 0 0 0 0 0 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" } - {FreezeMachine 0 1 Machine null Nil Machine 0 0 0 0 0 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" } - {ThawMachine 0 1 Machine null Nil Machine 0 0 0 0 0 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" } - {FreezeLocalMachine 1 1 Null null Nil Null 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" } - {ThawLocalMachine 1 1 Null null Nil Null 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" } - {FreezeEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "freeze_entity" "Freeze Entity" "Freezes an entity." "" } - {ThawEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "thaw_entity" "Thaw Entity" "Thaws an entity." "" } + {FreezeThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Locked "freeze_thread" "Freeze Thread" "Freezes the passed thread." "callstack,unwind" "" } + {ThawThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Unlocked "thaw_thread" "Thaw Thread" "Thaws the passed thread." "" "" } + {FreezeProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Locked "freeze_process" "Freeze Process" "Freezes the passed process." "" "" } + {ThawProcess 1 1 0 0 "query:processes" Process null Nil Process 0 0 0 0 0 1 1 Unlocked "thaw_process" "Thaw Process" "Thaws the passed process." "" "" } + {FreezeMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Locked "freeze_machine" "Freeze Machine" "Freezes the passed machine." "" "" } + {ThawMachine 0 1 0 0 "query:machines" Machine null Nil Machine 0 0 0 0 0 1 1 Unlocked "thaw_machine" "Thaw Machine" "Thaws the passed machine." "" "" } + {FreezeLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "freeze_local_machine" "Freeze Local Machine" "Freezes the local machine." "" "" } + {ThawLocalMachine 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Machine "thaw_local_machine" "Thaw Local Machine" "Thaws the local machine." "" "" } + {FreezeEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Unlocked "freeze_entity" "Freeze Entity" "Freezes an entity." "" "" } + {ThawEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Locked "thaw_entity" "Thaw Entity" "Thaws an entity." "" "" } //- rjf: entity decoration - {SetEntityColor 0 0 Null null Nil Null 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" } - {SetEntityName 0 0 Null null Nil Null 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" } + {SetEntityColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_color" "Set Entity Color" "Sets the passed entity's color." "" "" } + {SetEntityName 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_entity_name" "Set Entity Name" "Sets the passed entity's name." "" "" } //- rjf: attaching - {Attach 1 1 PID null Nil Null 0 0 0 0 0 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" } + {Attach 1 1 0 0 "query:unattached_processes" PID null Nil Null 0 0 0 0 0 1 1 Null "attach" "Attach" "Attaches to a process that is already running on the local machine." "" "" } } @enum D_CmdKind: @@ -60,47 +59,6 @@ D_CmdTable: // | | | | COUNT, } -//////////////////////////////// -//~ rjf: Built-In VieNull w Rules - -@table(coverage_check name name_lower string ih ex xp vb display_name docs schema description) -D_ViewRuleTable: -{ - {x Default default "default" - - - x "Default" - "" "" } - {x Array array "array" - - x - "Array" x "x:{expr}" "Specifies that a pointer points to N elements, rather than only 1." } - {x Slice slice "slice" - - x - "Slice" x "" "Specifies that a pointer within a struct, also containing an integer, points to the number of elements encoded by the integer." } - {- List list "list" - - - x "List" - "x:{member}" "Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list." } - {x ByteSwap bswap "bswap" x - x - "Byte Swap" x "" "Specifies that all integral evaluations should be byte-swapped, such that their endianness is reversed." } - {x Cast cast "cast" - - x - "Cast" x "x:{type}" "Specifies that the expression to which the view rule is applied should be casted to the provided type." } - {- BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "" "Specifies that all integral evaluations should appear in base-10 form." } - {- BaseBin base_bin "bin" x - - - "Binary Base (Base 2)" x "" "Specifies that all integral evaluations should appear in base-2 form." } - {- BaseOct base_oct "oct" x - - - "Octal Base (Base 8)" x "" "Specifies that all integral evaluations should appear in base-8 form." } - {- BaseHex base_hex "hex" x - - - "Hexadecimal Base (Base 16)" x "" "Specifies that all integral evaluations should appear in base-16 form." } - {- Only only "only" x - - x "Only Specified Members" x "x:{member}" "Specifies that only the specified members should appear in struct, union, or class evaluations." } - {- Omit omit "omit" x - - x "Omit Specified Members" x "x:{member}" "Omits a list of member names from appearing in struct, union, or class evaluations." } - {- NoAddr no_addr "no_addr" x - - - "Disable Address Values" x "" "Displays only what pointers point to, if possible, without the pointer's address value." } - {x Checkbox checkbox "checkbox" - - - - "Checkbox" x "" "Displays simple integer values as checkboxes, encoding zero or nonzero values." } - {- ColorRGBA color_rgba "color_rgba" - x - x "Color (RGBA)" x "" "Displays as a color, interpreting the data as encoding R, G, B, and A values." } - {x Text text "text" - x - x "Text" x "x:{'lang':lang, 'size':expr}" "Displays as text." } - {x Disasm disasm "disasm" - x - x "Disassembly" x "x:{'arch':arch, 'size':expr}" "Displays as disassembled instructions, interpreting the data as raw machine code." } - {x Memory memory "memory" - x - x "Memory" x "x:{'size':expr}" "Displays as a raw memory grid." } - {- Graph graph "graph" - x - x "Graph" x "" "Displays as a pointer graph, visualizing nodes and edges formed by pointers directly." } - {x Bitmap bitmap "bitmap" - x - x "Bitmap" x "x:{'w':expr, 'h':expr, 'fmt':tex2dformat}" "Displays as a bitmap, interpreting the data as raw pixel data." } - {- Geo3D geo3d "geo3d" - x - x "Geometry (3D)" x "x:{'count':expr, 'vtx':expr, 'vtx_size':expr}" "Displays as geometry, interpreting the data as index or vertex data." } -} - -@enum D_ViewRuleKind: -{ - @expand(D_ViewRuleTable a) `$(a.name)`, - COUNT, -} - -@data(D_ViewRuleSpecInfo) @c_file d_core_view_rule_spec_info_table: -{ - @expand(D_ViewRuleTable a) - ```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.schema)"), str8_lit_comp("$(a.description)"), (D_ViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(D_ViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(D_ViewRuleSpecInfoFlag_ExprResolution*$(a.xp == "x"))|(D_ViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), }```; -} - //////////////////////////////// //~ rjf: Developer Toggles @@ -114,7 +72,6 @@ D_DevToggleTable: {eval_compiler_tooltips} {eval_watch_key_tooltips} {cmd_context_tooltips} - {scratch_mouse_draw} {updating_indicator} } diff --git a/src/dbg_engine/dbg_engine_core.c b/src/dbg_engine/dbg_engine_core.c index ff307b28..69c5432d 100644 --- a/src/dbg_engine/dbg_engine_core.c +++ b/src/dbg_engine/dbg_engine_core.c @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.70f, 0.50f, 0.25f +#undef LAYER_COLOR +#define LAYER_COLOR 0x4d9ae3ff //////////////////////////////// //~ rjf: Generated Code @@ -12,14 +12,16 @@ //////////////////////////////// //~ rjf: Basic Helpers +#if !defined(XXH_IMPLEMENTATION) +# define XXH_IMPLEMENTATION +# define XXH_STATIC_LINKING_ONLY +# include "third_party/xxHash/xxhash.h" +#endif + internal U64 d_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; } @@ -59,7 +61,7 @@ d_breakpoint_array_copy(Arena *arena, D_BreakpointArray *src) for(U64 idx = 0; idx < dst.count; idx += 1) { dst.v[idx].file_path = push_str8_copy(arena, dst.v[idx].file_path); - dst.v[idx].symbol_name = push_str8_copy(arena, dst.v[idx].symbol_name); + dst.v[idx].vaddr_expr = push_str8_copy(arena, dst.v[idx].vaddr_expr); dst.v[idx].condition = push_str8_copy(arena, dst.v[idx].condition); } return dst; @@ -194,59 +196,6 @@ d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams * cmds->count += 1; } -//////////////////////////////// -//~ rjf: View Rule Spec Stateful Functions - -internal void -d_register_view_rule_specs(D_ViewRuleSpecInfoArray specs) -{ - for(U64 idx = 0; idx < specs.count; idx += 1) - { - // rjf: extract info from array slot - D_ViewRuleSpecInfo *info = &specs.v[idx]; - - // rjf: skip empties - if(info->string.size == 0) - { - continue; - } - - // rjf: determine hash/slot - U64 hash = d_hash_from_string(info->string); - U64 slot_idx = hash%d_state->view_rule_spec_table_size; - - // rjf: allocate node & push - D_ViewRuleSpec *spec = push_array(d_state->arena, D_ViewRuleSpec, 1); - SLLStackPush_N(d_state->view_rule_spec_table[slot_idx], spec, hash_next); - - // rjf: fill node - D_ViewRuleSpecInfo *info_copy = &spec->info; - MemoryCopyStruct(info_copy, info); - info_copy->string = push_str8_copy(d_state->arena, info->string); - info_copy->display_string = push_str8_copy(d_state->arena, info->display_string); - info_copy->description = push_str8_copy(d_state->arena, info->description); - } -} - -internal D_ViewRuleSpec * -d_view_rule_spec_from_string(String8 string) -{ - D_ViewRuleSpec *spec = &d_nil_core_view_rule_spec; - { - U64 hash = d_hash_from_string(string); - U64 slot_idx = hash%d_state->view_rule_spec_table_size; - for(D_ViewRuleSpec *s = d_state->view_rule_spec_table[slot_idx]; s != 0; s = s->hash_next) - { - if(str8_match(string, s->info.string, 0)) - { - spec = s; - break; - } - } - } - return spec; -} - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -351,13 +300,13 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread) // rjf: thread => unpacked info CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); Arch arch = thread->arch; - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle); + U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); // rjf: ip => machine code String8 machine_code = {0}; { Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, rng, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, rng, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } @@ -388,7 +337,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) // rjf: thread => info Arch arch = thread->arch; - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle); + U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); @@ -431,7 +380,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+50000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+50000); machine_code = machine_code_slice.data; LogInfoNamedBlockF("machine_code_slice") { @@ -549,7 +498,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) // rjf: thread => info Arch arch = thread->arch; - U64 ip_vaddr = ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle); + U64 ip_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); @@ -587,7 +536,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+5000); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+5000); machine_code = machine_code_slice.data; } @@ -606,6 +555,16 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) machine_code); } + // rjf: determine last + DASM_CtrlFlowPoint *last_call_point = 0; + if(good_line_info) for(DASM_CtrlFlowPointNode *n = ctrl_flow_info.exit_points.first; n != 0; n = n->next) + { + if(n->v.inst_flags & DASM_InstFlag_Call) + { + last_call_point = &n->v; + } + } + // rjf: push traps for all exit points if(good_line_info) for(DASM_CtrlFlowPointNode *n = ctrl_flow_info.exit_points.first; n != 0; n = n->next) { @@ -614,6 +573,23 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) B32 add = 1; U64 trap_addr = point->vaddr; + // rjf: if this is not the last call instruction in the control flow, + // and if we have no line info for this address, then do not add. + if(point != last_call_point && + point->inst_flags & DASM_InstFlag_Call && + point->jump_dest_vaddr != 0) + { + U64 jump_dest_vaddr = point->jump_dest_vaddr; + CTRL_Entity *jump_dest_module = ctrl_module_from_process_vaddr(process, jump_dest_vaddr); + U64 jump_dest_voff = ctrl_voff_from_vaddr(jump_dest_module, jump_dest_vaddr); + DI_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &jump_dest_dbgi_key, jump_dest_voff); + if(lines.count == 0) + { + add = 0; + } + } + // rjf: branches/jumps/returns => single-step & end, OR trap @ destination. if(point->inst_flags & (DASM_InstFlag_Call| DASM_InstFlag_Branch| @@ -664,67 +640,6 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread) //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: symbol lookups - -internal String8 -d_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff, B32 decorated) -{ - String8 result = {0}; - { - Temp scratch = scratch_begin(&arena, 1); - DI_Scope *scope = di_scope_open(); - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); - if(result.size == 0) - { - U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - U64 proc_idx = scope->proc_idx; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); - E_TypeKey type = e_type_key_ext(E_TypeKind_Function, procedure->type_idx, e_parse_ctx_module_idx_from_rdi(rdi)); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); - if(decorated && procedure->type_idx != 0) - { - String8List list = {0}; - e_type_lhs_string_from_key(scratch.arena, type, &list, 0, 0); - str8_list_push(scratch.arena, &list, name); - e_type_rhs_string_from_key(scratch.arena, type, &list, 0); - result = str8_list_join(arena, &list, 0); - } - else - { - result = push_str8_copy(arena, name); - } - } - if(result.size == 0) - { - U64 global_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, voff); - RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, global_idx); - U64 name_size = 0; - U8 *name_ptr = rdi_string_from_idx(rdi, global_var->name_string_idx, &name_size); - result = push_str8_copy(arena, str8(name_ptr, name_size)); - } - di_scope_close(scope); - scratch_end(scratch); - } - return result; -} - -internal String8 -d_symbol_name_from_process_vaddr(Arena *arena, CTRL_Entity *process, U64 vaddr, B32 decorated) -{ - ProfBeginFunction(); - String8 result = {0}; - { - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - U64 voff = ctrl_voff_from_vaddr(module, vaddr); - result = d_symbol_name_from_dbgi_key_voff(arena, &dbgi_key, voff, decorated); - } - ProfEnd(); - return result; -} - //- rjf: symbol -> voff lookups internal U64 @@ -741,7 +656,7 @@ d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name) RDI_NameMapKind_GlobalVariables, RDI_NameMapKind_Procedures, }; - if(rdi != &di_rdi_parsed_nil) + if(rdi != &rdi_parsed_nil) { for(U64 name_map_kind_idx = 0; name_map_kind_idx < ArrayCount(name_map_kinds); @@ -808,45 +723,6 @@ d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name) return result; } -internal U64 -d_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name) -{ - ProfBeginFunction(); - DI_Scope *scope = di_scope_open(); - U64 result = 0; - { - RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Types); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); - U64 entity_num = 0; - if(node != 0) - { - switch(node->match_count) - { - case 1: - { - entity_num = node->match_idx_or_idx_run_first + 1; - }break; - default: - { - U32 num = 0; - U32 *run = rdi_matches_from_map_node(rdi, node, &num); - if(num != 0) - { - entity_num = run[0]+1; - } - }break; - } - } - result = entity_num; - } - di_scope_close(scope); - ProfEnd(); - return result; -} - //- rjf: voff -> line info internal D_LineList @@ -968,7 +844,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key, // 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") + if(rdi != &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}; @@ -1066,7 +942,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64 // 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") + if(rdi != &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}; @@ -1185,7 +1061,7 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 U64 tls_index = 0; if(addr_size != 0) { - CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0); + CTRL_ProcessMemorySlice tls_index_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0); if(tls_index_slice.data.size >= addr_size) { tls_index = *(U64 *)tls_index_slice.data.str; @@ -1198,13 +1074,13 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; U64 tls_addr_array = 0; - CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); + CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0); String8 tls_addr_array_data = tls_addr_array_slice.data; if(tls_addr_array_data.size >= 8) { MemoryCopy(&tls_addr_array, tls_addr_array_data.str, sizeof(U64)); } - CTRL_ProcessMemorySlice result_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); + CTRL_ProcessMemorySlice result_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0); String8 result_data = result_slice.data; if(result_data.size >= 8) { @@ -1299,10 +1175,10 @@ internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena) { DI_KeyList dbgis = {0}; - CTRL_EntityList modules = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Module); - for(CTRL_EntityNode *n = modules.first; n != 0; n = n->next) + CTRL_EntityArray modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); + for EachIndex(idx, modules.count) { - CTRL_Entity *module = n->v; + CTRL_Entity *module = modules.v[idx]; DI_Key key = ctrl_dbgi_key_from_module(module); di_key_list_push(arena, &dbgis, &key); } @@ -1311,61 +1187,6 @@ d_push_active_dbgi_key_list(Arena *arena) //- rjf: per-run caches -internal CTRL_Unwind -d_query_cached_unwind_from_thread(CTRL_Entity *thread) -{ - Temp scratch = scratch_begin(0, 0); - CTRL_Unwind result = {0}; - if(thread->kind == CTRL_EntityKind_Thread) - { - U64 reg_gen = ctrl_reg_gen(); - U64 mem_gen = ctrl_mem_gen(); - D_UnwindCache *cache = &d_state->unwind_cache; - CTRL_Handle handle = thread->handle; - U64 hash = d_hash_from_string(str8_struct(&handle)); - U64 slot_idx = hash%cache->slots_count; - D_UnwindCacheSlot *slot = &cache->slots[slot_idx]; - D_UnwindCacheNode *node = 0; - for(D_UnwindCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(handle, n->thread)) - { - node = n; - break; - } - } - if(node == 0) - { - node = cache->free_node; - if(node != 0) - { - SLLStackPop(cache->free_node); - } - else - { - node = push_array_no_zero(d_state->arena, D_UnwindCacheNode, 1); - } - MemoryZeroStruct(node); - DLLPushBack(slot->first, slot->last, node); - node->arena = arena_alloc(); - node->thread = handle; - } - if(!d_state->ctrl_is_running && (node->reggen != reg_gen || node->memgen != mem_gen)) - { - CTRL_Unwind new_unwind = ctrl_unwind_from_thread(scratch.arena, d_state->ctrl_entity_store, thread->handle, os_now_microseconds()+100); - if(!(new_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale)) && new_unwind.frames.count != 0) - { - node->unwind = ctrl_unwind_deep_copy(node->arena, thread->arch, &new_unwind); - node->reggen = reg_gen; - node->memgen = mem_gen; - } - } - result = node->unwind; - } - scratch_end(scratch); - return result; -} - internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread) { @@ -1379,15 +1200,17 @@ d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count) U64 result = 0; if(unwind_count == 0) { - result = ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle); + result = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); } else { - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(thread); - if(unwind.frames.count != 0) + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, 0); + if(callstack.concrete_frames_count != 0) { - result = regs_rip_from_arch_block(thread->arch, unwind.frames.v[unwind_count%unwind.frames.count].regs); + result = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[unwind_count%callstack.concrete_frames_count]->regs); } + ctrl_scope_close(ctrl_scope); } return result; } @@ -1594,22 +1417,13 @@ d_init(void) d_state = push_array(arena, D_State, 1); d_state->arena = arena; d_state->cmds_arena = arena_alloc(); - d_state->output_log_key = hs_hash_from_data(str8_lit("output_log_key")); - d_state->ctrl_entity_store = ctrl_entity_store_alloc(); + d_state->output_log_key = hs_key_make(hs_root_alloc(), hs_id_make(0, 0)); + hs_submit_data(d_state->output_log_key, 0, str8_zero()); + d_state->ctrl_entity_store = ctrl_entity_ctx_rw_store_alloc(); d_state->ctrl_stop_arena = arena_alloc(); - d_state->view_rule_spec_table_size = 1024; - d_state->view_rule_spec_table = push_array(arena, D_ViewRuleSpec *, d_state->view_rule_spec_table_size); d_state->ctrl_msg_arena = arena_alloc(); - // rjf: register core view rules - { - D_ViewRuleSpecInfoArray array = {d_core_view_rule_spec_info_table, ArrayCount(d_core_view_rule_spec_info_table)}; - d_register_view_rule_specs(array); - } - // rjf: set up caches - d_state->unwind_cache.slots_count = 1024; - d_state->unwind_cache.slots = push_array(arena, D_UnwindCacheSlot, d_state->unwind_cache.slots_count); for(U64 idx = 0; idx < ArrayCount(d_state->tls_base_caches); idx += 1) { d_state->tls_base_caches[idx].arena = arena_alloc(); @@ -1628,13 +1442,12 @@ d_init(void) } internal D_EventList -d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64], CTRL_MetaEvalArray *meta_evals) +d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); D_EventList result = {0}; d_state->frame_index += 1; - d_state->frame_eval_memread_endt_us = os_now_microseconds() + 1000; ////////////////////////////// //- rjf: sync with ctrl thread @@ -1699,7 +1512,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P // rjf: push stop event to caller, if this is not a soft-halt if(should_snap) { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, event->entity); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, event->entity); D_EventCause cause = D_EventCause_Null; switch(event->cause) { @@ -1725,6 +1538,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P evt->cause = cause; evt->thread = thread->kind == CTRL_EntityKind_Thread ? thread->handle : ctrl_handle_zero(); evt->vaddr = event->rip_vaddr; + evt->id = event->u64_code; } }break; @@ -1733,7 +1547,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case CTRL_EventKind_NewProc: { // rjf: the first process? -> clear session output - CTRL_EntityList existing_processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray existing_processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(existing_processes.count == 1) { MTX_Op op = {r1u64(0, 0xffffffffffffffffull), str8_lit("[new session]\n")}; @@ -1816,10 +1630,10 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P // rjf: build data strings of all param data String8List strings = {0}; { - CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread); - for(CTRL_EntityNode *n = threads.first; n != 0; n = n->next) + CTRL_EntityArray threads = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Thread); + for EachIndex(idx, threads.count) { - CTRL_Entity *thread = n->v; + CTRL_Entity *thread = threads.v[idx]; if(thread->is_frozen) { str8_list_push(scratch.arena, &strings, str8_struct(&thread->id)); @@ -1831,8 +1645,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P D_Breakpoint *bp = &breakpoints->v[idx]; str8_list_push(scratch.arena, &strings, bp->file_path); str8_list_push(scratch.arena, &strings, str8_struct(&bp->pt)); - str8_list_push(scratch.arena, &strings, bp->symbol_name); - str8_list_push(scratch.arena, &strings, str8_struct(&bp->vaddr)); + str8_list_push(scratch.arena, &strings, bp->vaddr_expr); str8_list_push(scratch.arena, &strings, bp->condition); } } @@ -1854,53 +1667,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P d_cmd(D_CmdKind_SoftHaltRefresh); } - ////////////////////////////// - //- rjf: garbage collect eliminated thread unwinds - // - for(U64 slot_idx = 0; slot_idx < d_state->unwind_cache.slots_count; slot_idx += 1) - { - D_UnwindCacheSlot *slot = &d_state->unwind_cache.slots[slot_idx]; - for(D_UnwindCacheNode *n = slot->first, *next = 0; n != 0; n = next) - { - next = n->next; - if(ctrl_entity_from_handle(d_state->ctrl_entity_store, n->thread) == &ctrl_entity_nil) - { - DLLRemove(slot->first, slot->last, n); - arena_release(n->arena); - SLLStackPush(d_state->unwind_cache.free_node, n); - } - } - } - - ////////////////////////////// - //- rjf: sync with di parsers - // - ProfScope("sync with di parsers") - { - DI_EventList events = di_p2u_pop_events(scratch.arena, 0); - for(DI_EventNode *n = events.first; n != 0; n = n->next) - { - DI_Event *event = &n->v; - switch(event->kind) - { - default:{}break; - case DI_EventKind_ConversionStarted: - { - RD_Entity *task = rd_entity_alloc(rd_entity_root(), RD_EntityKind_ConversionTask); - rd_entity_equip_name(task, event->string); - }break; - case DI_EventKind_ConversionEnded: - { - RD_Entity *task = rd_entity_from_name_and_kind(event->string, RD_EntityKind_ConversionTask); - if(!rd_entity_is_nil(task)) - { - rd_entity_mark_for_deletion(task); - } - }break; - } - } - } - ////////////////////////////// //- rjf: process top-level commands // @@ -1927,7 +1693,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P //- rjf: low-level target control operations case D_CmdKind_LaunchAndRun: - case D_CmdKind_LaunchAndInit: + case D_CmdKind_LaunchAndStepInto: { // rjf: get list of targets to launch D_TargetArray *targets_to_launch = ¶ms->targets; @@ -1998,7 +1764,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P msg->debug_subprocesses = target->debug_subprocesses; msg->env_inherit = 1; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); - MemoryCopyStruct(&msg->meta_evals, meta_evals); str8_list_push(scratch.arena, &msg->entry_points, custom_entry_point_name); msg->env_string_list = env; } @@ -2008,7 +1773,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P need_run = 1; run_kind = D_RunKind_Run; run_thread = &ctrl_entity_nil; - run_flags = (cmd->kind == D_CmdKind_LaunchAndInit) ? CTRL_RunFlag_StopOnEntryPoint : 0; + run_flags = (cmd->kind == D_CmdKind_LaunchAndStepInto) ? CTRL_RunFlag_StopOnEntryPoint : 0; } // rjf: no targets -> error @@ -2019,7 +1784,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P }break; case D_CmdKind_Kill: { - CTRL_Entity *process = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->process); + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->process); if(process == &ctrl_entity_nil) { log_user_error(str8_lit("Cannot kill; no process was specified.")); @@ -2031,7 +1796,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P msg->exit_code = 1; msg->entity = process->handle; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); - MemoryCopyStruct(&msg->meta_evals, meta_evals); } }break; case D_CmdKind_KillAll: @@ -2040,11 +1804,10 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P 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: { - CTRL_Entity *process = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->process); + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->process); if(process == &ctrl_entity_nil) { log_user_error(str8_lit("Cannot detach; no process specified.")); @@ -2055,18 +1818,18 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P msg->kind = CTRL_MsgKind_Detach; msg->entity = process->handle; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); - MemoryCopyStruct(&msg->meta_evals, meta_evals); } }break; case D_CmdKind_Continue: { B32 good_to_run = 0; - CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread); + CTRL_EntityArray threads = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Thread); if(threads.count > 0) { - for(CTRL_EntityNode *n = threads.first; n != 0; n = n->next) + for EachIndex(idx, threads.count) { - if(!n->v->is_frozen) + CTRL_Entity *thread = threads.v[idx]; + if(!thread->is_frozen) { good_to_run = 1; break; @@ -2090,7 +1853,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_StepOverLine: case D_CmdKind_StepOut: { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->thread); if(thread == &ctrl_entity_nil) { log_user_error(str8_lit("Must have a selected thread to step.")); @@ -2119,13 +1882,15 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_StepOverLine: {traps = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break; case D_CmdKind_StepOut: { - // rjf: thread => full unwind - CTRL_Unwind unwind = ctrl_unwind_from_thread(scratch.arena, d_state->ctrl_entity_store, thread->handle, os_now_microseconds()+10000); + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + + // rjf: thread => call stack + CTRL_CallStack callstack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); // rjf: use first unwind frame to generate trap - if(unwind.flags == 0 && unwind.frames.count > 1) + if(callstack.concrete_frames_count > 1) { - U64 vaddr = regs_rip_from_arch_block(thread->arch, unwind.frames.v[1].regs); + U64 vaddr = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[1]->regs); CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; ctrl_trap_list_push(scratch.arena, &traps, &trap); } @@ -2134,6 +1899,8 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P log_user_error(str8_lit("Could not find the return address of the current callstack frame successfully.")); good = 0; } + + ctrl_scope_close(ctrl_scope); }break; } if(good && traps.count != 0) @@ -2164,38 +1931,18 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { need_run = 1; run_kind = d_state->ctrl_last_run_kind; - run_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, d_state->ctrl_last_run_thread_handle); + run_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, d_state->ctrl_last_run_thread_handle); run_flags = d_state->ctrl_last_run_flags; run_traps = d_state->ctrl_last_run_traps; }break; case D_CmdKind_SetThreadIP: { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->thread); U64 vaddr = params->vaddr; - void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, d_state->ctrl_entity_store, thread->handle); + void *block = ctrl_reg_block_from_thread(scratch.arena, &d_state->ctrl_entity_store->ctx, thread->handle); regs_arch_block_write_rip(thread->arch, block, vaddr); B32 result = ctrl_thread_write_reg_block(thread->handle, block); - - // rjf: early mutation of unwind cache for immediate frontend effect - if(result) - { - D_UnwindCache *cache = &d_state->unwind_cache; - if(cache->slots_count != 0) - { - CTRL_Handle thread_handle = thread->handle; - U64 hash = d_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash%cache->slots_count; - D_UnwindCacheSlot *slot = &cache->slots[slot_idx]; - for(D_UnwindCacheNode *n = slot->first; n != 0; n = n->next) - { - if(ctrl_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0) - { - regs_arch_block_write_rip(thread->arch, n->unwind.frames.v[0].regs, vaddr); - break; - } - } - } - } + (void)result; }break; //- rjf: high-level composite target control operations @@ -2203,20 +1950,20 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { run_extra_bps.count = 1; run_extra_bps.v = push_array(scratch.arena, D_Breakpoint, 1); - run_extra_bps.v[0].file_path = params->file_path; - run_extra_bps.v[0].pt = params->cursor; - d_cmd(D_CmdKind_Run); - }break; - case D_CmdKind_RunToAddress: - { - run_extra_bps.count = 1; - run_extra_bps.v = push_array(scratch.arena, D_Breakpoint, 1); - run_extra_bps.v[0].vaddr = params->vaddr; + if(params->file_path.size != 0) + { + run_extra_bps.v[0].file_path = params->file_path; + run_extra_bps.v[0].pt = params->cursor; + } + else if(params->vaddr != 0) + { + run_extra_bps.v[0].vaddr_expr = push_str8f(scratch.arena, "0x%I64x", params->vaddr); + } d_cmd(D_CmdKind_Run); }break; case D_CmdKind_Run: { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count != 0) { d_cmd(D_CmdKind_Continue); @@ -2228,7 +1975,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P }break; case D_CmdKind_Restart: { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count != 0) { d_cmd(D_CmdKind_KillAll); @@ -2238,7 +1985,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_StepInto: case D_CmdKind_StepOver: { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count != 0) { D_CmdKind step_cmd_kind = (cmd->kind == D_CmdKind_StepInto @@ -2255,7 +2002,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P } else if(!d_ctrl_targets_running()) { - d_cmd(D_CmdKind_LaunchAndInit, .targets = *targets); + d_cmd(D_CmdKind_LaunchAndStepInto, .targets = *targets); } }break; @@ -2277,18 +2024,18 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P case D_CmdKind_FreezeLocalMachine: { CTRL_MachineID machine_id = CTRL_MachineID_Local; - d_cmd(D_CmdKind_FreezeMachine, .machine = ctrl_handle_make(machine_id, dmn_handle_zero())); + d_cmd(D_CmdKind_FreezeMachine, .entity = ctrl_handle_make(machine_id, dmn_handle_zero())); }break; case D_CmdKind_ThawLocalMachine: { CTRL_MachineID machine_id = CTRL_MachineID_Local; - d_cmd(D_CmdKind_ThawMachine, .machine = ctrl_handle_make(machine_id, dmn_handle_zero())); + d_cmd(D_CmdKind_ThawMachine, .entity = ctrl_handle_make(machine_id, dmn_handle_zero())); }break; case D_CmdKind_FreezeEntity: case D_CmdKind_ThawEntity: { B32 should_freeze = (cmd->kind == D_CmdKind_FreezeEntity); - CTRL_Entity *root = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->entity); + CTRL_Entity *root = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->entity); for(CTRL_Entity *e = root; e != &ctrl_entity_nil; e = ctrl_entity_rec_depth_first_pre(e, root).next) { if(e->kind == CTRL_EntityKind_Thread) @@ -2303,7 +2050,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P { need_run = 1; run_kind = d_state->ctrl_last_run_kind; - run_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, d_state->ctrl_last_run_thread_handle); + run_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, d_state->ctrl_last_run_thread_handle); run_flags = d_state->ctrl_last_run_flags; run_traps = d_state->ctrl_last_run_traps; } @@ -2312,12 +2059,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P //- rjf: entity decoration case D_CmdKind_SetEntityColor: { - CTRL_Entity *entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->entity); + CTRL_Entity *entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->entity); entity->rgba = params->rgba; }break; case D_CmdKind_SetEntityName: { - CTRL_Entity *entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, params->entity); + CTRL_Entity *entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, params->entity); ctrl_entity_equip_string(d_state->ctrl_entity_store, entity, params->string); }break; @@ -2331,7 +2078,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P msg->kind = CTRL_MsgKind_Attach; msg->entity_id = pid; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); - MemoryCopyStruct(&msg->meta_evals, meta_evals); } }break; } @@ -2353,7 +2099,6 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P msg->entity = run_thread->handle; msg->parent = process->handle; MemoryCopyArray(msg->exception_code_filters, exception_code_filters); - MemoryCopyStruct(&msg->meta_evals, meta_evals); MemoryCopyStruct(&msg->traps, &run_traps); D_BreakpointArray *bp_batches[] = { @@ -2368,6 +2113,12 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P // rjf: unpack user breakpoint entity D_Breakpoint *bp = &batch_breakpoints->v[idx]; + // rjf: d -> ctrl flags + CTRL_UserBreakpointFlags ctrl_bp_flags = 0; + if(bp->flags & D_BreakpointFlag_BreakOnWrite) { ctrl_bp_flags |= CTRL_UserBreakpointFlag_BreakOnWrite; } + if(bp->flags & D_BreakpointFlag_BreakOnRead) { ctrl_bp_flags |= CTRL_UserBreakpointFlag_BreakOnRead; } + if(bp->flags & D_BreakpointFlag_BreakOnExecute) { ctrl_bp_flags |= CTRL_UserBreakpointFlag_BreakOnExecute; } + // rjf: textual location -> add breakpoints for all possible override locations if(bp->file_path.size != 0 && bp->pt.line != 0) { @@ -2375,28 +2126,25 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P for(String8Node *n = overrides.first; n != 0; n = n->next) { CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_FileNameAndLineColNumber}; + ctrl_user_bp.flags = ctrl_bp_flags; + ctrl_user_bp.id = bp->id; ctrl_user_bp.string = n->string; ctrl_user_bp.pt = bp->pt; ctrl_user_bp.condition = bp->condition; + ctrl_user_bp.size = bp->size; ctrl_user_breakpoint_list_push(scratch.arena, &msg->user_bps, &ctrl_user_bp); } } - // rjf: virtual address location -> add breakpoint for address - else if(bp->vaddr != 0) + // rjf: virtual address expression -> add expression breakpoint + else if(bp->vaddr_expr.size != 0) { - CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_VirtualAddress}; - ctrl_user_bp.u64 = bp->vaddr; - ctrl_user_bp.condition = bp->condition; - ctrl_user_breakpoint_list_push(scratch.arena, &msg->user_bps, &ctrl_user_bp); - } - - // rjf: symbol name location -> add breakpoint for symbol name - else if(bp->symbol_name.size != 0) - { - CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_SymbolNameAndOffset}; - ctrl_user_bp.string = bp->symbol_name; + CTRL_UserBreakpoint ctrl_user_bp = {CTRL_UserBreakpointKind_Expression}; + ctrl_user_bp.flags = ctrl_bp_flags; + ctrl_user_bp.id = bp->id; + ctrl_user_bp.string = bp->vaddr_expr; ctrl_user_bp.condition = bp->condition; + ctrl_user_bp.size = bp->size; ctrl_user_breakpoint_list_push(scratch.arena, &msg->user_bps, &ctrl_user_bp); } } diff --git a/src/dbg_engine/dbg_engine_core.h b/src/dbg_engine/dbg_engine_core.h index f39bbde7..042ffd3a 100644 --- a/src/dbg_engine/dbg_engine_core.h +++ b/src/dbg_engine/dbg_engine_core.h @@ -28,14 +28,24 @@ struct D_TargetArray U64 count; }; +typedef U32 D_BreakpointFlags; +enum +{ + D_BreakpointFlag_BreakOnWrite = (1<<0), + D_BreakpointFlag_BreakOnRead = (1<<1), + D_BreakpointFlag_BreakOnExecute = (1<<2), +}; + typedef struct D_Breakpoint D_Breakpoint; struct D_Breakpoint { + D_BreakpointFlags flags; + U64 id; String8 file_path; TxtPt pt; - String8 symbol_name; - U64 vaddr; + String8 vaddr_expr; String8 condition; + U64 size; }; typedef struct D_BreakpointArray D_BreakpointArray; @@ -89,6 +99,7 @@ struct D_Event CTRL_Handle thread; U64 vaddr; U64 code; + U64 id; }; typedef struct D_EventNode D_EventNode; @@ -158,42 +169,6 @@ D_RunKind; #include "dbg_engine/generated/dbg_engine.meta.h" -//////////////////////////////// -//~ rjf: View Rules - -typedef U32 D_ViewRuleSpecInfoFlags; // NOTE(rjf): see @view_rule_info -enum -{ - D_ViewRuleSpecInfoFlag_Inherited = (1<<0), - D_ViewRuleSpecInfoFlag_Expandable = (1<<1), - D_ViewRuleSpecInfoFlag_ExprResolution = (1<<2), - D_ViewRuleSpecInfoFlag_VizBlockProd = (1<<3), -}; - -typedef struct D_ViewRuleSpecInfo D_ViewRuleSpecInfo; -struct D_ViewRuleSpecInfo -{ - String8 string; - String8 display_string; - String8 schema; - String8 description; - D_ViewRuleSpecInfoFlags flags; -}; - -typedef struct D_ViewRuleSpecInfoArray D_ViewRuleSpecInfoArray; -struct D_ViewRuleSpecInfoArray -{ - D_ViewRuleSpecInfo *v; - U64 count; -}; - -typedef struct D_ViewRuleSpec D_ViewRuleSpec; -struct D_ViewRuleSpec -{ - D_ViewRuleSpec *hash_next; - D_ViewRuleSpecInfo info; -}; - //////////////////////////////// //~ rjf: Command Types @@ -240,35 +215,6 @@ struct D_CmdList //////////////////////////////// //~ rjf: Main State Caches -//- rjf: per-thread unwind cache - -typedef struct D_UnwindCacheNode D_UnwindCacheNode; -struct D_UnwindCacheNode -{ - D_UnwindCacheNode *next; - D_UnwindCacheNode *prev; - U64 reggen; - U64 memgen; - Arena *arena; - CTRL_Handle thread; - CTRL_Unwind unwind; -}; - -typedef struct D_UnwindCacheSlot D_UnwindCacheSlot; -struct D_UnwindCacheSlot -{ - D_UnwindCacheNode *first; - D_UnwindCacheNode *last; -}; - -typedef struct D_UnwindCache D_UnwindCache; -struct D_UnwindCache -{ - U64 slots_count; - D_UnwindCacheSlot *slots; - D_UnwindCacheNode *free_node; -}; - //- rjf: per-run tls-base-vaddr cache typedef struct D_RunTLSBaseCacheNode D_RunTLSBaseCacheNode; @@ -331,17 +277,15 @@ struct D_State // rjf: top-level state Arena *arena; U64 frame_index; - U64 frame_eval_memread_endt_us; // rjf: commands Arena *cmds_arena; D_CmdList cmds; // rjf: output log key - U128 output_log_key; + HS_Key output_log_key; // rjf: per-run caches - D_UnwindCache unwind_cache; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; D_RunTLSBaseCache tls_base_caches[2]; @@ -353,10 +297,6 @@ struct D_State D_RunLocalsCache member_caches[2]; U64 member_cache_gen; - // rjf: view rule specification table - U64 view_rule_spec_table_size; - D_ViewRuleSpec **view_rule_spec_table; - // rjf: user -> ctrl driving state Arena *ctrl_last_run_arena; D_RunKind ctrl_last_run_kind; @@ -373,7 +313,7 @@ struct D_State CTRL_MsgList ctrl_msgs; // rjf: ctrl -> user reading state - CTRL_EntityStore *ctrl_entity_store; + CTRL_EntityCtxRWStore *ctrl_entity_store; Arena *ctrl_stop_arena; CTRL_Event ctrl_last_stop_event; }; @@ -381,7 +321,6 @@ struct D_State //////////////////////////////// //~ rjf: Globals -read_only global D_ViewRuleSpec d_nil_core_view_rule_spec = {0}; global D_State *d_state = 0; //////////////////////////////// @@ -416,12 +355,6 @@ internal D_CmdParams d_cmd_params_copy(Arena *arena, D_CmdParams *src); //- rjf: command lists internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams *params); -//////////////////////////////// -//~ rjf: View Rule Spec Stateful Functions - -internal void d_register_view_rule_specs(D_ViewRuleSpecInfoArray specs); -internal D_ViewRuleSpec *d_view_rule_spec_from_string(String8 string); - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -432,13 +365,8 @@ internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: voff|vaddr -> symbol lookups -internal String8 d_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff, B32 decorated); -internal String8 d_symbol_name_from_process_vaddr(Arena *arena, CTRL_Entity *process, U64 vaddr, B32 decorated); - //- rjf: symbol -> voff lookups internal U64 d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name); -internal U64 d_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name); //- rjf: voff -> line info internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff); @@ -477,7 +405,6 @@ internal B32 d_ctrl_targets_running(void); internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena); //- rjf: per-run caches -internal CTRL_Unwind d_query_cached_unwind_from_thread(CTRL_Entity *thread); internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread); internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count); internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr); @@ -495,6 +422,6 @@ internal B32 d_next_cmd(D_Cmd **cmd); //~ rjf: Main Layer Top-Level Calls internal void d_init(void); -internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64], CTRL_MetaEvalArray *meta_evals); +internal D_EventList d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_PathMapArray *path_maps, U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]); #endif // DBG_ENGINE_CORE_H diff --git a/src/dbg_engine/generated/dbg_engine.meta.c b/src/dbg_engine/generated/dbg_engine.meta.c index 6d096e0b..3d32a4c2 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.c +++ b/src/dbg_engine/generated/dbg_engine.meta.c @@ -3,31 +3,3 @@ //- GENERATED CODE -C_LINKAGE_BEGIN -D_ViewRuleSpecInfo d_core_view_rule_spec_info_table[21] = -{ -{str8_lit_comp("default"), str8_lit_comp("Default"), str8_lit_comp(""), str8_lit_comp(""), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("array"), str8_lit_comp("Array"), str8_lit_comp("x:{expr}"), str8_lit_comp("Specifies that a pointer points to N elements, rather than only 1."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("slice"), str8_lit_comp("Slice"), str8_lit_comp(""), str8_lit_comp("Specifies that a pointer within a struct, also containing an integer, points to the number of elements encoded by the integer."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("list"), str8_lit_comp("List"), str8_lit_comp("x:{member}"), str8_lit_comp("Specifies that some struct, union, or class forms the top of a linked list, and the member which points at the following element in the list."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("bswap"), str8_lit_comp("Byte Swap"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should be byte-swapped, such that their endianness is reversed."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("cast"), str8_lit_comp("Cast"), str8_lit_comp("x:{type}"), str8_lit_comp("Specifies that the expression to which the view rule is applied should be casted to the provided type."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*1)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("dec"), str8_lit_comp("Decimal Base (Base 10)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-10 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("bin"), str8_lit_comp("Binary Base (Base 2)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-2 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("oct"), str8_lit_comp("Octal Base (Base 8)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-8 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("hex"), str8_lit_comp("Hexadecimal Base (Base 16)"), str8_lit_comp(""), str8_lit_comp("Specifies that all integral evaluations should appear in base-16 form."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("only"), str8_lit_comp("Only Specified Members"), str8_lit_comp("x:{member}"), str8_lit_comp("Specifies that only the specified members should appear in struct, union, or class evaluations."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("omit"), str8_lit_comp("Omit Specified Members"), str8_lit_comp("x:{member}"), str8_lit_comp("Omits a list of member names from appearing in struct, union, or class evaluations."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("no_addr"), str8_lit_comp("Disable Address Values"), str8_lit_comp(""), str8_lit_comp("Displays only what pointers point to, if possible, without the pointer's address value."), (D_ViewRuleSpecInfoFlag_Inherited*1)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("checkbox"), str8_lit_comp("Checkbox"), str8_lit_comp(""), str8_lit_comp("Displays simple integer values as checkboxes, encoding zero or nonzero values."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*0)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*0), }, -{str8_lit_comp("color_rgba"), str8_lit_comp("Color (RGBA)"), str8_lit_comp(""), str8_lit_comp("Displays as a color, interpreting the data as encoding R, G, B, and A values."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("text"), str8_lit_comp("Text"), str8_lit_comp("x:{'lang':lang, 'size':expr}"), str8_lit_comp("Displays as text."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), str8_lit_comp("x:{'arch':arch, 'size':expr}"), str8_lit_comp("Displays as disassembled instructions, interpreting the data as raw machine code."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("memory"), str8_lit_comp("Memory"), str8_lit_comp("x:{'size':expr}"), str8_lit_comp("Displays as a raw memory grid."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("graph"), str8_lit_comp("Graph"), str8_lit_comp(""), str8_lit_comp("Displays as a pointer graph, visualizing nodes and edges formed by pointers directly."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("bitmap"), str8_lit_comp("Bitmap"), str8_lit_comp("x:{'w':expr, 'h':expr, 'fmt':tex2dformat}"), str8_lit_comp("Displays as a bitmap, interpreting the data as raw pixel data."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -{str8_lit_comp("geo3d"), str8_lit_comp("Geometry (3D)"), str8_lit_comp("x:{'count':expr, 'vtx':expr, 'vtx_size':expr}"), str8_lit_comp("Displays as geometry, interpreting the data as index or vertex data."), (D_ViewRuleSpecInfoFlag_Inherited*0)|(D_ViewRuleSpecInfoFlag_Expandable*1)|(D_ViewRuleSpecInfoFlag_ExprResolution*0)|(D_ViewRuleSpecInfoFlag_VizBlockProd*1), }, -}; - -C_LINKAGE_END - diff --git a/src/dbg_engine/generated/dbg_engine.meta.h b/src/dbg_engine/generated/dbg_engine.meta.h index d129e3d2..8451a246 100644 --- a/src/dbg_engine/generated/dbg_engine.meta.h +++ b/src/dbg_engine/generated/dbg_engine.meta.h @@ -10,7 +10,7 @@ typedef enum D_CmdKind { D_CmdKind_Null, D_CmdKind_LaunchAndRun, -D_CmdKind_LaunchAndInit, +D_CmdKind_LaunchAndStepInto, D_CmdKind_Kill, D_CmdKind_KillAll, D_CmdKind_Detach, @@ -24,7 +24,6 @@ D_CmdKind_Halt, D_CmdKind_SoftHaltRefresh, D_CmdKind_SetThreadIP, D_CmdKind_RunToLine, -D_CmdKind_RunToAddress, D_CmdKind_Run, D_CmdKind_Restart, D_CmdKind_StepInto, @@ -45,32 +44,6 @@ D_CmdKind_Attach, D_CmdKind_COUNT, } D_CmdKind; -typedef enum D_ViewRuleKind -{ -D_ViewRuleKind_Default, -D_ViewRuleKind_Array, -D_ViewRuleKind_Slice, -D_ViewRuleKind_List, -D_ViewRuleKind_ByteSwap, -D_ViewRuleKind_Cast, -D_ViewRuleKind_BaseDec, -D_ViewRuleKind_BaseBin, -D_ViewRuleKind_BaseOct, -D_ViewRuleKind_BaseHex, -D_ViewRuleKind_Only, -D_ViewRuleKind_Omit, -D_ViewRuleKind_NoAddr, -D_ViewRuleKind_Checkbox, -D_ViewRuleKind_ColorRGBA, -D_ViewRuleKind_Text, -D_ViewRuleKind_Disasm, -D_ViewRuleKind_Memory, -D_ViewRuleKind_Graph, -D_ViewRuleKind_Bitmap, -D_ViewRuleKind_Geo3D, -D_ViewRuleKind_COUNT, -} D_ViewRuleKind; - global B32 DEV_simulate_lag = 0; global B32 DEV_draw_ui_text_pos = 0; global B32 DEV_draw_ui_focus_debug = 0; @@ -78,7 +51,6 @@ global B32 DEV_draw_ui_box_heatmap = 0; global B32 DEV_eval_compiler_tooltips = 0; global B32 DEV_eval_watch_key_tooltips = 0; global B32 DEV_cmd_context_tooltips = 0; -global B32 DEV_scratch_mouse_draw = 0; global B32 DEV_updating_indicator = 0; struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = { @@ -89,7 +61,6 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = {&DEV_eval_compiler_tooltips, str8_lit_comp("eval_compiler_tooltips")}, {&DEV_eval_watch_key_tooltips, str8_lit_comp("eval_watch_key_tooltips")}, {&DEV_cmd_context_tooltips, str8_lit_comp("cmd_context_tooltips")}, -{&DEV_scratch_mouse_draw, str8_lit_comp("scratch_mouse_draw")}, {&DEV_updating_indicator, str8_lit_comp("updating_indicator")}, }; #endif // DBG_ENGINE_META_H diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 063be596..96f0b480 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0x7c4ce3ff + //////////////////////////////// //~ rjf: Basic Helpers @@ -262,22 +265,26 @@ di_scope_open(void) scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); } MemoryZeroStruct(scope); + DLLPushBack(di_tctx->first_scope, di_tctx->last_scope, scope); return scope; } internal void di_scope_close(DI_Scope *scope) { + DLLRemove(di_tctx->first_scope, di_tctx->last_scope, scope); for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) { next = t->next; if(t->node != 0) { ins_atomic_u64_dec_eval(&t->node->touch_count); + os_condition_variable_broadcast(t->stripe->cv); } if(t->search_node != 0) { ins_atomic_u64_dec_eval(&t->search_node->scope_refcount); + os_condition_variable_broadcast(t->search_stripe->cv); } SLLStackPush(di_tctx->free_touch, t); } @@ -285,7 +292,7 @@ di_scope_close(DI_Scope *scope) } internal void -di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) +di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Stripe *stripe, DI_Node *node) { if(node != 0) { @@ -303,10 +310,11 @@ di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) MemoryZeroStruct(touch); SLLQueuePush(scope->first_touch, scope->last_touch, touch); touch->node = node; + touch->stripe = stripe; } internal void -di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchNode *node) +di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchStripe *stripe, DI_SearchNode *node) { if(node != 0) { @@ -324,6 +332,7 @@ di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchNod MemoryZeroStruct(touch); SLLQueuePush(scope->first_touch, scope->last_touch, touch); touch->search_node = node; + touch->search_stripe = stripe; } //////////////////////////////// @@ -522,6 +531,7 @@ di_close(DI_Key *key) DI_Slot *slot = &di_shared->slots[slot_idx]; DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; log_infof("close_debug_info: {\"%S\", 0x%I64x}\n", key_normalized.path, key_normalized.min_timestamp); + B32 closed = 0; OS_MutexScopeW(stripe->rw_mutex) { //- rjf: find existing node @@ -533,16 +543,8 @@ di_close(DI_Key *key) node->ref_count -= 1; if(node->ref_count == 0) for(;;) { - //- rjf: wait for touch count to go to 0 - if(ins_atomic_u64_eval(&node->touch_count) != 0) - { - os_rw_mutex_drop_w(stripe->rw_mutex); - for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); - os_rw_mutex_take_w(stripe->rw_mutex); - } - //- rjf: release - if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) + if(ins_atomic_u64_eval(&node->touch_count) == 0) { di_string_release__stripe_mutex_w_guarded(stripe, node->key.path); if(node->file_base != 0) @@ -565,6 +567,9 @@ di_close(DI_Key *key) SLLStackPush(stripe->free_node, node); break; } + + //- rjf: wait for touch count to go to 0 + os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, max_U64); } } } @@ -580,7 +585,7 @@ internal RDI_Parsed * di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us) { ProfBeginFunction(); - RDI_Parsed *result = &di_rdi_parsed_nil; + RDI_Parsed *result = &rdi_parsed_nil; if(key->path.size != 0) { Temp scratch = scratch_begin(0, 0); @@ -610,7 +615,7 @@ di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us) //- rjf: parse done -> touch, grab result if(node != 0 && node->parse_done) { - di_scope_touch_node__stripe_mutex_r_guarded(scope, node); + di_scope_touch_node__stripe_mutex_r_guarded(scope, stripe, node); result = &node->rdi; break; } @@ -702,12 +707,11 @@ di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams B32 params_stale = 1; B32 query_stale = 1; B32 results_stale = 1; - if(params_hash == node->buckets[node->bucket_read_gen%ArrayCount(node->buckets)].params_hash && - node->bucket_read_gen != 0) + if(node->bucket_read_gen != 0) { - di_scope_touch_search_node__stripe_mutex_r_guarded(scope, node); + di_scope_touch_search_node__stripe_mutex_r_guarded(scope, stripe, node); items = node->items; - params_stale = 0; + params_stale = (params_hash != node->buckets[node->bucket_read_gen%ArrayCount(node->buckets)].params_hash); query_stale = !str8_match(query, node->buckets[node->bucket_read_gen%ArrayCount(node->buckets)].query, 0); results_stale = (node->bucket_read_gen < node->bucket_write_gen); } @@ -716,8 +720,8 @@ di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *stale_out = (params_stale || query_stale || results_stale); } - // rjf: if query stale -> request again - if(query_stale && node->bucket_read_gen <= node->bucket_write_gen && node->bucket_write_gen < node->bucket_read_gen + ArrayCount(node->buckets)-1) + // rjf: if query or params stale -> request again + if((query_stale || params_stale) && node->bucket_read_gen <= node->bucket_write_gen && node->bucket_write_gen < node->bucket_read_gen + ArrayCount(node->buckets)-1) { node->bucket_write_gen += 1; if(node->bucket_write_gen >= node->bucket_items_gen + ArrayCount(node->buckets)) @@ -1084,7 +1088,7 @@ ASYNC_WORK_DEF(di_parse_work) //////////////////////////// //- rjf: do initial parse of rdi // - RDI_Parsed rdi_parsed_maybe_compressed = di_rdi_parsed_nil; + RDI_Parsed rdi_parsed_maybe_compressed = rdi_parsed_nil; { RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); (void)parse_status; @@ -1349,7 +1353,6 @@ di_search_thread__entry_point(void *p) for(;;) { Temp scratch = scratch_begin(0, 0); - DI_Scope *di_scope = di_scope_open(); //- rjf: get next key, unpack U128 key = di_u2s_dequeue_req(thread_idx); @@ -1380,6 +1383,9 @@ di_search_thread__entry_point(void *p) } } + //- rjf: begin debug info scope + DI_Scope *di_scope = di_scope_open(); + //- rjf: get all rdis U64 rdis_count = params.dbgi_keys.count; RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); @@ -1428,6 +1434,9 @@ di_search_thread__entry_point(void *p) cancelled = (cancelled || out->cancelled); } + //- rjf: end debug info scope + di_scope_close(di_scope); + //- rjf: list -> array DI_SearchItemArray items = {0}; if(arena != 0 && !cancelled) @@ -1464,13 +1473,14 @@ di_search_thread__entry_point(void *p) quick_sort(items.v, items.count, sizeof(DI_SearchItem), di_qsort_compare_search_items); } - //- rjf: commit to cache - busyloop on scope touches + //- rjf: commit to cache - wait on scope touches if(arena != 0) { - for(B32 done = 0; !done;) + OS_MutexScopeW(stripe->rw_mutex) for(;;) { B32 found = 0; - OS_MutexScopeW(stripe->rw_mutex) for(DI_SearchNode *n = slot->first; n != 0; n = n->next) + B32 done = 0; + for(DI_SearchNode *n = slot->first; n != 0; n = n->next) { if(u128_match(n->key, key)) { @@ -1489,14 +1499,17 @@ di_search_thread__entry_point(void *p) break; } } - if(!found) + if((found && done) || !found) { break; } + if(found && !done) + { + os_condition_variable_wait_rw_w(stripe->cv, stripe->rw_mutex, os_now_microseconds()+1000); + } } } - di_scope_close(di_scope); scratch_end(scratch); } } diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 3b3b23ea..ca8b8e77 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -218,13 +218,16 @@ struct DI_Touch { DI_Touch *next; DI_Node *node; + DI_Stripe *stripe; DI_SearchNode *search_node; + DI_SearchStripe *search_stripe; }; typedef struct DI_Scope DI_Scope; struct DI_Scope { DI_Scope *next; + DI_Scope *prev; DI_Touch *first_touch; DI_Touch *last_touch; }; @@ -233,6 +236,8 @@ typedef struct DI_TCTX DI_TCTX; struct DI_TCTX { Arena *arena; + DI_Scope *first_scope; + DI_Scope *last_scope; DI_Scope *free_scope; DI_Touch *free_touch; }; @@ -376,7 +381,6 @@ struct DI_Shared global DI_Shared *di_shared = 0; thread_static DI_TCTX *di_tctx = 0; -global RDI_Parsed di_rdi_parsed_nil = {0}; //////////////////////////////// //~ rjf: Basic Helpers @@ -407,8 +411,8 @@ 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); +internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Stripe *stripe, DI_Node *node); +internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchStripe *stripe, DI_SearchNode *node); //////////////////////////////// //~ rjf: Per-Slot Functions diff --git a/src/demon/demon_core.h b/src/demon/demon_core.h index 32ef28a0..94f8d8c3 100644 --- a/src/demon/demon_core.h +++ b/src/demon/demon_core.h @@ -73,7 +73,7 @@ struct DMN_Event U64 size; String8 string; U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully) - U32 flags; + U32 flags; // DMN_TrapFlags, if `DMN_EventKind_SetBreakpoint` S32 signo; S32 sigcode; U64 instruction_pointer; @@ -100,12 +100,22 @@ struct DMN_EventList //////////////////////////////// //~ rjf: Run Control Types +typedef U32 DMN_TrapFlags; +enum +{ + DMN_TrapFlag_BreakOnWrite = (1<<0), + DMN_TrapFlag_BreakOnRead = (1<<1), + DMN_TrapFlag_BreakOnExecute = (1<<2), +}; + typedef struct DMN_Trap DMN_Trap; struct DMN_Trap { DMN_Handle process; U64 vaddr; U64 id; + DMN_TrapFlags flags; + U32 size; }; typedef struct DMN_TrapChunkNode DMN_TrapChunkNode; diff --git a/src/demon/demon_core.mdesk b/src/demon/demon_core.mdesk index 1ccc3c14..3c9a367e 100644 --- a/src/demon/demon_core.mdesk +++ b/src/demon/demon_core.mdesk @@ -21,6 +21,9 @@ DMN_EventKindTable: {Memory} {DebugString} {SetThreadName} + {SetThreadColor} + {SetBreakpoint} + {UnsetBreakpoint} } @table(name) diff --git a/src/demon/generated/demon.meta.c b/src/demon/generated/demon.meta.c index 69511785..47406944 100644 --- a/src/demon/generated/demon.meta.c +++ b/src/demon/generated/demon.meta.c @@ -4,7 +4,7 @@ //- GENERATED CODE C_LINKAGE_BEGIN -String8 dmn_event_kind_string_table[17] = +String8 dmn_event_kind_string_table[20] = { str8_lit_comp("Null"), str8_lit_comp("Error"), @@ -23,6 +23,9 @@ str8_lit_comp("Halt"), str8_lit_comp("Memory"), str8_lit_comp("DebugString"), str8_lit_comp("SetThreadName"), +str8_lit_comp("SetThreadColor"), +str8_lit_comp("SetBreakpoint"), +str8_lit_comp("UnsetBreakpoint"), }; String8 dmn_exception_kind_string_table[5] = diff --git a/src/demon/generated/demon.meta.h b/src/demon/generated/demon.meta.h index 3b73d40b..4a8b5b80 100644 --- a/src/demon/generated/demon.meta.h +++ b/src/demon/generated/demon.meta.h @@ -25,6 +25,9 @@ DMN_EventKind_Halt, DMN_EventKind_Memory, DMN_EventKind_DebugString, DMN_EventKind_SetThreadName, +DMN_EventKind_SetThreadColor, +DMN_EventKind_SetBreakpoint, +DMN_EventKind_UnsetBreakpoint, DMN_EventKind_COUNT, } DMN_EventKind; @@ -58,7 +61,7 @@ DMN_ExceptionKind_COUNT, } DMN_ExceptionKind; C_LINKAGE_BEGIN -extern String8 dmn_event_kind_string_table[17]; +extern String8 dmn_event_kind_string_table[20]; extern String8 dmn_exception_kind_string_table[5]; C_LINKAGE_END diff --git a/src/demon/linux/demon_core_linux.c b/src/demon/linux/demon_core_linux.c index 861c21d3..ffa705af 100644 --- a/src/demon/linux/demon_core_linux.c +++ b/src/demon/linux/demon_core_linux.c @@ -15,6 +15,8 @@ dmn_init(void) internal DMN_CtrlCtx * dmn_ctrl_begin(void) { + DMN_CtrlCtx *ctx = (DMN_CtrlCtx *)1; + return ctx; } internal void @@ -30,26 +32,32 @@ dmn_ctrl_exclusive_access_end(void) internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params) { + return 0; } internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) { + return 0; } internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) { + return 0; } internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) { + return 0; } internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { + DMN_EventList evts = {0}; + return evts; } //////////////////////////////// @@ -68,16 +76,19 @@ dmn_halt(U64 code, U64 user_data) internal U64 dmn_run_gen(void) { + return 0; } internal U64 dmn_mem_gen(void) { + return 0; } internal U64 dmn_reg_gen(void) { + return 0; } //- rjf: non-blocking-control-thread access barriers @@ -85,6 +96,7 @@ dmn_reg_gen(void) internal B32 dmn_access_open(void) { + return 0; } internal void @@ -97,6 +109,7 @@ dmn_access_close(void) internal U64 dmn_process_memory_reserve(DMN_Handle process, U64 vaddr, U64 size) { + return 0; } internal void @@ -122,11 +135,13 @@ dmn_process_memory_protect(DMN_Handle process, U64 vaddr, U64 size, OS_AccessFla internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst) { + return 0; } internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) { + return 0; } //- rjf: threads @@ -134,26 +149,31 @@ dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) internal Arch dmn_arch_from_thread(DMN_Handle handle) { + return Arch_Null; } internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle) { + return 0; } internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle) { + return 0; } internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block) { + return 0; } internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) { + return 0; } //- rjf: system process listing @@ -166,6 +186,7 @@ dmn_process_iter_begin(DMN_ProcessIter *iter) internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out) { + return 0; } internal void diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c index 1ac146b0..d9fe31df 100644 --- a/src/demon/win32/demon_core_win32.c +++ b/src/demon/win32/demon_core_win32.c @@ -56,16 +56,17 @@ dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id) // rjf: allocate DMN_W32_Entity *e = dmn_w32_shared->entities_first_free; { + U32 gen = 0; if(e != 0) { SLLStackPop(dmn_w32_shared->entities_first_free); + gen = e->gen; } else { e = push_array_no_zero(dmn_w32_shared->entities_arena, DMN_W32_Entity, 1); dmn_w32_shared->entities_count += 1; } - U32 gen = e->gen; MemoryZeroStruct(e); e->gen = gen+1; } @@ -155,6 +156,7 @@ dmn_w32_entity_release(DMN_W32_Entity *entity) { CloseHandle(t->e->handle); } + t->e->kind = DMN_W32_EntityKind_Null; // rjf: remove from id -> entity map if(t->e->id != 0) @@ -469,9 +471,9 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) } // rjf: get COFF header - B32 got_file_header = 0; - U64 file_header_off = 0; - COFF_FileHeader file_header = {0}; + B32 got_coff_header = 0; + U64 coff_header_off = 0; + COFF_FileHeader coff_header = {0}; if(pe_offset > 0) { U64 pe_magic_off = base_vaddr + pe_offset; @@ -479,28 +481,28 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); if(pe_magic == PE_MAGIC) { - file_header_off = pe_magic_off + sizeof(pe_magic); - if(dmn_w32_process_read_struct(process, file_header_off, &file_header)) + coff_header_off = pe_magic_off + sizeof(pe_magic); + if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header)) { - got_file_header = 1; + got_coff_header = 1; } } } // rjf: get arch and size DMN_W32_ImageInfo result = zero_struct; - if(got_file_header) + if(got_coff_header) { U64 optional_size_off = 0; Arch arch = Arch_Null; - switch(file_header.machine) + switch(coff_header.machine) { - case COFF_Machine_X86: + case COFF_MachineType_X86: { arch = Arch_x86; optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image); }break; - case COFF_Machine_X64: + case COFF_MachineType_X64: { arch = Arch_x64; optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); @@ -510,7 +512,7 @@ dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) } if(arch != Arch_Null) { - U64 optional_off = file_header_off + sizeof(COFF_FileHeader); + U64 optional_off = coff_header_off + sizeof(coff_header); U32 size = 0; if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size)) { @@ -749,12 +751,12 @@ dmn_w32_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block) dst->fs.u16 = ctx->SegFs; dst->gs.u16 = ctx->SegGs; dst->ss.u16 = ctx->SegSs; - dst->dr0.u32 = ctx->Dr0; - dst->dr1.u32 = ctx->Dr1; - dst->dr2.u32 = ctx->Dr2; - dst->dr3.u32 = ctx->Dr3; - dst->dr6.u32 = ctx->Dr6; - dst->dr7.u32 = ctx->Dr7; + dst->dr0.u64 = ctx->Dr0; + dst->dr1.u64 = ctx->Dr1; + dst->dr2.u64 = ctx->Dr2; + dst->dr3.u64 = ctx->Dr3; + dst->dr6.u64 = ctx->Dr6; + dst->dr7.u64 = ctx->Dr7; // NOTE(rjf): this bit is "supposed to always be 1", according to old info. // may need to be investigated. dst->rflags.u64 = ctx->EFlags | 0x2; @@ -1020,12 +1022,12 @@ dmn_w32_thread_write_reg_block(Arch arch, HANDLE thread, void *reg_block) ctx->SegFs = src->fs.u16; ctx->SegGs = src->gs.u16; ctx->SegSs = src->ss.u16; - ctx->Dr0 = src->dr0.u32; - ctx->Dr1 = src->dr1.u32; - ctx->Dr2 = src->dr2.u32; - ctx->Dr3 = src->dr3.u32; - ctx->Dr6 = src->dr6.u32; - ctx->Dr7 = src->dr7.u32; + ctx->Dr0 = src->dr0.u64; + ctx->Dr1 = src->dr1.u64; + ctx->Dr2 = src->dr2.u64; + ctx->Dr3 = src->dr3.u64; + ctx->Dr6 = src->dr6.u64; + ctx->Dr7 = src->dr7.u64; ctx->EFlags = src->rflags.u64; fxsave->ControlWord = src->fcw.u16; fxsave->StatusWord = src->fsw.u16; @@ -1291,7 +1293,6 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params) inherit_handles = 1; } PROCESS_INFORMATION process_info = {0}; - AllocConsole(); if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, creation_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) { // check if we are 32-bit app, and just close it immediately @@ -1313,15 +1314,13 @@ dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_ProcessLaunchParams *params) } else { - MessageBox(0, "Error starting process.", "Process error", MB_OK|MB_ICONSTOP); - } - FreeConsole(); - - //- rjf: eliminate all handles which have stuck around from the AllocConsole - { - SetStdHandle(STD_INPUT_HANDLE, 0); - SetStdHandle(STD_OUTPUT_HANDLE, 0); - SetStdHandle(STD_ERROR_HANDLE, 0); + DWORD error = GetLastError(); + LPWSTR message = 0; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), (LPWSTR)&message, 0, 0); + String8 message8 = message ? str8_from_16(scratch.arena, str16_cstring(message)) : str8_lit("unknown error"); + LocalFree(message); + + log_user_errorf("There was an error starting %S: %S", params->cmd_line.first->string, message8); } } scratch_end(scratch); @@ -1560,10 +1559,161 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, trap_idx += 1) { DMN_Trap *trap = n->v+n_idx; - trap_swap_bytes[trap_idx] = 0xCC; - dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr+1), trap_swap_bytes+trap_idx); - U8 int3 = 0xCC; - dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &int3); + if(trap->flags == 0) + { + trap_swap_bytes[trap_idx] = 0xCC; + dmn_process_read(trap->process, r1u64(trap->vaddr, trap->vaddr+1), trap_swap_bytes+trap_idx); + U8 int3 = 0xCC; + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &int3); + } + } + } + } + + ////////////////////////// + //- rjf: gather all flagged traps, bucketed by process + // + typedef struct DMN_FlaggedTrapTask DMN_FlaggedTrapTask; + struct DMN_FlaggedTrapTask + { + DMN_FlaggedTrapTask *next; + DMN_Handle process; + DMN_TrapChunkList traps; + }; + DMN_FlaggedTrapTask *first_flagged_trap_task = 0; + DMN_FlaggedTrapTask *last_flagged_trap_task= 0; + for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next) + { + for(U64 n_idx = 0; n_idx < n->count; n_idx += 1) + { + DMN_Trap *trap = n->v+n_idx; + if(trap->flags != 0) + { + DMN_FlaggedTrapTask *task = 0; + for(DMN_FlaggedTrapTask *t = first_flagged_trap_task; t != 0; t = t->next) + { + if(dmn_handle_match(t->process, trap->process)) + { + task = t; + break; + } + } + if(task == 0) + { + task = push_array(scratch.arena, DMN_FlaggedTrapTask, 1); + SLLQueuePush(first_flagged_trap_task, last_flagged_trap_task, task); + task->process = trap->process; + } + B32 already_in_task = 0; + for(DMN_TrapChunkNode *n = task->traps.first; n != 0; n = n->next) + { + for(U64 n_idx = 0; n_idx < n->count; n_idx += 1) + { + if(n->v[n_idx].id == trap->id) + { + already_in_task = 1; + goto end_look_for_existing_trap_in_task; + } + } + } + end_look_for_existing_trap_in_task:; + if(!already_in_task) + { + dmn_trap_chunk_list_push(scratch.arena, &task->traps, 8, trap); + } + } + } + } + + ////////////////////////// + //- rjf: write all debug register states, for flagged-traps + // + ProfScope("write all debug register states, for flagged-traps") + { + //- rjf: for each flagged trap task, iterate all threads in the + // associated process, and prepare debug registers accordingly + for(DMN_FlaggedTrapTask *t = first_flagged_trap_task; t != 0; t = t->next) + { + DMN_Handle process = t->process; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Thread) + { + switch(child->arch) + { + default:{}break; + + //- rjf: x64 + case Arch_x64: + { + REGS_RegBlockX64 regs = {0}; + dmn_w32_thread_read_reg_block(child->arch, child->handle, ®s); + { + U64 trap_idx = 0; + for(DMN_TrapChunkNode *n = t->traps.first; n != 0; n = n->next) + { + for(U64 n_idx = 0; n_idx < n->count && trap_idx < 4; n_idx += 1, trap_idx += 1) + { + DMN_Trap *trap = &n->v[n_idx]; + REGS_Reg64 *addr_reg = ®s.dr0; + switch(trap_idx) + { + default:{}break; + case 0:{addr_reg = ®s.dr0;}break; + case 1:{addr_reg = ®s.dr1;}break; + case 2:{addr_reg = ®s.dr2;}break; + case 3:{addr_reg = ®s.dr3;}break; + } + addr_reg->u64 = trap->vaddr; + regs.dr7.u64 |= bit9|bit10|bit11; + regs.dr7.u64 |= (1ull << (trap_idx*2)); + // NOTE(rjf): global-enable regs.dr7.u64 |= (1ull << (trap_idx*2+1)); + regs.dr7.u64 &= ~((U64)(bit17|bit18|bit19|bit20) << (trap_idx*4)); + regs.dr7.u64 &= ~((U64)(bit15|bit16)); + switch(trap->flags) + { + case DMN_TrapFlag_BreakOnExecute: + default:{}break; + case DMN_TrapFlag_BreakOnWrite: + case DMN_TrapFlag_BreakOnWrite|DMN_TrapFlag_BreakOnExecute: + { + regs.dr7.u64 |= ((U64)bit17) << (trap_idx*4); + }break; + case DMN_TrapFlag_BreakOnRead|DMN_TrapFlag_BreakOnWrite|DMN_TrapFlag_BreakOnExecute: + case DMN_TrapFlag_BreakOnRead|DMN_TrapFlag_BreakOnWrite: + { + regs.dr7.u64 |= (((U64)bit17) << (trap_idx*4)); + regs.dr7.u64 |= (((U64)bit18) << (trap_idx*4)); + }break; + } + switch(trap->size) + { + case 1: + default:{}break; + case 2: + { + regs.dr7.u64 |= (((U64)bit19) << (trap_idx*4)); + }break; + case 4: + { + regs.dr7.u64 |= (((U64)bit19) << (trap_idx*4)); + regs.dr7.u64 |= (((U64)bit20) << (trap_idx*4)); + }break; + case 8: + { + regs.dr7.u64 |= (((U64)bit20) << (trap_idx*4)); + }break; + } + } + } + } + dmn_w32_thread_write_reg_block(child->arch, child->handle, ®s); + }break; + } + } } } } @@ -1721,6 +1871,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { dmn_w32_shared->resume_needed = 0; resume_good = !!ContinueDebugEvent(dmn_w32_shared->resume_pid, dmn_w32_shared->resume_tid, resume_code); + DWORD error = GetLastError(); dmn_w32_shared->resume_needed = 0; dmn_w32_shared->resume_tid = 0; dmn_w32_shared->resume_pid = 0; @@ -1736,6 +1887,8 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } else { + DWORD err = GetLastError(); + (void)err; keep_going = 1; } ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen); @@ -1843,6 +1996,15 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) { DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + // rjf: if this was the process we were going to resume, then we will + // just not resume, and wait for another debug event + if(evt.dwProcessId == dmn_w32_shared->resume_pid) + { + dmn_w32_shared->resume_needed = 0; + dmn_w32_shared->resume_tid = 0; + dmn_w32_shared->resume_pid = 0; + } + // rjf: generate events for children for(DMN_W32_Entity *child = process->first; child != &dmn_w32_entity_nil; child = child->next) { @@ -1948,6 +2110,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) e->kind = DMN_EventKind_Halt; dmn_w32_shared->halter_process = dmn_handle_zero(); dmn_w32_shared->halter_tid = 0; + keep_going = 0; } // rjf: if this thread is *not* the halter, then generate a regular exit-thread event @@ -2089,6 +2252,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) //- rjf: check if this trap is a usage-code-specified trap or something else B32 hit_user_trap = 0; + U64 user_trap_id = 0; if(is_trap) { for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next) @@ -2098,6 +2262,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) if(dmn_handle_match(n->v[idx].process, dmn_w32_handle_from_entity(process)) && n->v[idx].vaddr == instruction_pointer) { hit_user_trap = 1; + user_trap_id = n->v[idx].id; break; } } @@ -2186,6 +2351,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) e->code = exception->ExceptionCode; e->flags = exception->ExceptionFlags; e->instruction_pointer = (U64)exception->ExceptionAddress; + e->user_data = user_trap_id; //- rjf: fill according to exception code switch(exception->ExceptionCode) @@ -2215,6 +2381,72 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) case DMN_W32_EXCEPTION_SINGLE_STEP: { e->kind = DMN_EventKind_SingleStep; + + // NOTE(rjf): data breakpoints are reported via single-steps + // over the instructions which caused the breakpoint to be + // hit - so if we have data breakpoints set, we need to + // check this thread's debug registers, to determine if this + // is a regular single-step or a data breakpoint hit. + if(first_flagged_trap_task != 0) + { + // rjf: first determine the flagged trap index + U64 flagged_trap_idx = 0; + switch(thread->arch) + { + default:{NotImplemented;}break; + case Arch_x64: + { + REGS_RegBlockX64 regs = {0}; + dmn_w32_thread_read_reg_block(thread->arch, thread->handle, ®s); + if(regs.dr6.u64 & 0xF) + { + e->kind = DMN_EventKind_Breakpoint; + if(0){} + else if(regs.dr7.u64 & (1ull<<0) && regs.dr6.u64 & (1ull<<0)) { flagged_trap_idx = 0; } + else if(regs.dr7.u64 & (1ull<<2) && regs.dr6.u64 & (1ull<<1)) { flagged_trap_idx = 1; } + else if(regs.dr7.u64 & (1ull<<4) && regs.dr6.u64 & (1ull<<2)) { flagged_trap_idx = 2; } + else if(regs.dr7.u64 & (1ull<<8) && regs.dr6.u64 & (1ull<<3)) { flagged_trap_idx = 3; } + } + }break; + } + + // rjf: find the flagged trap task for this thread's process + DMN_W32_Entity *process = thread->parent; + DMN_FlaggedTrapTask *task = 0; + for(DMN_FlaggedTrapTask *t = first_flagged_trap_task; t != 0; t = t->next) + { + if(dmn_handle_match(t->process, dmn_w32_handle_from_entity(process))) + { + task = t; + break; + } + } + + // rjf: find the trap + DMN_Trap *trap = 0; + if(task != 0) + { + U64 trap_idx = 0; + for(DMN_TrapChunkNode *n = task->traps.first; n != 0; n = n->next) + { + for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, trap_idx += 1) + { + if(trap_idx == flagged_trap_idx) + { + trap = &n->v[n_idx]; + goto break_search_for_flagged_trap; + } + } + } + break_search_for_flagged_trap:; + } + + // rjf: fill event based on trap + if(trap != 0) + { + e->user_data = trap->id; + } + } }break; //- rjf: fill throw info @@ -2303,6 +2535,31 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } }break; + //- rjf: fill set-thread-color info + case DMN_W32_EXCEPTION_RADDBG_SET_THREAD_COLOR: + { + e->kind = DMN_EventKind_SetThreadColor; + e->code = exception->ExceptionInformation[0]; + e->user_data = exception->ExceptionInformation[1]; + }break; + + //- rjf: fill set-data-breakpoint info + case DMN_W32_EXCEPTION_RADDBG_SET_BREAKPOINT: + { + U64 vaddr = exception->ExceptionInformation[0]; + U64 size = exception->ExceptionInformation[1]; + U64 read = exception->ExceptionInformation[2]; + U64 write = exception->ExceptionInformation[3]; + U64 exec = exception->ExceptionInformation[4]; + U64 set = exception->ExceptionInformation[5]; + e->kind = set ? DMN_EventKind_SetBreakpoint : DMN_EventKind_UnsetBreakpoint; + e->address = vaddr; + e->size = size; + if(read) { e->flags |= DMN_TrapFlag_BreakOnRead; } + if(write) { e->flags |= DMN_TrapFlag_BreakOnWrite; } + if(exec) { e->flags |= DMN_TrapFlag_BreakOnExecute; } + }break; + //- rjf: unhandled exception case default: { @@ -2400,6 +2657,10 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next) { DMN_W32_Entity *thread = n->v; + if(thread->kind != DMN_W32_EntityKind_Thread) + { + continue; + } DWORD suspend_result = SuspendThread(thread->handle); switch(suspend_result) { @@ -2428,7 +2689,9 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) } } + //////////////////////// //- rjf: gather new thread-names + // ProfScope("gather new thread names") if(dmn_w32_GetThreadDescription != 0) { for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; @@ -2481,10 +2744,46 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) for(U64 n_idx = 0; n_idx < n->count; n_idx += 1, trap_idx += 1) { DMN_Trap *trap = n->v+n_idx; - U8 og_byte = trap_swap_bytes[trap_idx]; - if(og_byte != 0xCC) + if(trap->flags == 0) { - dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &og_byte); + U8 og_byte = trap_swap_bytes[trap_idx]; + if(og_byte != 0xCC) + { + dmn_process_write(trap->process, r1u64(trap->vaddr, trap->vaddr+1), &og_byte); + } + } + } + } + } + + ////////////////////////// + //- rjf: clear all debug register states, for flagged-traps + // + ProfScope("clear all debug register states, for flagged-traps") + { + for(DMN_FlaggedTrapTask *t = first_flagged_trap_task; t != 0; t = t->next) + { + DMN_Handle process = t->process; + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Thread) + { + switch(child->arch) + { + default:{}break; + + //- rjf: x64 + case Arch_x64: + { + REGS_RegBlockX64 regs = {0}; + dmn_w32_thread_read_reg_block(child->arch, child->handle, ®s); + regs.dr7.u64 = 0; + dmn_w32_thread_write_reg_block(child->arch, child->handle, ®s); + }break; + } } } } diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h index c7234571..05483e26 100644 --- a/src/demon/win32/demon_core_win32.h +++ b/src/demon/win32/demon_core_win32.h @@ -15,47 +15,49 @@ //////////////////////////////// //~ rjf: Win32 Exception Codes -#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DMN_W32_EXCEPTION_THROW 0xE06D7363u -#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u -#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u -#define DMN_w32_EXCEPTION_CLR 0xE0434352u +#define DMN_W32_EXCEPTION_BREAKPOINT 0x80000003u +#define DMN_W32_EXCEPTION_SINGLE_STEP 0x80000004u +#define DMN_W32_EXCEPTION_LONG_JUMP 0x80000026u +#define DMN_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u +#define DMN_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu +#define DMN_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u +#define DMN_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u +#define DMN_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du +#define DMN_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu +#define DMN_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu +#define DMN_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u +#define DMN_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u +#define DMN_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u +#define DMN_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u +#define DMN_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u +#define DMN_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u +#define DMN_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u +#define DMN_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du +#define DMN_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u +#define DMN_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u +#define DMN_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u +#define DMN_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu +#define DMN_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u +#define DMN_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u +#define DMN_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u +#define DMN_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u +#define DMN_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u +#define DMN_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u +#define DMN_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au +#define DMN_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u +#define DMN_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u +#define DMN_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u +#define DMN_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u +#define DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u +#define DMN_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u +#define DMN_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u +#define DMN_W32_EXCEPTION_NO_MEMORY 0xC0000017u +#define DMN_W32_EXCEPTION_THROW 0xE06D7363u +#define DMN_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u +#define DMN_w32_EXCEPTION_CLRDBG_NOTIFICATION 0x04242420u +#define DMN_w32_EXCEPTION_CLR 0xE0434352u +#define DMN_W32_EXCEPTION_RADDBG_SET_THREAD_COLOR 0x00524144u +#define DMN_W32_EXCEPTION_RADDBG_SET_BREAKPOINT 0x00524145u //////////////////////////////// //~ rjf: Win32 Register Codes diff --git a/src/draw/draw.c b/src/draw/draw.c index 272571b3..db34c9b0 100644 --- a/src/draw/draw.c +++ b/src/draw/draw.c @@ -45,9 +45,9 @@ dr_hash_from_string(String8 string) //~ rjf: Fancy String Type Functions internal void -dr_fancy_string_list_push(Arena *arena, DR_FancyStringList *list, DR_FancyString *str) +dr_fstrs_push(Arena *arena, DR_FStrList *list, DR_FStr *str) { - DR_FancyStringNode *n = push_array_no_zero(arena, DR_FancyStringNode, 1); + DR_FStrNode *n = push_array_no_zero(arena, DR_FStrNode, 1); MemoryCopyStruct(&n->v, str); SLLQueuePush(list->first, list->last, n); list->node_count += 1; @@ -55,7 +55,38 @@ dr_fancy_string_list_push(Arena *arena, DR_FancyStringList *list, DR_FancyString } internal void -dr_fancy_string_list_concat_in_place(DR_FancyStringList *dst, DR_FancyStringList *to_push) +dr_fstrs_push_new_(Arena *arena, DR_FStrList *list, DR_FStrParams *params, DR_FStrParams *overrides, String8 string) +{ + DR_FStr fstr = {string, *params}; + if(!fnt_tag_match(fnt_tag_zero(), overrides->font)) + { + fstr.params.font = overrides->font; + } + if(overrides->raster_flags != 0) + { + fstr.params.raster_flags = overrides->raster_flags; + } + if(overrides->color.x != 0 || overrides->color.y != 0 || overrides->color.z != 0 || overrides->color.w != 0) + { + fstr.params.color = overrides->color; + } + if(overrides->size != 0) + { + fstr.params.size = overrides->size; + } + if(overrides->underline_thickness != 0) + { + fstr.params.underline_thickness = overrides->underline_thickness; + } + if(overrides->strikethrough_thickness != 0) + { + fstr.params.strikethrough_thickness = overrides->strikethrough_thickness; + } + dr_fstrs_push(arena, list, &fstr); +} + +internal void +dr_fstrs_concat_in_place(DR_FStrList *dst, DR_FStrList *to_push) { if(dst->last != 0 && to_push->first != 0) { @@ -71,34 +102,80 @@ dr_fancy_string_list_concat_in_place(DR_FancyStringList *dst, DR_FancyStringList MemoryZeroStruct(to_push); } +internal DR_FStrList +dr_fstrs_copy(Arena *arena, DR_FStrList *src) +{ + DR_FStrList dst = {0}; + for(DR_FStrNode *src_n = src->first; src_n != 0; src_n = src_n->next) + { + DR_FStr fstr = src_n->v; + fstr.string = push_str8_copy(arena, fstr.string); + dr_fstrs_push(arena, &dst, &fstr); + } + return dst; +} + internal String8 -dr_string_from_fancy_string_list(Arena *arena, DR_FancyStringList *list) +dr_string_from_fstrs(Arena *arena, DR_FStrList *list) { String8 result = {0}; - result.size = list->total_size; - result.str = push_array_no_zero(arena, U8, result.size); - U64 idx = 0; - for(DR_FancyStringNode *n = list->first; n != 0; n = n->next) { - MemoryCopy(result.str+idx, n->v.string.str, n->v.string.size); - idx += n->v.string.size; + Temp scratch = scratch_begin(&arena, 1); + String8List parts = {0}; + for(DR_FStrNode *n = list->first; n != 0; n = n->next) + { + if(!fnt_tag_match(n->v.params.font, dr_thread_ctx->icon_font)) + { + str8_list_push(scratch.arena, &parts, n->v.string); + } + } + result = str8_list_join(arena, &parts, 0); + result = str8_skip_chop_whitespace(result); + scratch_end(scratch); } return result; } -internal DR_FancyRunList -dr_fancy_run_list_from_fancy_string_list(Arena *arena, F32 tab_size_px, FNT_RasterFlags flags, DR_FancyStringList *strs) +internal FuzzyMatchRangeList +dr_fuzzy_match_find_from_fstrs(Arena *arena, DR_FStrList *fstrs, String8 needle) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 fstrs_string = {0}; + fstrs_string.size = fstrs->total_size; + fstrs_string.str = push_array(arena, U8, fstrs_string.size); + { + // TODO(rjf): the fact that we only increment on non-icon portions is super weird? + // we are only doing that because of the rendering of the fuzzy matches, so maybe + // once that is straightened out, we can fix the code here too... + U64 off = 0; + for(DR_FStrNode *n = fstrs->first; n != 0; n = n->next) + { + if(!fnt_tag_match(n->v.params.font, dr_thread_ctx->icon_font)) + { + MemoryCopy(fstrs_string.str + off, n->v.string.str, n->v.string.size); + off += n->v.string.size; + } + } + } + FuzzyMatchRangeList ranges = fuzzy_match_find(arena, needle, fstrs_string); + scratch_end(scratch); + return ranges; +} + +internal DR_FRunList +dr_fruns_from_fstrs(Arena *arena, F32 tab_size_px, DR_FStrList *strs) { ProfBeginFunction(); - DR_FancyRunList run_list = {0}; + DR_FRunList run_list = {0}; F32 base_align_px = 0; - for(DR_FancyStringNode *n = strs->first; n != 0; n = n->next) + for(DR_FStrNode *n = strs->first; n != 0; n = n->next) { - DR_FancyRunNode *dst_n = push_array(arena, DR_FancyRunNode, 1); - dst_n->v.run = fnt_push_run_from_string(arena, n->v.font, n->v.size, base_align_px, tab_size_px, flags, n->v.string); - dst_n->v.color = n->v.color; - dst_n->v.underline_thickness = n->v.underline_thickness; - dst_n->v.strikethrough_thickness = n->v.strikethrough_thickness; + DR_FRunNode *dst_n = push_array(arena, DR_FRunNode, 1); + dst_n->v.run = fnt_run_from_string(n->v.params.font, n->v.params.size, base_align_px, tab_size_px, n->v.params.raster_flags, n->v.string); + dst_n->v.color = n->v.params.color; + dst_n->v.underline_thickness = n->v.params.underline_thickness; + dst_n->v.strikethrough_thickness = n->v.params.strikethrough_thickness; + dst_n->v.icon = (fnt_tag_match(n->v.params.font, dr_thread_ctx->icon_font)); SLLQueuePush(run_list.first, run_list.last, dst_n); run_list.node_count += 1; run_list.dim.x += dst_n->v.run.dim.x; @@ -109,20 +186,14 @@ dr_fancy_run_list_from_fancy_string_list(Arena *arena, F32 tab_size_px, FNT_Rast return run_list; } -internal DR_FancyRunList -dr_fancy_run_list_copy(Arena *arena, DR_FancyRunList *src) +internal Vec2F32 +dr_dim_from_fstrs(F32 tab_size_px, DR_FStrList *fstrs) { - DR_FancyRunList dst = {0}; - for(DR_FancyRunNode *src_n = src->first; src_n != 0; src_n = src_n->next) - { - DR_FancyRunNode *dst_n = push_array(arena, DR_FancyRunNode, 1); - SLLQueuePush(dst.first, dst.last, dst_n); - MemoryCopyStruct(&dst_n->v, &src_n->v); - dst_n->v.run.pieces = fnt_piece_array_copy(arena, &src_n->v.run.pieces); - dst.node_count += 1; - } - dst.dim = src->dim; - return dst; + Temp scratch = scratch_begin(0, 0); + DR_FRunList fruns = dr_fruns_from_fstrs(scratch.arena, tab_size_px, fstrs); + Vec2F32 dim = fruns.dim; + scratch_end(scratch); + return dim; } //////////////////////////////// @@ -131,7 +202,7 @@ dr_fancy_run_list_copy(Arena *arena, DR_FancyRunList *src) // (Frame boundaries) internal void -dr_begin_frame(void) +dr_begin_frame(FNT_Tag icon_font) { if(dr_thread_ctx == 0) { @@ -143,6 +214,7 @@ dr_begin_frame(void) arena_pop_to(dr_thread_ctx->arena, dr_thread_ctx->arena_frame_start_pos); dr_thread_ctx->free_bucket_selection = 0; dr_thread_ctx->top_bucket = 0; + dr_thread_ctx->icon_font = icon_font; } internal void @@ -455,7 +527,7 @@ dr_sub_bucket(DR_Bucket *bucket) //- rjf: text internal void -dr_truncated_fancy_run_list(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FNT_Run trailer_run) +dr_truncated_fancy_run_list(Vec2F32 p, DR_FRunList *list, F32 max_x, FNT_Run trailer_run) { ProfBeginFunction(); @@ -467,9 +539,9 @@ dr_truncated_fancy_run_list(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FNT_Run B32 trailer_found = 0; Vec4F32 last_color = {0}; U64 byte_off = 0; - for(DR_FancyRunNode *n = list->first; n != 0; n = n->next) + for(DR_FRunNode *n = list->first; n != 0; n = n->next) { - DR_FancyRun *fr = &n->v; + DR_FRun *fr = &n->v; Rng1F32 pixel_range = {0}; { pixel_range.min = 100000; @@ -502,7 +574,7 @@ dr_truncated_fancy_run_list(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FNT_Run if(!r_handle_match(texture, r_handle_zero())) { dr_img(dst, src, texture, fr->color, 0, 0, 0); - //dr_rect(dst, v4f32(0, 1, 0, 0.5f), 0, 1.f, 0.f); + // dr_rect(dst, v4f32(0, 1, 0, 0.5f), 0, 1.f, 0.f); } advance += piece->advance; pixel_range.min = Min(pre_advance, pixel_range.min); @@ -558,7 +630,7 @@ dr_truncated_fancy_run_list(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FNT_Run } internal void -dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color) +dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color) { for(FuzzyMatchRangeNode *match_n = ranges->first; match_n != 0; match_n = match_n->next) { @@ -573,9 +645,9 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x F32 advance = 0; F32 ascent = 0; F32 descent = 0; - for(DR_FancyRunNode *fr_n = list->first; fr_n != 0; fr_n = fr_n->next) + for(DR_FRunNode *fr_n = list->first; fr_n != 0; fr_n = fr_n->next) { - DR_FancyRun *fr = &fr_n->v; + DR_FRun *fr = &fr_n->v; FNT_Run *run = &fr->run; ascent = run->ascent; descent = run->descent; @@ -589,7 +661,10 @@ dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x pixel_range.min = Min(pre_advance, pixel_range.min); pixel_range.max = Max(post_advance, pixel_range.max); } - byte_off += piece->decode_size; + if(!fr->icon) + { + byte_off += piece->decode_size; + } advance += piece->advance; } } @@ -637,7 +712,7 @@ internal void dr_text(FNT_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, Vec2F32 p, Vec4F32 color, String8 string) { Temp scratch = scratch_begin(0, 0); - FNT_Run run = fnt_push_run_from_string(scratch.arena, font, size, base_align_px, tab_size_px, flags, string); + FNT_Run run = fnt_run_from_string(font, size, base_align_px, tab_size_px, flags, string); dr_text_run(p, color, run); scratch_end(scratch); } diff --git a/src/draw/draw.h b/src/draw/draw.h index 1efb2bed..f338e0fd 100644 --- a/src/draw/draw.h +++ b/src/draw/draw.h @@ -7,54 +7,62 @@ //////////////////////////////// //~ rjf: Fancy String Types -typedef struct DR_FancyString DR_FancyString; -struct DR_FancyString +typedef struct DR_FStrParams DR_FStrParams; +struct DR_FStrParams { FNT_Tag font; - String8 string; + FNT_RasterFlags raster_flags; Vec4F32 color; F32 size; F32 underline_thickness; F32 strikethrough_thickness; }; -typedef struct DR_FancyStringNode DR_FancyStringNode; -struct DR_FancyStringNode +typedef struct DR_FStr DR_FStr; +struct DR_FStr { - DR_FancyStringNode *next; - DR_FancyString v; + String8 string; + DR_FStrParams params; }; -typedef struct DR_FancyStringList DR_FancyStringList; -struct DR_FancyStringList +typedef struct DR_FStrNode DR_FStrNode; +struct DR_FStrNode { - DR_FancyStringNode *first; - DR_FancyStringNode *last; + DR_FStrNode *next; + DR_FStr v; +}; + +typedef struct DR_FStrList DR_FStrList; +struct DR_FStrList +{ + DR_FStrNode *first; + DR_FStrNode *last; U64 node_count; U64 total_size; }; -typedef struct DR_FancyRun DR_FancyRun; -struct DR_FancyRun +typedef struct DR_FRun DR_FRun; +struct DR_FRun { FNT_Run run; Vec4F32 color; F32 underline_thickness; F32 strikethrough_thickness; + B32 icon; }; -typedef struct DR_FancyRunNode DR_FancyRunNode; -struct DR_FancyRunNode +typedef struct DR_FRunNode DR_FRunNode; +struct DR_FRunNode { - DR_FancyRunNode *next; - DR_FancyRun v; + DR_FRunNode *next; + DR_FRun v; }; -typedef struct DR_FancyRunList DR_FancyRunList; -struct DR_FancyRunList +typedef struct DR_FRunList DR_FRunList; +struct DR_FRunList { - DR_FancyRunNode *first; - DR_FancyRunNode *last; + DR_FRunNode *first; + DR_FRunNode *last; U64 node_count; Vec2F32 dim; }; @@ -91,6 +99,7 @@ struct DR_ThreadCtx { Arena *arena; U64 arena_frame_start_pos; + FNT_Tag icon_font; DR_BucketSelectionNode *top_bucket; DR_BucketSelectionNode *free_bucket_selection; }; @@ -108,19 +117,22 @@ internal U64 dr_hash_from_string(String8 string); //////////////////////////////// //~ rjf: Fancy String Type Functions -internal void dr_fancy_string_list_push(Arena *arena, DR_FancyStringList *list, DR_FancyString *str); -#define dr_fancy_string_list_push_new(arena, list, font_, size_, color_, string_, ...) dr_fancy_string_list_push((arena), (list), &(DR_FancyString){.font = (font_), .string = (string_), .color = (color_), .size = (size_), __VA_ARGS__}) -internal void dr_fancy_string_list_concat_in_place(DR_FancyStringList *dst, DR_FancyStringList *to_push); -internal String8 dr_string_from_fancy_string_list(Arena *arena, DR_FancyStringList *list); -internal DR_FancyRunList dr_fancy_run_list_from_fancy_string_list(Arena *arena, F32 tab_size_px, FNT_RasterFlags flags, DR_FancyStringList *strs); -internal DR_FancyRunList dr_fancy_run_list_copy(Arena *arena, DR_FancyRunList *src); +internal void dr_fstrs_push(Arena *arena, DR_FStrList *list, DR_FStr *str); +internal void dr_fstrs_push_new_(Arena *arena, DR_FStrList *list, DR_FStrParams *params, DR_FStrParams *overrides, String8 string); +#define dr_fstrs_push_new(arena, list, params, string, ...) dr_fstrs_push_new_((arena), (list), (params), &(DR_FStrParams){.size = 0, __VA_ARGS__}, (string)) +internal void dr_fstrs_concat_in_place(DR_FStrList *dst, DR_FStrList *to_push); +internal DR_FStrList dr_fstrs_copy(Arena *arena, DR_FStrList *src); +internal String8 dr_string_from_fstrs(Arena *arena, DR_FStrList *list); +internal FuzzyMatchRangeList dr_fuzzy_match_find_from_fstrs(Arena *arena, DR_FStrList *fstrs, String8 needle); +internal DR_FRunList dr_fruns_from_fstrs(Arena *arena, F32 tab_size_px, DR_FStrList *strs); +internal Vec2F32 dr_dim_from_fstrs(F32 tab_size_px, DR_FStrList *fstrs); //////////////////////////////// //~ rjf: Top-Level API // // (Frame boundaries & bucket submission) -internal void dr_begin_frame(void); +internal void dr_begin_frame(FNT_Tag icon_font); internal void dr_submit_bucket(OS_Handle os_window, R_Handle r_window, DR_Bucket *bucket); //////////////////////////////// @@ -184,8 +196,8 @@ internal void dr_sub_bucket(DR_Bucket *bucket); //~ rjf: Draw Call Helpers //- rjf: text -internal void dr_truncated_fancy_run_list(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FNT_Run trailer_run); -internal void dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FancyRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color); +internal void dr_truncated_fancy_run_list(Vec2F32 p, DR_FRunList *list, F32 max_x, FNT_Run trailer_run); +internal void dr_truncated_fancy_run_fuzzy_matches(Vec2F32 p, DR_FRunList *list, F32 max_x, FuzzyMatchRangeList *ranges, Vec4F32 color); internal void dr_text_run(Vec2F32 p, Vec4F32 color, FNT_Run run); internal void dr_text(FNT_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, Vec2F32 p, Vec4F32 color, String8 string); diff --git a/src/dwarf/dwarf.c b/src/dwarf/dwarf.c index 6a224f34..05f72bc0 100644 --- a/src/dwarf/dwarf.c +++ b/src/dwarf/dwarf.c @@ -1,6 +1,74 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal U64 +dw_reg_size_from_code_x86(DW_Reg reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX86_##reg_name_dw: return reg_size; + DW_Regs_X86_XList(X) +#undef X + } + return 0; +} + +internal U64 +dw_reg_pos_from_code_x86(DW_Reg reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX86_##reg_name_dw: return reg_pos; + DW_Regs_X86_XList(X) +#undef X + } + return max_U64; +} + +internal U64 +dw_reg_size_from_code_x64(DW_Reg reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX64_##reg_name_dw: return reg_size; + DW_Regs_X64_XList(X) +#undef X + } + return 0; +} + +internal U64 +dw_reg_pos_from_code_x64(DW_Reg reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX64_##reg_name_dw: return reg_pos; + DW_Regs_X64_XList(X) +#undef X + } + return max_U64; +} + +internal U64 +dw_reg_size_from_code(Arch arch, DW_Reg reg_code) +{ + switch (arch) { + case Arch_Null: break; + case Arch_x86: return dw_reg_size_from_code_x86(reg_code); + case Arch_x64: return dw_reg_size_from_code_x64(reg_code); + default: NotImplemented; break; + } + return 0; +} + +internal U64 +dw_reg_pos_from_code(Arch arch, DW_Reg reg_code) +{ + switch (arch) { + case Arch_Null: break; + case Arch_x86: return dw_reg_pos_from_code_x86(reg_code); + case Arch_x64: return dw_reg_pos_from_code_x64(reg_code); + default: NotImplemented; break; + } + return max_U64; +} + internal DW_AttribClass dw_attrib_class_from_attrib_kind_v2(DW_AttribKind k) { @@ -135,6 +203,11 @@ internal DW_AttribClass dw_attrib_class_from_form_kind(DW_Version ver, DW_FormKind k) { #define X(_N,_C) case DW_Form_##_N: return _C; + + switch (k) { + DW_Form_AttribClass_GNU_XList(X) + } + switch (ver) { case DW_Version_5: { switch (k) { @@ -207,20 +280,20 @@ dw_dwo_name_string_from_section_kind(DW_SectionKind k) } internal U64 -dw_offset_size_from_mode(DW_Mode mode) +dw_size_from_format(DW_Format format) { U64 result = 0; - switch (mode) { - case DW_Mode_Null: break; - case DW_Mode_32Bit: result = 4; break; - case DW_Mode_64Bit: result = 8; break; + switch (format) { + case DW_Format_Null: break; + case DW_Format_32Bit: result = 4; break; + case DW_Format_64Bit: result = 8; break; default: InvalidPath; break; } return result; } internal DW_AttribClass -dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib_kind, DW_FormKind form_kind) +dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B32 relaxed, DW_AttribKind attrib_kind, DW_FormKind form_kind) { // NOTE(rjf): DWARF's spec specifies two mappings: // (DW_AttribKind) => List(DW_AttribClass) @@ -257,10 +330,59 @@ dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 rel } } - if (attrib_kind != DW_Attrib_Null && form_kind != DW_Form_Null) { - //Assert(result != DW_AttribClass_Null && result != DW_AttribClass_Undefined); - } - return result; } +internal U64 +dw_pick_default_lower_bound(DW_Language lang) +{ + U64 lower_bound = max_U64; + switch (lang) { + case DW_Language_Null: break; + case DW_Language_C89: + case DW_Language_C: + case DW_Language_CPlusPlus: + case DW_Language_C99: + case DW_Language_CPlusPlus03: + case DW_Language_CPlusPlus11: + case DW_Language_C11: + case DW_Language_CPlusPlus14: + case DW_Language_Java: + case DW_Language_ObjC: + case DW_Language_ObjCPlusPlus: + case DW_Language_UPC: + case DW_Language_D: + case DW_Language_Python: + case DW_Language_OpenCL: + case DW_Language_Go: + case DW_Language_Haskell: + case DW_Language_OCaml: + case DW_Language_Rust: + case DW_Language_Swift: + case DW_Language_Dylan: + case DW_Language_RenderScript: + case DW_Language_BLISS: + lower_bound = 0; + break; + case DW_Language_Ada83: + case DW_Language_Cobol74: + case DW_Language_Cobol85: + case DW_Language_Fortran77: + case DW_Language_Fortran90: + case DW_Language_Pascal83: + case DW_Language_Modula2: + case DW_Language_Ada95: + case DW_Language_Fortran95: + case DW_Language_PLI: + case DW_Language_Modula3: + case DW_Language_Julia: + case DW_Language_Fortran03: + case DW_Language_Fortran08: + lower_bound = 1; + default: + NotImplemented; + break; + } + return lower_bound; +} + diff --git a/src/dwarf/dwarf.h b/src/dwarf/dwarf.h index 4fd083ce..4c7132a4 100644 --- a/src/dwarf/dwarf.h +++ b/src/dwarf/dwarf.h @@ -29,32 +29,35 @@ typedef enum DW_ExtEnum DW_Ext_All = DW_Ext_GNU|DW_Ext_LLVM|DW_Ext_APPLE|DW_Ext_MIPS, } DW_ExtEnum; -typedef enum DW_Mode +#define DW_FormatFromSize(size) ((size) >= max_U32 ? DW_Format_64Bit : DW_Format_32Bit) +typedef enum DW_Format { - DW_Mode_Null, - DW_Mode_32Bit, - DW_Mode_64Bit -} DW_Mode; + DW_Format_Null, + DW_Format_32Bit, + DW_Format_64Bit +} DW_Format; -#define DW_SectionKind_XList(X) \ - X(Null, "", "", "" ) \ - X(Abbrev, ".debug_abbrev", "__debug_abbrev", ".debug_abbrev.dwo" ) \ - X(ARanges, ".debug_aranges", "__debug_aranges", ".debug_aranges.dwo" ) \ - X(Frame, ".debug_frame", "__debug_frame", ".debug_frame.dwo" ) \ - X(Info, ".debug_info", "__debug_info", ".debug_info.dwo" ) \ - X(Line, ".debug_line", "__debug_line", ".debug_line.dwo" ) \ - X(Loc, ".debug_loc", "__debug_loc", ".debug_loc.dwo" ) \ - X(MacInfo, ".debug_macinfo", "__debug_macinfo", ".debug_macinfo.dwo" ) \ - X(PubNames, ".debug_pubnames", "__debug_pubnames", ".debug_pubnames.dwo" ) \ - X(PubTypes, ".debug_pubtypes", "__debug_pubtypes", ".debug_pubtypes.dwo" ) \ - X(Ranges, ".debug_ranges", "__debug_ranges", ".debug_ranges.dwo" ) \ - X(Str, ".debug_str", "__debug_str", ".debug_str.dwo" ) \ - X(Addr, ".debug_addr", "__debug_addr", ".debug_addr.dwo" ) \ - X(LocLists, ".debug_loclists", "__debug_loclists", ".debug_loclists.dwo" ) \ - X(RngLists, ".debug_rnglists", "__debug_rnglists", ".debug_rnglists.dwo" ) \ - X(StrOffsets, ".debug_stroffsets", "__debug_stroffsets", ".debug_stroffsets.dwo" ) \ - X(LineStr, ".debug_linestr", "__debug_linestr", ".debug_linestr.dwo" ) \ - X(Names, ".debug_names", "__debug_names", ".debug_names.dwo" ) +#define DW_SentinelFromSize(address_size) ((address_size) == 4 ? max_U32 : (address_size) == 8 ? max_U64 : 0) + +#define DW_SectionKind_XList(X )\ + X(Null, "", "", "" )\ + X(Abbrev, ".debug_abbrev", "__debug_abbrev", ".debug_abbrev.dwo" )\ + X(ARanges, ".debug_aranges", "__debug_aranges", ".debug_aranges.dwo" )\ + X(Frame, ".debug_frame", "__debug_frame", ".debug_frame.dwo" )\ + X(Info, ".debug_info", "__debug_info", ".debug_info.dwo" )\ + X(Line, ".debug_line", "__debug_line", ".debug_line.dwo" )\ + X(Loc, ".debug_loc", "__debug_loc", ".debug_loc.dwo" )\ + X(MacInfo, ".debug_macinfo", "__debug_macinfo", ".debug_macinfo.dwo" )\ + X(PubNames, ".debug_pubnames", "__debug_pubnames", ".debug_pubnames.dwo" )\ + X(PubTypes, ".debug_pubtypes", "__debug_pubtypes", ".debug_pubtypes.dwo" )\ + X(Ranges, ".debug_ranges", "__debug_ranges", ".debug_ranges.dwo" )\ + X(Str, ".debug_str", "__debug_str", ".debug_str.dwo" )\ + X(Addr, ".debug_addr", "__debug_addr", ".debug_addr.dwo" )\ + X(LocLists, ".debug_loclists", "__debug_loclists", ".debug_loclists.dwo" )\ + X(RngLists, ".debug_rnglists", "__debug_rnglists", ".debug_rnglists.dwo" )\ + X(StrOffsets, ".debug_str_offsets", "__debug_str_offsets", ".debug_str_offsets.dwo")\ + X(LineStr, ".debug_line_str", "__debug_line_str", ".debug_line_str.dwo" )\ + X(Names, ".debug_names", "__debug_names", ".debug_names.dwo" ) typedef U64 DW_SectionKind; typedef enum DW_SectionKindEnum @@ -82,8 +85,8 @@ typedef enum DW_SectionKindEnum X(Ada95, 0x0D) \ X(Fortran95, 0x0E) \ X(PLI, 0x0F) \ - X(ObjectiveC, 0x10) \ - X(ObjectiveCPlusPlus, 0x11) \ + X(ObjC, 0x10) \ + X(ObjCPlusPlus, 0x11) \ X(UPC, 0x12) \ X(D, 0x13) \ X(Python, 0x14) \ @@ -119,6 +122,20 @@ typedef enum DW_LanguageEnum DW_Language_UserHi = 0xffff, } DW_LanguageEnum; +#define DW_Inl_XList(X) \ + X(NotInlined, 0) \ + X(Inlined, 1) \ + X(DeclaredNotInlined, 2) \ + X(DeclaredInlined, 3) + +typedef U32 DW_InlKind; +typedef enum DW_InlKindEnum +{ +#define X(_N,_ID) DW_Inl_##_N = _ID, + DW_Inl_XList(X) +#undef X +} DW_InlKindEnum; + #define DW_StdOpcode_XList(X) \ X(ExtendedOpcode, 0x00) \ X(Copy, 0x01) \ @@ -157,19 +174,19 @@ typedef enum DW_ExtOpcode #undef X } DW_ExtOpcode; -#define DW_NameCase_XList(X) \ - X(Sensitive, 0x00) \ - X(Upper, 0x01) \ - X(Lower, 0x02) \ - X(Insensitive, 0x03) +#define DW_IDCaseKind_XList(X) \ + X(CaseSensitive, 0x00) \ + X(UpCase, 0x01) \ + X(DownCase, 0x02) \ + X(CaseInsensitive, 0x03) -typedef enum DW_NameCase +typedef U64 DW_IDCaseKind; +typedef enum DW_IDCaseKindEnum { -#define X(_N,_ID) DW_NameCase_##_N = _ID, - DW_NameCase_XList(X) +#define X(_N,_ID) DW_IDCase_##_N = _ID, + DW_IDCaseKind_XList(X) #undef X - DW_NameCase_Count -} DW_NameCase; +} DW_IDCaseKindEnum; #define DW_Tag_V3_XList(X) \ X(ArrayType, 0x01) \ @@ -250,6 +267,7 @@ typedef enum DW_NameCase typedef U64 DW_TagKind; typedef enum DW_TagKindEnum { + DW_Tag_Null, #define X(_N,_ID) DW_Tag_##_N = _ID, DW_Tag_V3_XList(X) DW_Tag_V5_XList(X) @@ -436,7 +454,7 @@ typedef enum DW_AttribClassEnum X(LineStrp, DW_AttribClass_String) \ X(ImplicitConst, DW_AttribClass_Const) \ X(LocListx, DW_AttribClass_LocListPtr) \ - X(RngListx, DW_AttribClass_RngListPtr) \ + X(RngListx, DW_AttribClass_RngList) \ X(RefSup8, DW_AttribClass_Reference) \ X(Strx1, DW_AttribClass_String) \ X(Strx2, DW_AttribClass_String) \ @@ -447,6 +465,18 @@ typedef enum DW_AttribClassEnum X(Addrx3, DW_AttribClass_Address) \ X(Addrx4, DW_AttribClass_Address) +#define DW_Form_GNU_XList(X) \ + X(GNU_AddrIndex, 0x1f01) \ + X(GNU_StrIndex, 0x1f02) \ + X(GNU_RefAlt, 0x1f20) \ + X(GNU_StrpAlt, 0x1f21) + +#define DW_Form_AttribClass_GNU_XList(X) \ + X(GNU_AddrIndex, DW_AttribClass_Undefined) \ + X(GNU_StrIndex, DW_AttribClass_Undefined) \ + X(GNU_RefAlt, DW_AttribClass_Undefined) \ + X(GNU_StrpAlt, DW_AttribClass_String) + typedef U64 DW_FormKind; typedef enum DW_FormEnum { @@ -455,6 +485,7 @@ typedef enum DW_FormEnum DW_Form_V2_XList(X) DW_Form_V4_XList(X) DW_Form_V5_XList(X) + DW_Form_GNU_XList(X) #undef X } DW_FormEnum; @@ -1143,41 +1174,41 @@ typedef enum DW_AttribKindEnum DW_Attrib_UserHi = 0x3fff } DW_AttribKindEnum; -#define DW_AttribTypeEncodingKind_XList(X) \ - X(Null, 0x00) \ - X(Address, 0x01) \ - X(Boolean, 0x02) \ - X(ComplexFloat, 0x03) \ - X(Float, 0x04) \ - X(Signed, 0x05) \ - X(SignedChar, 0x06) \ - X(Unsigned, 0x07) \ - X(UnsignedChar, 0x08) \ - X(ImaginaryFloat, 0x09) \ - X(PackedDecimal, 0x0A) \ - X(NumericString, 0x0B) \ - X(Edited, 0x0C) \ - X(SignedFixed, 0x0D) \ - X(UnsignedFixed, 0x0E) \ - X(DecimalFloat, 0x0F) \ - X(Utf, 0x10) \ - X(Ucs, 0x11) \ +#define DW_ATE_XList(X) \ + X(Null, 0x00) \ + X(Address, 0x01) \ + X(Boolean, 0x02) \ + X(ComplexFloat, 0x03) \ + X(Float, 0x04) \ + X(Signed, 0x05) \ + X(SignedChar, 0x06) \ + X(Unsigned, 0x07) \ + X(UnsignedChar, 0x08) \ + X(ImaginaryFloat, 0x09) \ + X(PackedDecimal, 0x0A) \ + X(NumericString, 0x0B) \ + X(Edited, 0x0C) \ + X(SignedFixed, 0x0D) \ + X(UnsignedFixed, 0x0E) \ + X(DecimalFloat, 0x0F) \ + X(Utf, 0x10) \ + X(Ucs, 0x11) \ X(Ascii, 0x12) -typedef U64 DW_AttribTypeEncodingKind; -typedef enum DW_AttribTypeEncodingKindEnum +typedef U64 DW_ATE; +typedef enum DW_ATEEnum { -#define X(_N,_ID) DW_AttribTypeEncodingKind_##_N = _ID, - DW_AttribTypeEncodingKind_XList(X) +#define X(_N,_ID) DW_ATE_##_N = _ID, + DW_ATE_XList(X) #undef X -} DW_AttribTypeEncodingKindEnum; +} DW_ATEnum; -#define DW_CallingConventionKind_XList(X) \ - X(DW_CallingConvention_Normal, 0x0) \ - X(DW_CallingConvention_Program, 0x1) \ - X(DW_CallingConvention_NoCall, 0x2) \ - X(DW_CallingConvention_PassByValue, 0x1) \ - X(DW_CallingConvention_PassByReference, 0x2) +#define DW_CallingConventionKind_XList(X) \ + X(Normal, 0x0) \ + X(Program, 0x1) \ + X(NoCall, 0x3) \ + X(PassByValue, 0x4) \ + X(PassByReference, 0x5) typedef U64 DW_CallingConventionKind; typedef enum DW_CallingConventionKindEnum @@ -1188,9 +1219,9 @@ typedef enum DW_CallingConventionKindEnum } DW_CallingConventionKindEnum; #define DW_AccessKind_XList(X) \ - X(DW_Access_Public, 0x00) \ - X(DW_Access_Private, 0x01) \ - X(DW_Access_Protected, 0x02) + X(Public, 0x00) \ + X(Private, 0x01) \ + X(Protected, 0x02) typedef U64 DW_AccessKind; typedef enum DW_AccessKindEnum @@ -1215,7 +1246,7 @@ typedef enum DW_VirtualityEnum #define DW_RngListEntryKind(X) \ X(EndOfList, 0x00) \ - X(BaseAddressX, 0x01) \ + X(BaseAddressx, 0x01) \ X(StartxEndx, 0x02) \ X(StartxLength, 0x03) \ X(OffsetPair, 0x04) \ @@ -1223,32 +1254,51 @@ typedef enum DW_VirtualityEnum X(StartEnd, 0x06) \ X(StartLength, 0x07) -typedef U64 DW_RngListEntryKind; -typedef enum DW_RngListEntryKindEnum +typedef U8 DW_RLE; +typedef enum DW_RLE_Enum { -#define X(_N,_ID) DW_RngListEntryKind_##_N = _ID, +#define X(_N,_ID) DW_RLE_##_N = _ID, DW_RngListEntryKind(X) #undef X -} DW_RngListEntryKindEnum; +} DW_RLE_Enum; #define DW_LocListEntry_XList(X) \ X(EndOfList, 0x00) \ - X(BaseAddressX, 0x01) \ - X(StartXEndX, 0x02) \ - X(StartXLength, 0x03) \ + X(BaseAddressx, 0x01) \ + X(StartxEndx, 0x02) \ + X(StartxLength, 0x03) \ X(OffsetPair, 0x04) \ X(DefaultLocation, 0x05) \ X(BaseAddress, 0x06) \ X(StartEnd, 0x07) \ X(StartLength, 0x08) -typedef U64 DW_LocListEntryKind; -typedef enum DW_LocListEntryEnum +#define DW_LocListEntry_GNU_XList(X) \ + X(GNU_ViewPair, 0x9) + +typedef U8 DW_LLE; +typedef enum DW_LLE_Enum { -#define X(_N,_ID) DW_LocListEntryKind_##_N = _ID, +#define X(_N,_ID) DW_LLE_##_N = _ID, DW_LocListEntry_XList(X) #undef X -} DW_LocListEntryEnum; +} DW_LLEEnum; + +#define DW_AddrClass_XList(X) \ + X(None, 0) \ + X(Near16, 1) \ + X(Far16, 2) \ + X(Huge16, 3) \ + X(Near32, 4) \ + X(Far32, 5) + +typedef U64 DW_AddrClass; +typedef enum DW_AddrClassEnum +{ +#define X(_N, _ID) DW_AddrClassKind_##_N = _ID, + DW_AddrClass_XList(X) +#undef X +} DW_AddrClassEnum; #define DW_CompUnitKind_XList(X) \ X(Reserved, 0) \ @@ -1269,16 +1319,23 @@ typedef enum DW_CompUnitKindEnum DW_CompUnitKind_UserHi = 0xff } DW_CompUnitKindEnum; -typedef enum DW_LNCT +#define DW_LNCT_XList(X) \ + X(Path, 0x1) \ + X(DirectoryIndex, 0x2) \ + X(TimeStamp, 0x3) \ + X(Size, 0x4) \ + X(MD5, 0x5) \ + X(LLVM_Source, 0x2001) + +typedef U64 DW_LNCT; +typedef enum DW_LNCTEnum { - DW_LNCT_Path = 0x1, - DW_LNCT_DirectoryIndex = 0x2, - DW_LNCT_TimeStamp = 0x3, - DW_LNCT_Size = 0x4, - DW_LNCT_MD5 = 0x5, - DW_LNCT_UserLo = 0x2000, - DW_LNCT_UserHi = 0x3fff -} DW_LNCT; +#define X(_N, _ID) DW_LNCT_##_N = _ID, + DW_LNCT_XList(X) +#undef X + DW_LNCT_UserLo = 0x2000, + DW_LNCT_UserHi = 0x3fff +} DW_LNCTEnum; #define DW_CFA_Kind1_XList(X) \ X(Nop, 0x0) \ @@ -1505,9 +1562,19 @@ enum X(Convert, 0xa8) \ X(ReInterpret, 0xa9) -#define DW_Expr_GNU_XList(X) \ - X(GNU_PushTlsAddress, 0xe0) \ - X(GNU_UnInit, 0xf0) +#define DW_Expr_GNU_XList(X) \ + X(GNU_PushTlsAddress, 0xe0) \ + X(GNU_UnInit, 0xf0) \ + X(GNU_ImplicitPointer, 0xf2) \ + X(GNU_EntryValue, 0xf3) \ + X(GNU_ConstType, 0xf4) \ + X(GNU_RegvalType, 0xf5) \ + X(GNU_DerefType, 0xf6) \ + X(GNU_Convert, 0xf7) \ + X(GNU_ParameterRef, 0xfa) \ + X(GNU_AddrIndex, 0xfb) \ + X(GNU_ConstIndex, 0xfc) + typedef U64 DW_ExprOp; typedef enum DW_ExprOpEnum { @@ -1541,22 +1608,22 @@ typedef enum DW_ExprOpEnum X(St5, 16, st5, 0, 10) \ X(St6, 17, st6, 0, 10) \ X(St7, 18, st7, 0, 10) \ - X(Xmm0, 21, xmm0, 0, 16) \ - X(Xmm1, 22, xmm1, 0, 16) \ - X(Xmm2, 23, xmm2, 0, 16) \ - X(Xmm3, 24, xmm3, 0, 16) \ - X(Xmm4, 25, xmm4, 0, 16) \ - X(Xmm5, 26, xmm5, 0, 16) \ - X(Xmm6, 27, xmm6, 0, 16) \ - X(Xmm7, 28, xmm7, 0, 16) \ - X(Mm0, 29, mm0, 0, 4) \ - X(Mm1, 30, mm1, 0, 4) \ - X(Mm2, 31, mm2, 0, 4) \ - X(Mm3, 32, mm3, 0, 4) \ - X(Mm4, 33, mm4, 0, 4) \ - X(Mm5, 34, mm5, 0, 4) \ - X(Mm6, 35, mm6, 0, 4) \ - X(Mm7, 36, mm7, 0, 4) \ + X(Xmm0, 21, ymm0, 0, 16) \ + X(Xmm1, 22, ymm1, 0, 16) \ + X(Xmm2, 23, ymm2, 0, 16) \ + X(Xmm3, 24, ymm3, 0, 16) \ + X(Xmm4, 25, ymm4, 0, 16) \ + X(Xmm5, 26, ymm5, 0, 16) \ + X(Xmm6, 27, ymm6, 0, 16) \ + X(Xmm7, 28, ymm7, 0, 16) \ + X(Mm0, 29, fpr0, 0, 8) \ + X(Mm1, 30, fpr1, 0, 8) \ + X(Mm2, 31, fpr2, 0, 8) \ + X(Mm3, 32, fpr3, 0, 8) \ + X(Mm4, 33, fpr4, 0, 8) \ + X(Mm5, 34, fpr5, 0, 8) \ + X(Mm6, 35, fpr6, 0, 8) \ + X(Mm7, 36, fpr7, 0, 8) \ X(Fcw, 37, fcw, 0, 2) \ X(Fsw, 38, fsw, 0, 2) \ X(Mxcsr, 39, mxcsr, 0, 4) \ @@ -1587,22 +1654,38 @@ typedef enum DW_ExprOpEnum X(R14, 14, r14, 0, 8) \ X(R15, 15, r15, 0, 8) \ X(Rip, 16, rip, 0, 8) \ - X(Xmm0, 17, ymm0, 0, 16) \ - X(Xmm1, 18, ymm1, 0, 16) \ - X(Xmm2, 19, ymm2, 0, 16) \ - X(Xmm3, 20, ymm3, 0, 16) \ - X(Xmm4, 21, ymm4, 0, 16) \ - X(Xmm5, 22, ymm5, 0, 16) \ - X(Xmm6, 23, ymm6, 0, 16) \ - X(Xmm7, 24, ymm7, 0, 16) \ - X(Xmm8, 25, ymm8, 0, 16) \ - X(Xmm9, 26, ymm9, 0, 16) \ - X(Xmm10, 27, ymm10, 0, 16) \ - X(Xmm11, 28, ymm11, 0, 16) \ - X(Xmm12, 29, ymm12, 0, 16) \ - X(Xmm13, 30, ymm13, 0, 16) \ - X(Xmm14, 31, ymm14, 0, 16) \ - X(Xmm15, 32, ymm15, 0, 16) \ + X(Xmm0, 17, zmm0, 0, 16) \ + X(Xmm1, 18, zmm1, 0, 16) \ + X(Xmm2, 19, zmm2, 0, 16) \ + X(Xmm3, 20, zmm3, 0, 16) \ + X(Xmm4, 21, zmm4, 0, 16) \ + X(Xmm5, 22, zmm5, 0, 16) \ + X(Xmm6, 23, zmm6, 0, 16) \ + X(Xmm7, 24, zmm7, 0, 16) \ + X(Xmm8, 25, zmm8, 0, 16) \ + X(Xmm9, 26, zmm9, 0, 16) \ + X(Xmm10, 27, zmm10, 0, 16) \ + X(Xmm11, 28, zmm11, 0, 16) \ + X(Xmm12, 29, zmm12, 0, 16) \ + X(Xmm13, 30, zmm13, 0, 16) \ + X(Xmm14, 31, zmm14, 0, 16) \ + X(Xmm15, 32, zmm15, 0, 16) \ + X(Xmm16, 67, zmm16, 0, 16) \ + X(Xmm17, 68, zmm17, 0, 16) \ + X(Xmm18, 69, zmm18, 0, 16) \ + X(Xmm19, 70, zmm19, 0, 16) \ + X(Xmm20, 71, zmm20, 0, 16) \ + X(Xmm21, 72, zmm21, 0, 16) \ + X(Xmm22, 73, zmm22, 0, 16) \ + X(Xmm23, 74, zmm23, 0, 16) \ + X(Xmm24, 75, zmm24, 0, 16) \ + X(Xmm25, 76, zmm25, 0, 16) \ + X(Xmm26, 77, zmm26, 0, 16) \ + X(Xmm27, 78, zmm27, 0, 16) \ + X(Xmm28, 79, zmm28, 0, 16) \ + X(Xmm29, 80, zmm29, 0, 16) \ + X(Xmm30, 81, zmm30, 0, 16) \ + X(Xmm31, 82, zmm31, 0, 16) \ X(St0, 33, st0, 0, 10) \ X(St1, 34, st1, 0, 10) \ X(St2, 35, st2, 0, 10) \ @@ -1611,14 +1694,14 @@ typedef enum DW_ExprOpEnum X(St5, 38, st5, 0, 10) \ X(St6, 39, st6, 0, 10) \ X(St7, 40, st7, 0, 10) \ - X(Mm0, 41, mm0, 0, 8) \ - X(Mm1, 42, mm1, 0, 8) \ - X(Mm2, 43, mm2, 0, 8) \ - X(Mm3, 44, mm3, 0, 8) \ - X(Mm4, 45, mm4, 0, 8) \ - X(Mm5, 46, mm5, 0, 8) \ - X(Mm6, 47, mm6, 0, 8) \ - X(Mm7, 48, mm7, 0, 8) \ + X(Mm0, 41, fpr0, 0, 8) \ + X(Mm1, 42, fpr1, 0, 8) \ + X(Mm2, 43, fpr2, 0, 8) \ + X(Mm3, 44, fpr3, 0, 8) \ + X(Mm4, 45, fpr4, 0, 8) \ + X(Mm5, 46, fpr5, 0, 8) \ + X(Mm6, 47, fpr6, 0, 8) \ + X(Mm7, 48, fpr7, 0, 8) \ X(Rflags, 49, rflags, 0, 4) \ X(Es, 50, es, 0, 2) \ X(Cs, 51, cs, 0, 2) \ @@ -1631,24 +1714,33 @@ typedef enum DW_ExprOpEnum X(Tr, 62, nil, 0, 0) \ X(Ldtr, 63, nil, 0, 0) -typedef U32 DW_RegX86; +typedef U32 DW_Reg; + +typedef DW_Reg DW_RegX86; typedef enum DW_RegX86Enum { -#define X(_N,_ID,...) DW_Reg_x86_##_N = _ID, +#define X(_N,_ID,...) DW_RegX86_##_N = _ID, DW_Regs_X86_XList(X) #undef X } DW_RegX86Enum; -typedef U32 DW_RegX64; +typedef DW_Reg DW_RegX64; typedef enum DW_RegX64Enum { -#define X(_N,_ID,...) DW_Reg_x64_##_N = _ID, +#define X(_N,_ID,...) DW_RegX64_##_N = _ID, DW_Regs_X64_XList(X) #undef X } DW_RegX64Enum; //////////////////////////////// +internal U64 dw_reg_size_from_code_x86(DW_Reg reg_code); +internal U64 dw_reg_pos_from_code_x86(DW_Reg reg_code); +internal U64 dw_reg_size_from_code_x64(DW_Reg reg_code); +internal U64 dw_reg_pos_from_code_x64(DW_Reg reg_code); +internal U64 dw_reg_size_from_code(Arch arch, DW_Reg reg_code); +internal U64 dw_reg_pos_from_code(Arch arch, DW_Reg reg_code); + //- Attrib Class Encodings // Speced Encodings @@ -1679,10 +1771,12 @@ internal String8 dw_dwo_name_string_from_section_kind (DW_SectionKind k); //////////////////////////////// -internal U64 dw_offset_size_from_mode(DW_Mode mode); +internal U64 dw_size_from_format(DW_Format format); //////////////////////////////// -internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, DW_Language lang, B32 relaxed, DW_AttribKind attrib, DW_FormKind form_kind); +internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B32 relaxed, DW_AttribKind attrib, DW_FormKind form_kind); + +internal U64 dw_pick_default_lower_bound(DW_Language lang); #endif // DWARF_H diff --git a/src/dwarf/dwarf_coff.c b/src/dwarf/dwarf_coff.c new file mode 100644 index 00000000..423761bc --- /dev/null +++ b/src/dwarf/dwarf_coff.c @@ -0,0 +1,68 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +dw_is_dwarf_present_coff_section_table(String8 raw_image, + String8 string_table, + U64 section_count, + COFF_SectionHeader *section_table) +{ + B32 is_dwarf_present = 0; + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ion_table[i]; + String8 name = coff_name_from_section_header(string_table, header); + + DW_SectionKind s = dw_section_kind_from_string(name); + if (s == DW_Section_Null) { + s = dw_section_dwo_kind_from_string(name); + } + + is_dwarf_present = s != DW_Section_Null; + if (is_dwarf_present) { + break; + } + } + + return is_dwarf_present; +} + +internal DW_Input +dw_input_from_coff_section_table(Arena *arena, + String8 raw_image, + String8 string_table, + U64 section_count, + COFF_SectionHeader *section_table) +{ + DW_Input input = {0}; + B32 sect_status[ArrayCount(input.sec)] = {0}; + + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = §ion_table[i]; + Rng1U64 raw_data_range = rng_1u64(header->foff, header->foff + header->fsize); + String8 name = coff_name_from_section_header(string_table, header); + + DW_SectionKind s = dw_section_kind_from_string(name); + B32 is_dwo = 0; + if (s == DW_Section_Null) { + s = dw_section_dwo_kind_from_string(name); + is_dwo = 1; + } + + if (s != DW_Section_Null) { + if (sect_status[s]) { + Assert(!"too many debug sections with identical name, picking first"); + } else { + sect_status[s] = 1; + DW_Section *d = &input.sec[s]; + d->name = push_str8_copy(arena, name); + d->data = str8_substr(raw_image, raw_data_range); + d->is_dwo = is_dwo; + } + } + } + + return input; +} + + diff --git a/src/dwarf/dwarf_coff.h b/src/dwarf/dwarf_coff.h new file mode 100644 index 00000000..e612897a --- /dev/null +++ b/src/dwarf/dwarf_coff.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_COFF_H +#define DWARF_COFF_H + +internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table); + +#endif // DWARF_COFF_H + diff --git a/src/dwarf/dwarf_elf.c b/src/dwarf/dwarf_elf.c new file mode 100644 index 00000000..99117b2e --- /dev/null +++ b/src/dwarf/dwarf_elf.c @@ -0,0 +1,132 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +dw_is_dwarf_present_elf_section_table(String8 raw_image, ELF_BinInfo *bin) +{ + Temp scratch = scratch_begin(0,0); + + B32 is_dwarf_present = 0; + + ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_image, &bin->hdr); + + for (U64 i = 0; i < sections.count; ++i) { + ELF_Shdr64 *shdr = §ions.v[i]; + String8 name = elf_name_from_shdr64(raw_image, &bin->hdr, bin->sh_name_range, shdr); + + if (shdr->sh_type != ELF_SectionCode_ProgBits) { + continue; + } + + DW_SectionKind s = dw_section_kind_from_string(name); + if (s == DW_Section_Null) { + s = dw_section_dwo_kind_from_string(name); + } + + is_dwarf_present = s != DW_Section_Null; + if (is_dwarf_present) { + break; + } + } + + scratch_end(scratch); + return is_dwarf_present; +} + +internal DW_Input +dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_Input result = {0}; + B32 sect_status[ArrayCount(result.sec)] = {0}; + + ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_image, &bin->hdr); + + for (U64 sect_idx = 1; sect_idx < sections.count; ++sect_idx) { + ELF_Shdr64 *shdr = §ions.v[sect_idx]; + + // skip BSS sections + if (shdr->sh_type != ELF_SectionCode_ProgBits) { + continue; + } + + String8 name = elf_name_from_shdr64(raw_image, &bin->hdr, bin->sh_name_range, shdr); + + DW_SectionKind s = dw_section_kind_from_string(name); + B32 is_dwo = 0; + if (s == DW_Section_Null) { + s = dw_section_dwo_kind_from_string(name); + is_dwo = 1; + } + + if (s != DW_Section_Null) { + if (sect_status[s]) { + Assert(!"too many debug sections with identical name, picking first"); + } else { + Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size); + String8 data = str8_substr(raw_image, raw_data_range); + + // ELF was compiled with compressed debug info + if (shdr->sh_flags & ELF_Shf_Compressed) { + String8 comp_data_with_header = data; + + // read header + ELF_Chdr64 chdr64 = {0}; + U64 chdr_size = 0; + if (ELF_HdrIs64Bit(bin->hdr.e_ident)) { + chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr64); + if (chdr_size != sizeof(chdr64)) { + Assert(!"not enough bytes to read header"); + } + } else if (ELF_HdrIs32Bit(bin->hdr.e_ident)) { + ELF_Chdr32 chdr32 = {0}; + chdr_size = str8_deserial_read_struct(comp_data_with_header, 0, &chdr32); + if (chdr_size == sizeof(chdr32)) { + chdr64 = elf_chdr64_from_chdr32(chdr32); + } + } + + AssertAlways(IsPow2(chdr64.ch_addr_align)); + + // skip header + String8 comp_data = str8_skip(comp_data_with_header, chdr_size); + + // push buffer for the decompressor + U8 *decomp_buffer = push_array_no_zero_aligned(arena, U8, chdr64.ch_size, chdr64.ch_addr_align); + U64 actual_decomp_size = 0; + + // decompress + switch (chdr64.ch_type) { + case ELF_CompressType_None: { + AssertAlways(!"unexpected compression type"); + } break; + case ELF_CompressType_ZLib: { + actual_decomp_size = zsinflate(decomp_buffer, chdr64.ch_size, comp_data.str, comp_data.size); + } break; + case ELF_CompressType_ZStd: { + // TODO: zstd lib + NotImplemented; + } break; + default: InvalidPath; break; + } + + // TODO: error handling + AssertAlways(actual_decomp_size == chdr64.ch_size); + + // set decompressed section data + data = str8(decomp_buffer, actual_decomp_size); + } + + sect_status[s] = 1; + DW_Section *d = &result.sec[s]; + d->name = push_str8_copy(arena, name); + d->data = data; + d->is_dwo = is_dwo; + } + } + } + + scratch_end(scratch); + return result; +} diff --git a/src/dwarf/dwarf_elf.h b/src/dwarf/dwarf_elf.h new file mode 100644 index 00000000..776e7b2c --- /dev/null +++ b/src/dwarf/dwarf_elf.h @@ -0,0 +1,11 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DWARF_ELF_H +#define DWARF_ELF_H + +internal DW_Input dw_input_from_elf_section_table(Arena *arena, String8 raw_image, ELF_BinInfo *bin); + +#endif // DWARF_ELF_H + + diff --git a/src/dwarf/dwarf_enum.c b/src/dwarf/dwarf_enum.c index 68b29463..ae41b06b 100644 --- a/src/dwarf/dwarf_enum.c +++ b/src/dwarf/dwarf_enum.c @@ -7,12 +7,10 @@ dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op) String8 result = {0}; #define X(_N,...) case DW_ExprOp_##_N: result = str8_lit(Stringify(_N)); goto exit; - switch (ext) { - case DW_Ext_Null: break; - case DW_Ext_LLVM: break; - case DW_Ext_APPLE: break; - case DW_Ext_MIPS: break; - case DW_Ext_GNU: DW_Expr_GNU_XList(X); break; + if (ext & DW_Ext_GNU) { + switch (op) { + DW_Expr_GNU_XList(X); + } } switch (ver) { @@ -48,6 +46,7 @@ internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind) { switch (kind) { + case DW_Tag_Null: return str8_lit("Null"); #define X(_N,_ID) case DW_Tag_##_N: return str8_lit(Stringify(_N)); DW_Tag_V3_XList(X) DW_Tag_V5_XList(X) @@ -149,6 +148,50 @@ dw_string_from_language(Arena *arena, DW_Language kind) return push_str8f(arena, "%x", kind); } +internal String8 +dw_string_from_inl(Arena *arena, DW_InlKind kind) +{ + switch (kind) { +#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N)); + DW_Inl_XList(X) +#undef X + } + return push_str8f(arena, "%x", kind); +} + +internal String8 +dw_string_from_access_kind(Arena *arena, DW_AccessKind kind) +{ + switch (kind) { +#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N)); + DW_AccessKind_XList(X) +#undef X + } + return push_str8f(arena, "%llx", kind); +} + +internal String8 +dw_string_from_calling_convetion(Arena *arena, DW_CallingConventionKind kind) +{ + switch (kind) { +#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N)); + DW_CallingConventionKind_XList(X) +#undef X + } + return push_str8f(arena, "%llx", kind); +} + +internal String8 +dw_string_from_attrib_type_encoding(Arena *arena, DW_ATE kind) +{ + switch (kind) { +#define X(_N,_ID) case _ID: return str8_lit(Stringify(_N)); + DW_ATE_XList(X) +#undef X + } + return push_str8f(arena, "%llx", kind); +} + internal String8 dw_string_from_std_opcode(Arena *arena, DW_StdOpcode kind) { @@ -173,7 +216,7 @@ dw_string_from_ext_opcode(Arena *arena, DW_ExtOpcode kind) } internal String8 -dw_string_from_loc_list_entry_kind(Arena *arena, DW_LocListEntryKind kind) +dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind) { NotImplemented; return str8_zero(); @@ -187,7 +230,7 @@ dw_string_from_section_kind(Arena *arena, DW_SectionKind kind) } internal String8 -dw_string_from_rng_list_entry_kind(Arena *arena, DW_RngListEntryKind kind) +dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind) { NotImplemented; return str8_zero(); @@ -201,14 +244,14 @@ dw_string_from_register(Arena *arena, Arch arch, U64 reg_id) case Arch_Null: break; case Arch_x86: { switch (reg_id) { - #define X(_N, _ID, ...) case DW_Reg_x86_##_N: reg_str = str8_lit(Stringify(_ID)); break; + #define X(_N, _ID, ...) case DW_RegX86_##_N: reg_str = str8_lit(Stringify(_N)); break; DW_Regs_X86_XList(X) #undef X } } break; case Arch_x64: { switch (reg_id) { - #define X(_N, _ID, ...) case DW_Reg_x64_##_N: reg_str = str8_lit(Stringify(_ID)); break; + #define X(_N, _ID, ...) case DW_RegX64_##_N: reg_str = str8_lit(Stringify(_N)); break; DW_Regs_X64_XList(X) #undef X } diff --git a/src/dwarf/dwarf_enum.h b/src/dwarf/dwarf_enum.h index 1bbc3898..1a770ee9 100644 --- a/src/dwarf/dwarf_enum.h +++ b/src/dwarf/dwarf_enum.h @@ -8,6 +8,7 @@ internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind); internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind); internal String8 dw_string_from_form_kind(Arena *arena, DW_Version ver, DW_FormKind kind); +internal String8 dw_string_access_kind(Arena *arena, DW_AccessKind kind); //internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id); diff --git a/src/dwarf/dwarf_expr.c b/src/dwarf/dwarf_expr.c index fe4fd9a1..98309b97 100644 --- a/src/dwarf/dwarf_expr.c +++ b/src/dwarf/dwarf_expr.c @@ -3,13 +3,16 @@ //- analyzers +#if 0 internal DW_SimpleLoc dw_expr__analyze_fast(void *base, Rng1U64 range, U64 text_section_base) { DW_SimpleLoc result = {DW_SimpleLocKind_Empty}; + String8 expr_data = str8((U8*)data+range.min, (U8*)data+range.max); + U8 op = 0; - if (dw_based_range_read(base, range, 0, 1, &op)) { + if (str8_deserial_read_struct(expr_data, 0, &op)) { // step params U64 size_param = 0; B32 is_signed = 0; @@ -548,12 +551,14 @@ dw_expr__analyze_details(void *in_base, Rng1U64 in_range, DW_ExprMachineCallConf scratch_end(scratch); return result; } +#endif //- full eval internal DW_Location dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_ExprMachineConfig *config) { +#if 0 Temp scratch = scratch_begin(&arena_optional, 1); DW_Location result = {0}; @@ -1322,8 +1327,12 @@ dw_expr__eval(Arena *arena_optional, void *expr_base, Rng1U64 expr_range, DW_Exp // clear stack scratch_end(scratch); return result; +#endif + DW_Location result = {0}; + return result; } + //- dw expr val stack internal DW_ExprStack diff --git a/src/dwarf/dwarf_parse.c b/src/dwarf/dwarf_parse.c index aa2c7d3e..a8722d0e 100644 --- a/src/dwarf/dwarf_parse.c +++ b/src/dwarf/dwarf_parse.c @@ -1,66 +1,6 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -// TODO(rjf): -// -// [ ] Any time we encode a subrange of a section inside of a -// DW_AttribValue, we need to do that consistently, regardless of -// whether or not it is a string, memory block, etc. We should just use -// the DW_SectionKind and then the min/max pair. -// -// [ ] Things we are not reporting, or haven't figured out: -// @dwarf_expr @dwarf_v5 @dw_cross_unit -// [ ] currently, we're filtering out template arguments in the member accelerator. -// this is because they don't correspond one-to-one with anything in PDB, but -// they do contain useful information that we might want to expose another way -// somehow. -// [ ] DWARF V5 features that nobody seems to use right now -// [ ] ref_addr_desc + next_info_ctx -// apparently these are necessary when dereferencing some DWARF V5 ways of -// forming references. They don't seem to come up at all for any real data -// but might be a case somewhere. -// [ ] case when only .debug_line and .debug_line_str is available, without -// compilation unit debug info? do we care about this at all? -// [ ] DW_Form_RefSig8, which requires using .debug_names -// to do a lookup for a reference -// [ ] DWARF V5, but also V1 & V2 for dw_range_list_from_range_offset -// [ ] DW_AttribClass_RngList and DW_Form_RngListx -// [ ] DW_OpCode_XDEREF_SIZE + DW_OpCode_XDEREF -// [ ] DW_OpCode_PIECE + DW_OpCode_BIT_PIECE -// [ ] DW_ExtOpcode_DefineFile, for line info -// [ ] DWARF procedures in DWARF expr evaluation -// [ ] DW_Attrib_DataMemberLocation is not being *fully* handled right -// now; full handling requires evaluating a DWARF expression to find out the -// offset of a member. Right now we handle the common case, which is when it -// is encoded as a constant value. -// [ ] inline information -// [ ] full info we are not handling: -// [ ] friend classes -// [ ] DWARF macro info -// [ ] whether or not a function is the entry point -// [ ] attributes we are not handling that may be important: -// [ ] DW_Attrib_AbstractOrigin -// - ??? -// [ ] DW_Attrib_VariableParameter -// - determines whether or not a parameter to a function is mutable, I think? -// [ ] DW_Attrib_Mutable -// - I think this is for specific keywords, may not be relevant to C/++ -// [ ] DW_Attrib_CallColumn -// - column position of an inlined subroutine -// [ ] DW_Attrib_CallFile -// - file of inlined subroutine -// [ ] DW_Attrib_CallLine -// - line number of inlined subroutine -// [ ] DW_Attrib_ConstExpr -// - ??? maybe C++ constexpr? -// [ ] DW_Attrib_EnumClass -// - c++ thing that's an enum with a backing type -// [ ] DW_Attrib_LinkageName -// - name used to do linking - -//////////////////////////////// -//~ rjf: Basic Helpers - internal U64 dw_hash_from_string(String8 string) { @@ -68,86 +8,97 @@ dw_hash_from_string(String8 string) return hash64; } -//////////////////////////////// -//~ rjf: DWARF-Specific Based Range Reads - internal U64 -dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out) +str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out) { - String8 data = str8((U8*)base+range.min, dim_1u64(range)); - return str8_deserial_read(data, offset, out, size, 1); -} - -internal String8 -dw_based_range_read_string(void *base, Rng1U64 range, U64 offset) -{ - String8 data = str8((U8*)base+range.min, dim_1u64(range)); - String8 result = {0}; - str8_deserial_read_cstr(data, offset, &result); - return result; -} - -internal void * -dw_based_range_ptr(void *base, Rng1U64 range, U64 offset) -{ - Assert(offset < dim_1u64(range)); - U8 *data = (U8*)base + range.min + offset; - return data; -} - -internal void * -dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size) -{ - void *ptr = 0; - if (size > 0 && offset + size <= dim_1u64(range)) { - ptr = dw_based_range_ptr(base, range, offset); - } - return ptr; -} - -internal U64 -dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value) -{ - U64 value = 0; U64 bytes_read = 0; - U64 shift = 0; - U8 byte = 0; - for(U64 cursor = offset; - dw_based_range_read_struct(base, range, cursor, &byte) == 1; - cursor += 1) - { - bytes_read += 1; - U8 val = byte & 0x7fu; - value |= ((U64)val) << shift; - if((byte&0x80u) == 0) - { - break; + if (str8_deserial_read(string, off, size_out, sizeof(U32), sizeof(U32))) { + if (*size_out == max_U32) { + if (str8_deserial_read_struct(string, off+sizeof(U32), size_out)) { + bytes_read = sizeof(U32) + sizeof(U64); + } + } else { + *size_out &= (U64)max_U32; + bytes_read = sizeof(U32); } - shift += 7u; - } - if(out_value != 0) - { - *out_value = value; } return bytes_read; } internal U64 -dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value) +str8_deserial_read_dwarf_uint(String8 string, U64 off, DW_Format format, U64 *uint_out) { - U64 value = 0; U64 bytes_read = 0; - U64 shift = 0; - U8 byte = 0; - for(U64 cursor = offset; - dw_based_range_read_struct(base, range, cursor, &byte) == 1; - cursor += 1) + switch (format) { + case DW_Format_Null: break; + case DW_Format_32Bit: { + *uint_out &= (U64)max_U32; + bytes_read = str8_deserial_read(string, off, uint_out, sizeof(U32), sizeof(U32)); + } break; + case DW_Format_64Bit: { + bytes_read = str8_deserial_read_struct(string, off, uint_out); + } break; + } + return bytes_read; +} + +internal U64 +str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) { - bytes_read += 1; + U8 byte = 0; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + + if(bytes_read != sizeof(byte)) + { + break; + } + U8 val = byte & 0x7fu; value |= ((U64)val) << shift; + + cursor += bytes_read; shift += 7u; - if((byte&0x80u) == 0) + + if((byte & 0x80u) == 0) + { + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) + { + U8 byte; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + if(bytes_read != sizeof(byte)) + { + break; + } + + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + + cursor += bytes_read; + shift += 7u; + + if((byte & 0x80u) == 0) { if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) { @@ -156,43 +107,338 @@ dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_valu break; } } - if(out_value != 0) + if(value_out != 0) { - *out_value = value; + *value_out = value; } + U64 bytes_read = cursor - off; return bytes_read; } internal U64 -dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value) +str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out) { + Temp temp = temp_begin(arena); + + U64 *arr = push_array(arena, U64, count); + U64 i, cursor; + for (i = 0, cursor = off; i < count; ++i) { + U64 read_size = str8_deserial_read_uleb128(string, cursor, &arr[i]); + if (read_size == 0) { + break; + } + cursor += read_size; + } + U64 bytes_read = 0; - U64 value = 0; - U32 first32 = 0; - if(dw_based_range_read_struct(base, range, offset, &first32)) - { - // NOTE(rjf): DWARF 32-bit => use the first 32 bits as the size. - if(first32 != max_U32) - { - value = (U64)first32; - bytes_read = sizeof(U32); - } - // NOTE(rjf): DWARF 64-bit => first 32 are just a marker, use the next 64 bits as the size. - else if(dw_based_range_read_struct(base, range, offset + sizeof(U32), &value)) - { - value = 0; - bytes_read = sizeof(U32) + sizeof(U64); - } - } - if(out_value != 0) - { - *out_value = value; + if (i == count) { + *arr_out = arr; + bytes_read = cursor - off; + } else { + temp_end(temp); + *arr_out = 0; } + return bytes_read; } internal U64 -dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev) +str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out) +{ + Temp temp = temp_begin(arena); + + S64 *arr = push_array(arena, S64, count); + U64 i, cursor; + for (i = 0, cursor = off; i < count; ++i) { + U64 read_size = str8_deserial_read_sleb128(string, cursor, &arr[i]); + if (read_size == 0) { + break; + } + cursor += read_size; + } + + U64 bytes_read = 0; + if (i == count) { + *arr_out = arr; + bytes_read = cursor - off; + } else { + temp_end(temp); + *arr_out = 0; + } + + return bytes_read; +} + +internal DW_SectionKind +dw_section_kind_from_string(String8 string) +{ + DW_SectionKind s = DW_Section_Null; +#define X(_K,_L,_M,_W) \ + if (str8_match_lit(_L, string, 0)) { s = DW_Section_##_K; } \ + if (str8_match_lit(_M, string, 0)) { s = DW_Section_##_K; } + DW_SectionKind_XList(X) +#undef X + return s; +} + +internal DW_SectionKind +dw_section_dwo_kind_from_string(String8 string) +{ + DW_SectionKind s = DW_Section_Null; +#define X(_K,_L,_M,_W) \ + if (str8_match_lit(_W, string, 0)) { s = DW_Section_##_K; } + DW_SectionKind_XList(X) +#undef X + return s; +} + +internal Rng1U64List +dw_unit_ranges_from_data(Arena *arena, String8 data) +{ + Rng1U64List result = {0}; + + for (U64 cursor = 0; cursor < data.size; ) { + // read CU size + U64 cu_size = 0; + U64 cu_size_size = str8_deserial_read_dwarf_packed_size(data, cursor, &cu_size); + + // was read ok? + if (cu_size_size == 0) { + break; + } + + if (cu_size > 0) { + // push unit range + rng1u64_list_push(arena, &result, rng_1u64(cursor, cursor+cu_size+cu_size_size)); + } + + // advance + cursor += cu_size_size; + cursor += cu_size; + } + + return result; +} + +internal U64 +dw_read_list_unit_header_addr(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version_size) { + if (version >= DW_Version_5) { + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, + unit_length_size + version_size, + &address_size); + + if (address_size_size && address_size) { + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, + unit_length_size + version_size + address_size_size, + &segment_selector_size); + if (segment_selector_size_size) { + header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size; + + lu_out->version = version; + lu_out->segment_selector_size = segment_selector_size; + lu_out->address_size = address_size; + lu_out->entry_size = segment_selector_size + address_size; + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + } + } + + return header_size; +} + +internal U64 +dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version >= DW_Version_5) { + U16 padding = 0; + U64 padding_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &padding); + + if (padding_size && padding == 0) { + header_size = unit_length_size + version_size + padding_size; + + lu_out->version = version; + lu_out->address_size = 0; + lu_out->segment_selector_size = 0; + lu_out->entry_size = dw_size_from_format(DW_FormatFromSize(unit_length)); + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + + return header_size; +} + +internal U64 +dw_read_list_unit_header_list(String8 unit_data, DW_ListUnit *lu_out) +{ + U64 header_size = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, 0, &unit_length); + + if (unit_length_size) { + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_length_size, &version); + + if (version >= DW_Version_5) { + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size, &address_size); + + if (address_size_size && address_size > 0) { + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size, &segment_selector_size); + + if (segment_selector_size_size) { + U32 offset_entry_count = 0; + U64 offset_entry_count_size = str8_deserial_read_struct(unit_data, unit_length_size + version_size + address_size_size + segment_selector_size, &offset_entry_count); + + if (offset_entry_count_size) { + header_size = unit_length_size + version_size + address_size_size + segment_selector_size_size + offset_entry_count_size; + + lu_out->version = version; + lu_out->address_size = address_size; + lu_out->segment_selector_size = segment_selector_size; + lu_out->entry_size = dw_size_from_format(DW_FormatFromSize(unit_length)); + lu_out->entries = str8_skip(unit_data, header_size); + } + } + } + } + } + + return header_size; +} + +internal DW_ListUnitInput +dw_list_unit_input_from_input(Arena *arena, DW_Input *input) +{ + Temp scratch = scratch_begin(&arena, 1); + + DW_ListUnitInput result = {0}; + + DW_Section debug_addr = input->sec[DW_Section_Addr]; + { + String8 data = debug_addr.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.addr_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.addr_count = unit_ranges.count; + result.addrs = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.addr_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(debug_addr.data, result.addr_ranges.v[unit_idx]); + dw_read_list_unit_header_addr(unit_data, &result.addrs[unit_idx]); + } + } + + DW_Section debug_str_offsets = input->sec[DW_Section_StrOffsets]; + { + String8 data = debug_str_offsets.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.str_offset_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.str_offset_count = unit_ranges.count; + result.str_offsets = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.str_offset_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.str_offset_ranges.v[unit_idx]); + dw_read_list_unit_header_str_offsets(unit_data, &result.str_offsets[unit_idx]); + } + } + + DW_Section debug_rnglists = input->sec[DW_Section_RngLists]; + { + String8 data = debug_rnglists.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.rnglist_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.rnglist_count = unit_ranges.count; + result.rnglists = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.rnglist_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.rnglist_ranges.v[unit_idx]); + dw_read_list_unit_header_list(unit_data, &result.rnglists[unit_idx]); + } + } + + DW_Section debug_loclists = input->sec[DW_Section_LocLists]; + { + String8 data = debug_loclists.data; + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, data); + + result.loclist_ranges = rng1u64_array_from_list(arena, &unit_ranges); + result.loclist_count = unit_ranges.count; + result.loclists = push_array(arena, DW_ListUnit, unit_ranges.count); + + for (U64 unit_idx = 0; unit_idx < result.loclist_ranges.count; ++unit_idx) { + String8 unit_data = str8_substr(data, result.loclist_ranges.v[unit_idx]); + dw_read_list_unit_header_list(unit_data, &result.loclists[unit_idx]); + } + } + + scratch_end(scratch); + return result; +} + +internal U64 +dw_offset_from_list_unit(DW_ListUnit *lu, U64 index) +{ + U64 offset; + U64 entry_off = index * lu->entry_size; + if (entry_off + lu->entry_size <= lu->entries.size) { + offset = 0; + MemoryCopy(&offset, lu->entries.str + entry_off, lu->entry_size); + } else { + offset = max_U64; + } + return offset; +} + +internal U64 +dw_addr_from_list_unit(DW_ListUnit *lu, U64 index) +{ + U64 seg = 0; + U64 addr = max_U64; + U64 entry_count = lu->entries.size / lu->entry_size; + if (index < entry_count) { + U64 seg_off = lu->entry_size * index; + U64 addr_off = seg_off + lu->segment_selector_size; + MemoryCopy(&seg, lu->entries.str + seg_off, lu->segment_selector_size); + MemoryCopy(&addr, lu->entries.str + addr_off, lu->address_size); + // TODO: segment-based addressing + AssertAlways(seg == 0); + } else { + Assert(!"out of bounds index"); + } + return addr; +} + +internal U64 +dw_read_abbrev_tag(String8 data, U64 offset, DW_Abbrev *out_abbrev) { U64 total_bytes_read = 0; @@ -201,7 +447,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); + U64 bytes_read = str8_deserial_read_uleb128(data, id_off, &id); sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -211,7 +457,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U64 next_off = sub_kind_off; if(id != 0) { - U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + U64 bytes_read = str8_deserial_read_uleb128(data, sub_kind_off, &sub_kind); next_off += bytes_read; total_bytes_read += bytes_read; } @@ -220,17 +466,16 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev U8 has_children = 0; if(id != 0) { - total_bytes_read += dw_based_range_read_struct(base, range, next_off, &has_children); + total_bytes_read += str8_deserial_read_struct(data, next_off, &has_children); } //- rjf: fill abbrev if(out_abbrev != 0) { - DW_Abbrev abbrev = {0}; - abbrev.kind = DW_Abbrev_Tag; - abbrev.abbrev_range = rng_1u64(range.min+offset, range.min+offset+total_bytes_read); - abbrev.sub_kind = sub_kind; - abbrev.id = id; + DW_Abbrev abbrev = {0}; + abbrev.kind = DW_Abbrev_Tag; + abbrev.sub_kind = sub_kind; + abbrev.id = id; if(has_children) { abbrev.flags |= DW_AbbrevFlag_HasChildren; @@ -242,7 +487,7 @@ dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev } internal U64 -dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev) +dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev) { U64 total_bytes_read = 0; @@ -251,7 +496,7 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind_off = id_off; U64 id = 0; { - U64 bytes_read = dw_based_range_read_uleb128(base, range, id_off, &id); + U64 bytes_read = str8_deserial_read_uleb128(data, id_off, &id); sub_kind_off += bytes_read; total_bytes_read += bytes_read; } @@ -260,7 +505,7 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 sub_kind = 0; U64 next_off = sub_kind_off; { - U64 bytes_read = dw_based_range_read_uleb128(base, range, sub_kind_off, &sub_kind); + U64 bytes_read = str8_deserial_read_uleb128(data, sub_kind_off, &sub_kind); next_off += bytes_read; total_bytes_read += bytes_read; } @@ -269,7 +514,7 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW U64 implicit_const = 0; if(sub_kind == DW_Form_ImplicitConst) { - U64 bytes_read = dw_based_range_read_uleb128(base, range, next_off, &implicit_const); + U64 bytes_read = str8_deserial_read_uleb128(data, next_off, &implicit_const); total_bytes_read += bytes_read; } @@ -278,7 +523,6 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW { DW_Abbrev abbrev = {0}; abbrev.kind = DW_Abbrev_Attrib; - abbrev.abbrev_range = rng_1u64(offset, offset+total_bytes_read); abbrev.sub_kind = sub_kind; abbrev.id = id; if(sub_kind == DW_Form_ImplicitConst) @@ -292,200 +536,16 @@ dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW return total_bytes_read; } -internal U64 -dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out) -{ - U64 bytes_read = 0; - U64 bytes_to_read = 0; - DW_AttribValue form_value = {0}; - - switch(form_kind) - { - case DW_Form_Null: break; - - //- rjf: 1-byte uint reads - case DW_Form_Ref1: case DW_Form_Data1: case DW_Form_Flag: - case DW_Form_Strx1: case DW_Form_Addrx1: - bytes_to_read = 1; goto read_fixed_uint; - - //- rjf: 2-byte uint reads - case DW_Form_Ref2: case DW_Form_Data2: case DW_Form_Strx2: - case DW_Form_Addrx2: - bytes_to_read = 2; goto read_fixed_uint; - - //- rjf: 3-byte uint reads - case DW_Form_Strx3: case DW_Form_Addrx3: - bytes_to_read = 3; goto read_fixed_uint; - - //- rjf: 4-byte uint reads - case DW_Form_Data4: case DW_Form_Ref4: case DW_Form_RefSup4: case DW_Form_Strx4: case DW_Form_Addrx4: - bytes_to_read = 4; goto read_fixed_uint; - - //- rjf: 8-byte uint reads - case DW_Form_Data8: case DW_Form_Ref8: case DW_Form_RefSig8: case DW_Form_RefSup8: - bytes_to_read = 8; goto read_fixed_uint; - - //- rjf: address-size reads - case DW_Form_Addr: bytes_to_read = address_size; goto read_fixed_uint; - - //- rjf: offset-size reads - case DW_Form_RefAddr: case DW_Form_SecOffset: case DW_Form_LineStrp: - case DW_Form_Strp: case DW_Form_StrpSup: - bytes_to_read = dw_offset_size_from_mode(mode); goto read_fixed_uint; - - //- rjf: fixed-size uint reads - { - read_fixed_uint:; - U64 value = 0; - bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &value); - form_value.v[0] = value; - } break; - - //- rjf: uleb128 reads - case DW_Form_UData: case DW_Form_RefUData: case DW_Form_Strx: - case DW_Form_Addrx: case DW_Form_LocListx: case DW_Form_RngListx: - { - U64 value = 0; - bytes_read = dw_based_range_read_uleb128(base, range, offset, &value); - form_value.v[0] = value; - } break; - - //- rjf: sleb128 reads - case DW_Form_SData: - { - S64 value = 0; - bytes_read = dw_based_range_read_sleb128(base, range, offset, &value); - form_value.v[0] = value; - } break; - - //- rjf: fixed-size uint read + skip - case DW_Form_Block1: bytes_to_read = 1; goto read_fixed_uint_skip; - case DW_Form_Block2: bytes_to_read = 2; goto read_fixed_uint_skip; - case DW_Form_Block4: bytes_to_read = 4; goto read_fixed_uint_skip; - { - read_fixed_uint_skip:; - U64 size = 0; - bytes_read = dw_based_range_read(base, range, offset, bytes_to_read, &size); - form_value.v[0] = size; - form_value.v[1] = offset; - bytes_read += size; - } break; - - //- rjf: uleb 128 read + skip - case DW_Form_Block: - { - U64 size = 0; - bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); - form_value.v[0] = size; - form_value.v[1] = offset; - bytes_read += size; - } break; - - //- rjf: u64 ranges - case DW_Form_Data16: - { - U64 value1 = 0; - U64 value2 = 0; - bytes_read += dw_based_range_read_struct(base, range, offset, &value1); - bytes_read += dw_based_range_read_struct(base, range, offset + sizeof(U64), &value2); - form_value.v[0] = value1; - form_value.v[1] = value2; - } break; - - //- rjf: strings - case DW_Form_String: - { - String8 string = dw_based_range_read_string(base, range, offset); - bytes_read = string.size + 1; - U64 string_offset = offset; - U64 string_size = (offset + bytes_read) - string_offset; - form_value.v[0] = string_offset; - form_value.v[1] = string_offset+string_size-1; - } break; - - //- rjf: implicit const - case DW_Form_ImplicitConst: - { - // Special case. - // Unlike other forms that have their values stored in the .debug_info section, - // This one defines it's value in the .debug_abbrev section. - form_value.v[0] = implicit_const; - } break; - - //- rjf: expr loc - case DW_Form_ExprLoc: - { - U64 size = 0; - bytes_read = dw_based_range_read_uleb128(base, range, offset, &size); - form_value.v[0] = offset + bytes_read; - form_value.v[1] = size; - bytes_read += size; - } break; - - //- rjf: flag present - case DW_Form_FlagPresent: - { - form_value.v[0] = 1; - } break; - - case DW_Form_Indirect: - { - InvalidPath; - } break; - } - - if(form_value_out != 0) - { - *form_value_out = form_value; - } - - return bytes_read; -} - -//- rjf: important DWARF section base/range accessors - -internal DW_Mode -dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind) -{ - if(sections->v[kind].data.size > 0xffffffff) - { - return DW_Mode_64Bit; - } - else - { - return DW_Mode_32Bit; - } -} - -internal Rng1U64 -dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind) -{ - Rng1U64 result = rng_1u64(0, sections->v[kind].data.size); - return result; -} - -internal void * -dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind) -{ - return sections->v[kind].data.str; -} - -//////////////////////////////// -//~ rjf: Abbrev Table - internal DW_AbbrevTable -dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 abbrev_offset) +dw_make_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_offset) { - void *file_base = dw_base_from_sec(sections, DW_Section_Abbrev); - Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); - //- rjf: count the tags we have U64 tag_count = 0; - for(U64 abbrev_read_off = abbrev_offset - abbrev_range.min;;) + for(U64 abbrev_read_off = abbrev_offset;;) { DW_Abbrev tag; { - U64 bytes_read = dw_based_range_read_abbrev_tag(file_base, abbrev_range, abbrev_read_off, &tag); + U64 bytes_read = dw_read_abbrev_tag(abbrev_data, abbrev_read_off, &tag); abbrev_read_off += bytes_read; if(bytes_read == 0 || tag.id == 0) { @@ -495,7 +555,7 @@ dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 abbrev_offset) for(;;) { DW_Abbrev attrib = {0}; - U64 bytes_read = dw_based_range_read_abbrev_attrib_info(file_base, abbrev_range, abbrev_read_off, &attrib); + U64 bytes_read = dw_read_abbrev_attrib(abbrev_data, abbrev_read_off, &attrib); abbrev_read_off += bytes_read; if(bytes_read == 0 || attrib.id == 0) { @@ -512,11 +572,13 @@ dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 abbrev_offset) MemorySet(table.entries, 0, sizeof(DW_AbbrevTableEntry)*table.count); U64 tag_idx = 0; - for(U64 abbrev_read_off = abbrev_offset - abbrev_range.min;;) + for(U64 abbrev_read_off = abbrev_offset;;) { + U64 tag_abbrev_off = abbrev_read_off; + DW_Abbrev tag; { - U64 bytes_read = dw_based_range_read_abbrev_tag(file_base, abbrev_range, abbrev_read_off, &tag); + U64 bytes_read = dw_read_abbrev_tag(abbrev_data, abbrev_read_off, &tag); abbrev_read_off += bytes_read; if(bytes_read == 0 || tag.id == 0) { @@ -527,14 +589,14 @@ dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 abbrev_offset) // rjf: insert this tag into the table { table.entries[tag_idx].id = tag.id; - table.entries[tag_idx].off = tag.abbrev_range.min; + table.entries[tag_idx].off = tag_abbrev_off; tag_idx += 1; } for(;;) { DW_Abbrev attrib = {0}; - U64 bytes_read = dw_based_range_read_abbrev_attrib_info(file_base, abbrev_range, abbrev_read_off, &attrib); + U64 bytes_read = dw_read_abbrev_attrib(abbrev_data, abbrev_read_off, &attrib); abbrev_read_off += bytes_read; if(bytes_read == 0 || attrib.id == 0) { @@ -551,24 +613,15 @@ internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id) { U64 abbrev_offset = max_U64; - if(table.count > 0) - { - S64 min = 0; - S64 max = (S64)table.count - 1; - while(min <= max) - { - S64 mid = (min + max) / 2; - if (abbrev_id > table.entries[mid].id) - { - min = mid + 1; - } - else if (abbrev_id < table.entries[mid].id) - { - max = mid - 1; - } - else - { - abbrev_offset = table.entries[mid].off; + if (table.count > 0) { + for (S64 l = 0, r = (S64)table.count - 1; l <= r; ) { + S64 m = l + (r - l) / 2; + if (abbrev_id > table.entries[m].id) { + l = m + 1; + } else if (abbrev_id < table.entries[m].id) { + r = m - 1; + } else { + abbrev_offset = table.entries[m].off; break; } } @@ -576,1168 +629,2108 @@ dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id) return abbrev_offset; } -//////////////////////////////// -//~ rjf: Miscellaneous DWARF Section Parsing - -//- rjf: .debug_ranges (DWARF V4) - -internal Rng1U64List -dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off) +internal U64 +dw_read_form(String8 data, + U64 off, + DW_Version version, + DW_Format unit_format, + U64 address_size, + DW_FormKind form_kind, + U64 implicit_const, + DW_Form *form_out) { - void *base = dw_base_from_sec(sections, DW_Section_Ranges); - Rng1U64 rng = dw_range_from_sec(sections, DW_Section_Ranges); + U64 bytes_read = 0; + DW_Form form = {0}; - Rng1U64List list = {0}; - - U64 read_off = range_off; - U64 base_addr = comp_unit_base_addr; - - for(;read_off < rng.max;) - { - U64 v0 = 0; - U64 v1 = 0; - read_off += dw_based_range_read(base, rng, read_off, addr_size, &v0); - read_off += dw_based_range_read(base, rng, read_off, addr_size, &v1); - - //- rjf: base address entry - if((addr_size == 4 && v0 == 0xffffffff) || - (addr_size == 8 && v0 == 0xffffffffffffffff)) - { - base_addr = v1; + switch (form_kind) { + case DW_Form_Null: break; + + case DW_Form_Addr: { + bytes_read = str8_deserial_read_block(data, off, address_size, &form.addr); + } break; + case DW_Form_Block2: { + U16 size = 0; + U64 size_size = str8_deserial_read_struct(data, off, &size); + if (size_size) { + U64 block_size = str8_deserial_read_block(data, off + size_size, size, &form.block); + if (block_size) { + bytes_read = size_size + block_size; + } } - //- rjf: end-of-list entry - else if(v0 == 0 && v1 == 0) - { - break; + } break; + case DW_Form_Block4: { + U32 size = 0; + U64 size_size = str8_deserial_read_struct(data, off, &size); + if (size_size) { + U64 block_size = str8_deserial_read_block(data, off + size_size, size, &form.block); + if (block_size) { + bytes_read = size_size + block_size; + } } - //- rjf: range list entry - else - { - U64 min_addr = v0 + base_addr; - U64 max_addr = v1 + base_addr; - rng1u64_list_push(arena, &list, rng_1u64(min_addr, max_addr)); + } break; + case DW_Form_Data2: { + bytes_read = str8_deserial_read_block(data, off, sizeof(U16), &form.data); + } break; + case DW_Form_Data4: { + bytes_read = str8_deserial_read_block(data, off, sizeof(U32), &form.data); + } break; + case DW_Form_Data8: { + bytes_read = str8_deserial_read_block(data, off, sizeof(U64), &form.data); + } break; + case DW_Form_String: { + bytes_read = str8_deserial_read_cstr(data, off, &form.string); + } break; + case DW_Form_Block: { + U64 size = 0; + U64 size_size = str8_deserial_read_uleb128(data, off, &size); + if (size_size) { + U64 block_size = str8_deserial_read_block(data, off + size_size, size, &form.block); + if (block_size) { + bytes_read = size_size + block_size; + } } + } break; + case DW_Form_Block1: { + U8 size = 0; + U64 size_size = str8_deserial_read_struct(data, off, &size); + if (size_size) { + U64 block_size = str8_deserial_read_block(data, off, size, &form.block); + if (block_size == size) { + bytes_read = size_size + block_size; + } + } + } break; + case DW_Form_Data1: { + bytes_read = str8_deserial_read_block(data, off, sizeof(U8), &form.data); + } break; + case DW_Form_Flag: { + bytes_read = str8_deserial_read_struct(data, off, &form.flag); + } break; + case DW_Form_SData: { + bytes_read = str8_deserial_read_sleb128(data, off, &form.sdata); + } break; + case DW_Form_UData: { + bytes_read = str8_deserial_read_uleb128(data, off, &form.udata); + } break; + case DW_Form_RefAddr: { + if (version < DW_Version_3) { + bytes_read = str8_deserial_read(data, off, &form.ref, address_size, address_size); + } else { + bytes_read = str8_deserial_read_dwarf_uint(data, off, unit_format, &form.ref); + } + } break; + case DW_Form_GNU_RefAlt: { + bytes_read = str8_deserial_read_dwarf_uint(data, off, unit_format, &form.ref); + } break; + case DW_Form_Ref1: { + bytes_read = str8_deserial_read(data, off, &form.ref, 1, 1); + } break; + case DW_Form_Ref2: { + bytes_read = str8_deserial_read(data, off, &form.ref, 2, 2); + } break; + case DW_Form_Ref4: { + bytes_read = str8_deserial_read(data, off, &form.ref, 4, 4); + } break; + case DW_Form_Ref8: { + bytes_read = str8_deserial_read(data, off, &form.ref, 8, 8); + } break; + case DW_Form_RefUData: { + bytes_read = str8_deserial_read_uleb128(data, off, &form.ref); + } break; + case DW_Form_SecOffset: + case DW_Form_LineStrp: + case DW_Form_GNU_StrpAlt: + case DW_Form_Strp: { + bytes_read = str8_deserial_read_dwarf_uint(data, off, unit_format, &form.sec_offset); + } break; + case DW_Form_ExprLoc: { + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(data, off, &expr_size); + if (expr_size_size) { + if (str8_deserial_read_block(data, off + expr_size_size, expr_size, &form.exprloc)) { + bytes_read = expr_size_size + expr_size; + } + } + } break; + case DW_Form_FlagPresent: { + form.flag = 1; + } break; + case DW_Form_RefSig8: { + //U64 ref = 0; + //bytes_read = str8_deserial_read_struct(data, off, &ref); + NotImplemented; + } break; + case DW_Form_Addrx: + case DW_Form_RngListx: + case DW_Form_Strx: { + bytes_read = str8_deserial_read_uleb128(data, off, &form.xval); + } break; + case DW_Form_RefSup4: { + //U32 ref_sup4 = 0; + //bytes_read = str8_deserial_read_struct(data, off, &ref_sup4); + NotImplemented; + } break; + case DW_Form_StrpSup: { + bytes_read = str8_deserial_read_dwarf_uint(data, off, unit_format, &form.strp_sup); + } break; + case DW_Form_Data16: { + bytes_read = str8_deserial_read_block(data, off, 16, &form.data); + } break; + case DW_Form_ImplicitConst: { + // Special case. + // Unlike other forms that have their values stored in the .debug_info section, + // This one defines it's value in the .debug_abbrev section. + form.implicit_const = implicit_const; + } break; + case DW_Form_LocListx: { + bytes_read = str8_deserial_read_uleb128(data, off, &form.xval); + } break; + case DW_Form_RefSup8: { + NotImplemented; + } break; + case DW_Form_Strx1: { + bytes_read = str8_deserial_read(data, off, &form.xval, 1, 1); + } break; + case DW_Form_Strx2: { + bytes_read = str8_deserial_read(data, off, &form.xval, 2, 2); + } break; + case DW_Form_Strx3: { + bytes_read = str8_deserial_read(data, off, &form.xval, 3, 3); + } break; + case DW_Form_Strx4: { + bytes_read = str8_deserial_read(data, off, &form.xval, 4, 4); + } break; + case DW_Form_Addrx1: { + bytes_read = str8_deserial_read(data, off, &form.xval, 1, 1); + } break; + case DW_Form_Addrx2: { + bytes_read = str8_deserial_read(data, off, &form.xval, 2, 2); + } break; + case DW_Form_Addrx3: { + bytes_read = str8_deserial_read(data, off, &form.xval, 3, 3); + } break; + case DW_Form_Addrx4: { + bytes_read = str8_deserial_read(data, off, &form.xval, 4, 4); + } break; + default: InvalidPath; break; + } + + if (form_out) { + *form_out = form; } - return list; + return bytes_read; } -//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4) - -internal DW_PubStringsTable -dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind) +internal U64 +dw_read_tag(Arena *arena, + String8 tag_data, + U64 tag_off, + U64 tag_base, + DW_AbbrevTable abbrev_table, + String8 abbrev_data, + DW_Version version, + DW_Format unit_format, + U64 address_size, + DW_Tag *tag_out) { - Temp scratch = scratch_begin(&arena, 1); + U64 tag_cursor = tag_off; - DW_PubStringsTable names_table = {0}; - - // TODO(rjf): Arbitrary choice. - names_table.size = 16384; - names_table.buckets = push_array(arena, DW_PubStringsBucket*, names_table.size); - - void *base = dw_base_from_sec(sections, section_kind); - Rng1U64 rng = dw_range_from_sec(sections, section_kind); - DW_Mode mode = sections->v[section_kind].mode; - U64 off_size = dw_offset_size_from_mode(mode); - U64 cursor = 0; - - U64 table_length = 0; - U16 unit_version = 0; - U64 cu_info_off = 0; - U64 cu_info_len = 0; - cursor += dw_based_range_read_length(base, rng, cursor, &table_length); - cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); - cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); - cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); - - for(;;) - { - U64 info_off = 0; - { - U64 bytes_read = dw_based_range_read(base, rng, cursor, off_size, &info_off); - cursor += bytes_read; - if(bytes_read == 0) - { + // read tag abbrev id + U64 tag_abbrev_id = 0; + U64 tag_abbrev_id_size = str8_deserial_read_uleb128(tag_data, tag_cursor, &tag_abbrev_id); + Assert(tag_abbrev_id_size); + tag_cursor += tag_abbrev_id_size; + + // read tag abbrev + U64 abbrev_cursor = dw_abbrev_offset_from_abbrev_id(abbrev_table, tag_abbrev_id); + DW_Abbrev tag_abbrev = {0}; + U64 tag_abbrev_size = dw_read_abbrev_tag(abbrev_data, abbrev_cursor, &tag_abbrev); + + // read attribs + DW_AttribList attribs = {0}; + if (tag_abbrev_size > 0) { + abbrev_cursor += tag_abbrev_size; + + for (; tag_cursor < tag_data.size && abbrev_cursor < abbrev_data.size; ) { + U64 attrib_tag_cursor = tag_cursor; + U64 attrib_abbrev_off = abbrev_cursor; + + // read attrib abbrev + DW_Abbrev attrib_abbrev = {0}; + abbrev_cursor += dw_read_abbrev_attrib(abbrev_data, abbrev_cursor, &attrib_abbrev); + if (attrib_abbrev.id == 0) { break; } - } - - //- rjf: if we got a nonzero .debug_info offset, we've found a valid entry. - if(info_off != 0) - { - String8 string = dw_based_range_read_string(base, rng, cursor); - cursor += string.size + 1; - U64 hash = dw_hash_from_string(string); - U64 bucket_idx = hash % names_table.size; - - DW_PubStringsBucket *bucket = push_array(arena, DW_PubStringsBucket, 1); - bucket->next = names_table.buckets[bucket_idx]; - bucket->string = string; - bucket->info_off = info_off; - bucket->cu_info_off = cu_info_off; - names_table.buckets[bucket_idx] = bucket; - } - - //- rjf: if we did not read a proper entry in the table, we need to try to - // read the header of the next table. - else - { - U64 next_table_length = 0; - { - U64 bytes_read = dw_based_range_read_length(base, rng, cursor, &next_table_length); - if(bytes_read == 0 || next_table_length == 0) - { + DW_AttribKind attrib_kind = (DW_AttribKind)attrib_abbrev.id; + DW_FormKind form_kind = (DW_FormKind)attrib_abbrev.sub_kind; + + // special case, allows producer to embed form in .debug_info + if (form_kind == DW_Form_Indirect) { + U64 form_kind_size = str8_deserial_read_uleb128(tag_data, tag_cursor, &form_kind); + + if (form_kind_size == 0) { + Assert(!"unable to read indirect form kind"); break; } - cursor += bytes_read; + + tag_cursor += form_kind_size; } - cursor += dw_based_range_read_struct(base, rng, cursor, &unit_version); - cursor += dw_based_range_read(base, rng, cursor, off_size, &cu_info_off); - cursor += dw_based_range_read_length(base, rng, cursor, &cu_info_len); + + // read form value + DW_Form form = {0}; + tag_cursor += dw_read_form(tag_data, tag_cursor, version, unit_format, address_size, form_kind, attrib_abbrev.const_value, &form); + + // fill out node + DW_AttribNode *attrib_n = push_array(arena, DW_AttribNode, 1); + attrib_n->v.info_off = tag_base + attrib_tag_cursor; + attrib_n->v.abbrev_off = attrib_abbrev_off; + attrib_n->v.abbrev_id = attrib_abbrev.id; + attrib_n->v.attrib_kind = attrib_kind; + attrib_n->v.form_kind = form_kind; + attrib_n->v.form = form; + + // push node to list + SLLQueuePush(attribs.first, attribs.last, attrib_n); + ++attribs.count; } } - - scratch_end(scratch); - - return names_table; + + // fill out tag + tag_out->abbrev_id = tag_abbrev_id; + tag_out->has_children = !!(tag_abbrev.flags & DW_AbbrevFlag_HasChildren); + tag_out->kind = (DW_TagKind)tag_abbrev.sub_kind; + tag_out->attribs = attribs; + tag_out->info_off = tag_base + tag_off; + + U64 bytes_read = tag_cursor - tag_off; + return bytes_read; } -//- rjf: .debug_str_offsets (DWARF V5) - internal U64 -dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index) +dw_read_tag_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out) { - U64 result = 0; - - DW_Mode mode = sections->v[section].mode; - void *sec_base = dw_base_from_sec(sections, section); - Rng1U64 rng = dw_range_from_sec(sections, section); - U64 cursor = base; - - //- rjf: get the length of each entry - U64 entry_len = mode == DW_Mode_64Bit ? 8 : 4; - - //- rjf: parse the unit's length (not including the length itself) - U64 unit_length = 0; - cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); - - //- rjf: parse version - U16 version = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); - Assert(version == 5); // must be 5 as of V5. - - //- rjf: parse padding - U16 padding = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &padding); - Assert(padding == 0); // must be 0 as of V5. - - //- rjf: read - if (unit_length >= sizeof(U16)*2) - { - void *entries = (U8 *)sec_base + cursor; - U64 count = (unit_length - sizeof(U16)*2) / entry_len; - if(0 <= index && index < count) - { - switch(entry_len) - { - default: break; - case 4: result = ((U32 *)entries)[index]; break; - case 8: result = ((U64 *)entries)[index]; break; + String8 tag_data = str8_substr(input->sec[DW_Section_Info].data, cu->info_range); + U64 tag_off = info_off - cu->info_range.min; + return dw_read_tag(arena, tag_data, tag_off, cu->info_range.min, cu->abbrev_table, cu->abbrev_data, cu->version, cu->format, cu->address_size, tag_out); +} + +internal B32 +dw_try_u64_from_const_value(U64 type_byte_size, DW_ATE type_encoding, String8 const_value, U64 *value_out) +{ + B32 is_parsed = 0; + if (const_value.size <= type_byte_size) { + U64 value_size = Min(type_byte_size, const_value.size); + if (value_size <= sizeof(*value_out)) { + MemoryZeroStruct(value_out); + MemoryCopy(value_out, const_value.str, value_size); + if (type_encoding == DW_ATE_Signed || type_encoding == DW_ATE_SignedChar) { + *value_out = extend_sign64(*value_out, value_size); } + is_parsed = 1; + } else { + Assert(!"out value overflow"); } } - - return result; + return is_parsed; } -//- rjf: .debug_addr parsing - internal U64 -dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index) +dw_u64_from_const_value(String8 const_value) { - U64 result = 0; - - void *sec_base = dw_base_from_sec(sections, section); - Rng1U64 rng = dw_range_from_sec(sections, section); - U64 cursor = base; - - //- rjf: parse the unit's length (not including the length itself) - U64 unit_length = 0; - cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); - - //- rjf: parse version - U16 version = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); - Assert(version == 5); // must be 5 as of V5. - - //- rjf: parse address size - U8 address_size = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); - - //- rjf: parse segment selector size - U8 segment_selector_size = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); - - //- rjf: read - U64 entry_size = address_size + segment_selector_size; - U64 count = (unit_length - sizeof(U16)*2) / entry_size; - if(0 <= index && index < count) - { - void *entry = (U8 *)dw_based_range_ptr(sec_base, rng, cursor) + entry_size*index; - Rng1U64 entry_rng = rng_1u64(0, entry_size); - U64 segment = 0; - U64 addr = 0; - dw_based_range_read(entry, entry_rng, 0, sizeof(segment), &segment); - dw_based_range_read(entry, entry_rng, segment_selector_size, sizeof(addr), &addr); - result = addr; - } - + U64 result = 0; + B32 is_converted = dw_try_u64_from_const_value(sizeof(U64), DW_ATE_Unsigned, const_value, &result); + Assert(is_converted); // TODO: error handling return result; } -//- rjf: .debug_rnglists + .debug_loclists parsing - internal U64 -dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index) +dw_interp_sec_offset(DW_FormKind form_kind, DW_Form form) { - // - // NOTE(rjf): This is only appropriate to call when DW_Form_RngListx is - // used to access a range list, *OR* when DW_Form_LocListx is used to - // access a location list. Otherwise, DW_Form_SecOffset is required. - // - // See the DWARF V5 spec (February 13, 2017), page 242. (rnglists) - // See the DWARF V5 spec (February 13, 2017), page 215. (loclists) - // - - U64 result = 0; - - DW_Mode mode = sections->v[section_kind].mode; - void *sec_base = dw_base_from_sec(sections, section_kind); - Rng1U64 rng = dw_range_from_sec(sections, section_kind); - U64 cursor = base; - - //- rjf: get the length of each entry - U64 entry_len = mode == DW_Mode_64Bit ? 8 : 4; - - //- rjf: parse the unit's length (not including the length itself) - U64 unit_length = 0; - cursor += dw_based_range_read_length(sec_base, rng, cursor, &unit_length); - - //- rjf: parse version - U16 version = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &version); - Assert(version == 5); // must be 5 as of V5. - - //- rjf: parse address size - U8 address_size = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &address_size); - - //- rjf: parse segment selector size - U8 segment_selector_size = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &segment_selector_size); - - //- rjf: parse offset entry count - U32 offset_entry_count = 0; - cursor += dw_based_range_read_struct(sec_base, rng, cursor, &offset_entry_count); - - //- rjf: read from offsets array - U64 table_off = cursor; - void *offsets_arr = dw_based_range_ptr(sec_base, rng, cursor); - if(0 <= index && index < (U64)offset_entry_count) - { - U64 rnglist_offset = 0; - switch(entry_len) - { - default: break; - case 4: rnglist_offset = ((U32 *)offsets_arr)[index]; break; - case 8: rnglist_offset = ((U64 *)offsets_arr)[index]; break; - } - result = rnglist_offset+table_off; + U64 sec_offset = 0; + if (form_kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); } - - return result; -} - -internal Rng1U64List -dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset) -{ - Rng1U64List list = {0}; - - void *base = dw_base_from_sec(sections, section); - Rng1U64 rng = dw_range_from_sec(sections, section); - U64 cursor = offset; - - U64 base_addr = 0; - - for(B32 done = 0; !done;) - { - U8 kind8 = 0; - cursor += dw_based_range_read_struct(base, rng, cursor, &kind8); - DW_RngListEntryKind kind = (DW_RngListEntryKind)kind8; - - switch(kind) - { - //- rjf: can be used in split and non-split units: - default: - case DW_RngListEntryKind_EndOfList: - { - done = 1; - } break; - - case DW_RngListEntryKind_BaseAddressX: - { - U64 base_addr_idx = 0; - cursor += dw_based_range_read_uleb128(base, rng, cursor, &base_addr_idx); - base_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, base_addr_idx); - } break; - - case DW_RngListEntryKind_StartxEndx: - { - U64 start_addr_idx = 0; - U64 end_addr_idx = 0; - cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_addr_idx); - U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); - U64 end_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, end_addr_idx); - rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); - } break; - - case DW_RngListEntryKind_StartxLength: - { - U64 start_addr_idx = 0; - U64 length = 0; - cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_addr_idx); - cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); - U64 start_addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, addr_section_base, start_addr_idx); - U64 end_addr = start_addr + length; - rng1u64_list_push(arena, &list, rng_1u64(start_addr, end_addr)); - } break; - - case DW_RngListEntryKind_OffsetPair: - { - U64 start_offset = 0; - U64 end_offset = 0; - cursor += dw_based_range_read_uleb128(base, rng, cursor, &start_offset); - cursor += dw_based_range_read_uleb128(base, rng, cursor, &end_offset); - rng1u64_list_push(arena, &list, rng_1u64(start_offset + base_addr, end_offset + base_addr)); - } break; - - //- rjf: non-split units only: - - case DW_RngListEntryKind_BaseAddress: - { - U64 new_base_addr = 0; - cursor += dw_based_range_read(base, rng, cursor, addr_size, &new_base_addr); - base_addr = new_base_addr; - } break; - - case DW_RngListEntryKind_StartEnd: - { - U64 start = 0; - U64 end = 0; - cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); - cursor += dw_based_range_read(base, rng, cursor, addr_size, &end); - rng1u64_list_push(arena, &list, rng_1u64(start, end)); - } break; - - case DW_RngListEntryKind_StartLength: - { - U64 start = 0; - U64 length = 0; - cursor += dw_based_range_read(base, rng, cursor, addr_size, &start); - cursor += dw_based_range_read_uleb128(base, rng, cursor, &length); - rng1u64_list_push(arena, &list, rng_1u64(start, start+length)); - } break; - } - } - - return list; -} - -//////////////////////////////// -//~ rjf: Attrib Value Parsing - -internal DW_AttribValueResolveParams -dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root) -{ - DW_AttribValueResolveParams params = {0}; - params.version = root->version; - params.language = root->language; - params.addr_size = root->address_size; - params.containing_unit_info_off = root->info_off; - params.debug_addrs_base = root->addrs_base; - params.debug_rnglists_base = root->rnglist_base; - params.debug_str_offs_base = root->stroffs_base; - params.debug_loclists_base = root->loclist_base; - return params; -} - -internal DW_AttribValue -dw_attrib_value_from_form_value(DW_SectionArray *sections, - DW_AttribValueResolveParams resolve_params, - DW_FormKind form_kind, - DW_AttribClass value_class, - DW_AttribValue form_value) -{ - DW_AttribValue value = {0}; - - //~ rjf: DWARF V5 value parsing - - //- rjf: (DWARF V5 ONLY) the form value is storing an address index (ADDRess indeX), which we - // must resolve to an actual address using the containing comp unit's contribution to the - // .debug_addr section. - if(resolve_params.version >= DW_Version_5 && - value_class == DW_AttribClass_Address && - (form_kind == DW_Form_Addrx || form_kind == DW_Form_Addrx1 || - form_kind == DW_Form_Addrx2 || form_kind == DW_Form_Addrx3 || - form_kind == DW_Form_Addrx4)) - { - U64 addr_index = form_value.v[0]; - U64 addr = dw_v5_addr_from_addrs_section_base_index(sections, DW_Section_Addr, resolve_params.debug_addrs_base, addr_index); - value.v[0] = addr; - } - //- rjf: (DWARF V5 ONLY) lookup into the .debug_loclists section via an index - else if(resolve_params.version >= DW_Version_5 && - value_class == DW_AttribClass_LocList && - form_kind == DW_Form_LocListx) - { - U64 loclist_index = form_value.v[0]; - U64 loclist_offset = dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(sections, DW_Section_LocLists, resolve_params.debug_loclists_base, loclist_index); - value.section = DW_Section_LocLists; - value.v[0] = loclist_offset; - } - //- rjf: (DWARF V5 ONLY) lookup into the .debug_loclists section via an offset - else if(resolve_params.version >= DW_Version_5 && - (value_class == DW_AttribClass_LocList || value_class == DW_AttribClass_LocListPtr) && - form_kind == DW_Form_SecOffset) - { - U64 loclist_offset = form_value.v[0]; - value.section = DW_Section_LocLists; - value.v[0] = loclist_offset; - } - //- rjf: (DWARF V5 ONLY) lookup into the .debug_rnglists section via an index - else if(resolve_params.version >= DW_Version_5 && - (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && - form_kind == DW_Form_RngListx) - { - U64 rnglist_index = form_value.v[0]; - U64 rnglist_offset = dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(sections, DW_Section_RngLists, resolve_params.debug_rnglists_base, rnglist_index); - value.section = DW_Section_RngLists; - value.v[0] = rnglist_offset; - } - //- rjf: (DWARF V5 ONLY) lookup into the .debug_rnglists section via an offset - else if(resolve_params.version >= DW_Version_5 && - (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && - form_kind != DW_Form_RngListx) - { - U64 rnglist_offset = form_value.v[0]; - value.section = DW_Section_RngLists; - value.v[0] = rnglist_offset; - } - //- rjf: (DWARF V5 ONLY) .debug_str_offsets table index, that we need to resolve - // using the containing compilation unit's contribution to the section - else if(resolve_params.version >= DW_Version_5 && - value_class == DW_AttribClass_String && - (form_kind == DW_Form_Strx || - form_kind == DW_Form_Strx1 || - form_kind == DW_Form_Strx2 || - form_kind == DW_Form_Strx3 || - form_kind == DW_Form_Strx4)) - { - DW_SectionKind section = DW_Section_Str; - U64 str_index = form_value.v[0]; - U64 str_offset = dw_v5_offset_from_offs_section_base_index(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base, str_index); - void *base = dw_base_from_sec(sections, section); - Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = dw_based_range_read_string(base, range, str_offset); - value.section = section; - value.v[0] = str_offset; - value.v[1] = value.v[0] + string.size; - } - //- rjf: (DWARF V5 ONLY) reference that we should resolve through ref_addr_desc - else if(resolve_params.version >= DW_Version_5 && - value_class == DW_AttribClass_Reference && - form_kind == DW_Form_RefAddr) - { - // TODO(nick): DWARF 5 @dwarf_v5 - } - //- TODO(rjf): (DWARF V5 ONLY) reference resolution using the .debug_names section - else if(resolve_params.version >= DW_Version_5 && - form_kind == DW_Form_RefSig8) - { - // TODO(nick): DWARF 5: We need to handle .debug_names section in order to resolve this value. @dwarf_v5 - value.v[0] = max_U64; - } - - //~ rjf: All other value parsing (DWARF V4 and below) - - //- rjf: reference to an offset relative to the compilation unit's info base - else if (value_class == DW_AttribClass_Reference && - (form_kind == DW_Form_Ref1 || - form_kind == DW_Form_Ref2 || - form_kind == DW_Form_Ref4 || - form_kind == DW_Form_Ref8 || - form_kind == DW_Form_RefUData)) - { - value.v[0] = resolve_params.containing_unit_info_off + form_value.v[0]; - } - - //- rjf: info-section string -- this is a string that is just pasted straight - // into the .debug_info section - else if(value_class == DW_AttribClass_String && form_kind == DW_Form_String) - { - value = form_value; - value.section = DW_Section_Info; - } - - //- rjf: string-section string -- this is a string that's inside the .debug_str - // section, and we've been provided an offset to it - else if(value_class == DW_AttribClass_String && - (form_kind == DW_Form_Strp || - form_kind == DW_Form_StrpSup)) - { - - DW_SectionKind section = DW_Section_Str; - void *base = dw_base_from_sec(sections, section); - Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = dw_based_range_read_string(base, range, form_value.v[0]); - value.section = section; - value.v[0] = form_value.v[0]; - value.v[1] = value.v[0] + string.size; - } - //- rjf: line-string - else if(value_class == DW_AttribClass_String && form_kind == DW_Form_LineStrp) - { - DW_SectionKind section = DW_Section_LineStr; - void *base = dw_base_from_sec(sections, section); - Rng1U64 range = dw_range_from_sec(sections, section); - String8 string = dw_based_range_read_string(base, range, form_value.v[0]); - value.section = section; - value.v[0] = form_value.v[0]; - value.v[1] = value.v[0] + string.size; - } - //- rjf: .debug_ranges - else if(resolve_params.version < DW_Version_5 && - (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) && - (form_kind == DW_Form_SecOffset)) - { - U64 ranges_offset = form_value.v[0]; - value.section = DW_Section_Ranges; - value.v[0] = ranges_offset; - } - //- rjf: .debug_loc - else if(resolve_params.version < DW_Version_5 && - (value_class == DW_AttribClass_LocListPtr || value_class == DW_AttribClass_LocList) && - (form_kind == DW_Form_SecOffset)) - { - U64 offset = form_value.v[0]; - value.section = DW_Section_Loc; - value.v[0] = offset; - } - //- rjf: invalid attribute class - else if(value_class == 0) - { - Assert(!"attribute class was not resolved"); - } - //- rjf: in all other cases, we can accept the form_value as the correct - // representation for the parsed value, so we can just copy it over. - else - { - value = form_value; - } - - return value; + return sec_offset; } internal String8 -dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value) +dw_interp_exprloc(DW_FormKind form_kind, DW_Form form) { - DW_SectionKind section_kind = value.section; - void *base = dw_base_from_sec(sections, section_kind); - Rng1U64 range = dw_range_from_sec(sections, section_kind); + String8 expr = {0}; + if (form_kind == DW_Form_ExprLoc) { + expr = form.exprloc; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return expr; +} +internal U128 +dw_interp_const_u128(DW_FormKind form_kind, DW_Form form) +{ + AssertAlways(form.data.size <= sizeof(U128)); + U128 result = {0}; + MemoryCopy(&result.u64[0], form.data.str, form.data.size); + return result; +} + +internal U64 +dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_FormKind form_kind, DW_Form form) +{ + U64 result = max_U64; + if (form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || form_kind == DW_Form_Data16) { + if (form.data.size <= sizeof(result)) { + if (!dw_try_u64_from_const_value(type_byte_size, type_encoding, form.data, &result)) { + Assert(!"unable to decode data"); + } + } else { + Assert(!"unable to cast U128 to U64"); + } + } else if (form_kind == DW_Form_UData) { + result = form.udata; + } else if (form_kind == DW_Form_SData) { + result = form.sdata; + } else if (form_kind == DW_Form_ImplicitConst) { + result = form.implicit_const; + } else if (form_kind == DW_Form_Null) { + // skip + } else { + AssertAlways(!"unexpected form"); + } + return result; +} + +internal U64 +dw_interp_const_u64(DW_FormKind form_kind, DW_Form form) +{ + return dw_interp_const64(DW_ATE_Unsigned, sizeof(U64), form_kind, form); +} + +internal U32 +dw_interp_const_u32(DW_FormKind form_kind, DW_Form form) +{ + U64 const64 = dw_interp_const_u64(form_kind, form); + U32 const32 = safe_cast_u32(const64); + return const32; +} + +internal S64 +dw_interp_const_s64(DW_FormKind form_kind, DW_Form form) +{ + U64 const_u64 = dw_interp_const_u64(form_kind, form); + S64 const_s64 = (S64)const_u64; + return const_s64; +} + +internal S32 +dw_interp_const_s32(DW_FormKind form_kind, DW_Form form) +{ + U32 const_u32 = dw_interp_const_u32(form_kind, form); + S32 const_s32 = (S32)const_u32; + return const_s32; +} + +internal U64 +dw_interp_address(U64 address_size, U64 base_addr, DW_ListUnit *addr_lu, DW_FormKind form_kind, DW_Form form) +{ + U64 address = 0; + if (form_kind == DW_Form_Addr) { + if (!dw_try_u64_from_const_value(address_size, DW_ATE_Address, form.addr, &address)) { + AssertAlways(!"unable to decode address"); + } + } else if (form_kind == DW_Form_Addrx || form_kind == DW_Form_Addrx1 || form_kind == DW_Form_Addrx2 || + form_kind == DW_Form_Addrx3 || form_kind == DW_Form_Addrx4) { + address = dw_addr_from_list_unit(addr_lu, form.xval); + } else if (form_kind == DW_Form_SecOffset) { + if (addr_lu->segment_selector_size > 0) { + AssertAlways(!"TODO: support for segmented address space"); + } + if (form.sec_offset + addr_lu->segment_selector_size + addr_lu->address_size <= addr_lu->entries.size) { + MemoryCopy(&address, addr_lu->entries.str + form.sec_offset, addr_lu->address_size); + } else { + Assert(!"out of bounds .debug_addr offset"); + } + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return address; +} + +internal String8 +dw_interp_block(DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form) +{ + NotImplemented; + return str8_zero(); +} + +internal String8 +dw_interp_string(DW_Input *input, + DW_Format unit_format, + DW_ListUnit *str_offsets, + DW_FormKind form_kind, + DW_Form form) +{ String8 string = {0}; - string.str = (U8 *)dw_based_range_ptr(base, range, value.v[0]); - string.size = value.v[1] - value.v[0]; + if (form_kind == DW_Form_String) { + string = form.string; + } else if (form_kind == DW_Form_Strp) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.sec_offset, &string); + Assert(bytes_read > 0); + } else if (form_kind == DW_Form_LineStrp) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_LineStr].data, form.sec_offset, &string); + Assert(bytes_read > 0); + } else if (form_kind == DW_Form_StrpSup) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, form.strp_sup, &string); + Assert(bytes_read > 0); + } else if (form_kind == DW_Form_Strx || form_kind == DW_Form_Strx1 || + form_kind == DW_Form_Strx2 || form_kind == DW_Form_Strx3 || + form_kind == DW_Form_Strx4) { + U64 sec_offset = dw_offset_from_list_unit(str_offsets, form.xval); + if (sec_offset < input->sec[DW_Section_Str].data.size) { + U64 bytes_read = str8_deserial_read_cstr(input->sec[DW_Section_Str].data, sec_offset, &string); + Assert(bytes_read > 0); + } else { + AssertAlways(!"unable to translate index to offset"); + } + } else if (form_kind == DW_Form_GNU_StrpAlt) { + NotImplemented; + } else if (form_kind == DW_Form_GNU_StrIndex) { + NotImplemented; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } return string; } -internal Rng1U64List -dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value) +internal String8 +dw_interp_line_ptr(DW_Input *input, DW_FormKind form_kind, DW_Form form) { - Rng1U64List list = {0}; - switch(ranges_value.section) - { - //- rjf: (DWARF V5 ONLY) .debug_rnglists offset - case DW_Section_RngLists: - { - list = dw_v5_range_list_from_rnglist_offset(arena, sections, ranges_value.section, address_size, addr_section_base, ranges_value.v[0]); - } break; - - //- rjf: (DWARF V4 and earlier) .debug_ranges parsing - case DW_Section_Ranges: - { - list = dw_v4_range_list_from_range_offset(arena, sections, address_size, comp_unit_base_addr, ranges_value.v[0]); - } break; - - //- rjf: fall back to trying to use low/high PCs - default: - { - rng1u64_list_push(arena, &list, rng_1u64(low_pc, high_pc)); - } break; - } - return list; -} - -//////////////////////////////// -//~ rjf: Tag Parsing - -internal DW_AttribListParseResult -dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, - DW_SectionArray *sections, - DW_Version ver, - DW_Ext ext, - DW_Language lang, - U64 address_size, - U64 info_off, - U64 abbrev_off, - B32 relaxed) -{ - //- rjf: set up prereqs - DW_Mode info_mode = sections->v[DW_Section_Info].mode; - DW_Mode abbrev_mode = sections->v[DW_Section_Abbrev].mode; - void *info_base = dw_base_from_sec(sections, DW_Section_Info); - void *abbrev_base = dw_base_from_sec(sections, DW_Section_Abbrev); - Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); - Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); - - //- rjf: set up read offsets - U64 info_read_off = info_off; - U64 abbrev_read_off = abbrev_off; - - //- rjf: parse all attributes - DW_AttribListParseResult result = {0}; - for(B32 good_abbrev = 1; good_abbrev;) - { - U64 attrib_info_offset = info_read_off; - - //- rjf: parse abbrev attrib info - DW_Abbrev abbrev = {0}; - { - U64 bytes_read = dw_based_range_read_abbrev_attrib_info(abbrev_base, abbrev_range, abbrev_read_off, &abbrev); - abbrev_read_off += bytes_read; - good_abbrev = abbrev.id != 0; - } - - //- rjf: extract attrib info from abbrev - DW_AttribKind attrib_kind = (DW_AttribKind)abbrev.id; - DW_FormKind form_kind = (DW_FormKind)abbrev.sub_kind; - DW_AttribClass attrib_class = dw_pick_attrib_value_class(ver, ext, lang, relaxed, attrib_kind, form_kind); - - //- rjf: parse the form value from the file - DW_AttribValue form_value = {0}; - if(good_abbrev) - { - // Special case form that allows user to encode attribute form in .debug_info - if(form_kind == DW_Form_Indirect) - { - U64 override_form_kind = 0; - info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &override_form_kind); - form_kind = (DW_FormKind)override_form_kind; - } - U64 bytes_read = dw_based_range_read_attrib_form_value(info_base, info_range, info_read_off, info_mode, address_size, - form_kind, abbrev.const_value, &form_value); - info_read_off += bytes_read; - } - - //- rjf: push this parsed attrib to the list - if(good_abbrev) - { - DW_AttribNode *node = push_array(arena, DW_AttribNode, 1); - node->attrib.info_off = attrib_info_offset; - node->attrib.abbrev_id = abbrev.id; - node->attrib.attrib_kind = attrib_kind; - node->attrib.form_kind = form_kind; - node->attrib.value_class = attrib_class; - node->attrib.form_value = form_value; - result.attribs.count += 1; - SLLQueuePush(result.attribs.first, result.attribs.last, node); - } - } - - result.max_info_off = info_read_off; - result.max_abbrev_off = abbrev_read_off; - return result; -} - -internal DW_Tag * -dw_tag_from_info_offset(Arena *arena, - DW_SectionArray *sections, - DW_AbbrevTable abbrev_table, - DW_Version ver, - DW_Ext ext, - DW_Language lang, - U64 address_size, - U64 info_offset, - B32 relaxed) -{ - void *info_base = dw_base_from_sec(sections, DW_Section_Info); - Rng1U64 info_range = dw_range_from_sec(sections, DW_Section_Info); - void *abbrev_base = dw_base_from_sec(sections, DW_Section_Abbrev); - Rng1U64 abbrev_range = dw_range_from_sec(sections, DW_Section_Abbrev); - - DW_Tag *tag = push_array(arena, DW_Tag, 1); - - //- rjf: calculate .debug_info read cursor, relative to info range minimum - U64 info_read_off = info_offset - info_range.min; - - //- rjf: read abbrev ID - U64 abbrev_id = 0; - info_read_off += dw_based_range_read_uleb128(info_base, info_range, info_read_off, &abbrev_id); - B32 good_abbrev_id = abbrev_id != 0; - - //- rjf: figure out abbrev offset for this ID - U64 abbrev_offset = 0; - if(good_abbrev_id) - { - abbrev_offset = dw_abbrev_offset_from_abbrev_id(abbrev_table, abbrev_id); - } - - //- rjf: calculate .debug_abbrev read cursor, relative to abbrev range minimum - U64 abbrev_read_off = abbrev_offset - abbrev_range.min; - - //- rjf: parse abbrev tag info - DW_Abbrev abbrev_tag_info = {0}; - B32 good_tag_abbrev = 0; - if(good_abbrev_id) - { - abbrev_read_off += dw_based_range_read_abbrev_tag(abbrev_base, abbrev_range, abbrev_read_off, &abbrev_tag_info); - good_tag_abbrev = 1;//abbrev_tag_info.id != 0; - } - - //- rjf: parse all attributes for this tag - U64 attribs_info_off = 0; - U64 attribs_abbrev_off = 0; - DW_AttribList attribs = {0}; - if(good_tag_abbrev) - { - DW_AttribListParseResult attribs_parse = dw_parse_attrib_list_from_info_abbrev_offsets(arena, sections, ver, ext, lang, address_size, info_read_off, abbrev_read_off, relaxed); - attribs_info_off = info_read_off; - attribs_abbrev_off = abbrev_read_off; - info_read_off = attribs_parse.max_info_off; - abbrev_read_off = attribs_parse.max_abbrev_off; - attribs = attribs_parse.attribs; - } - - //- rjf: fill tag - { - tag->abbrev_id = abbrev_id; - tag->info_range = rng_1u64(info_offset, info_range.min + info_read_off); - tag->abbrev_range = rng_1u64(abbrev_offset, abbrev_range.min + abbrev_read_off); - tag->has_children = !!(abbrev_tag_info.flags & DW_AbbrevFlag_HasChildren); - tag->kind = (DW_TagKind)abbrev_tag_info.sub_kind; - tag->attribs_info_off = attribs_info_off; - tag->attribs_abbrev_off = attribs_abbrev_off; - tag->attribs = attribs; - } - - return tag; -} - -//////////////////////////////// - -internal U64 -dw_v5_header_offset_from_table_offset(DW_SectionArray *sections, DW_SectionKind section, U64 table_off) -{ - // NOTE(rjf): From the DWARF V5 spec (February 13, 2017), page 401: - // - // " - // Each skeleton compilation unit also has a DW_AT_addr_base attribute, - // which provides the relocated offset to that compilation unit’s - // contribution in the executable’s .debug_addr section. Unlike the - // DW_AT_stmt_list attribute, the offset refers to the first address table - // slot, not to the section header. In this example, we see that the first - // address (slot 0) from demo1.o begins at offset 48. Because the - // .debug_addr section contains an 8-byte header, the object file’s - // contribution to the section actually begins at offset 40 (for a 64-bit - // DWARF object, the header would be 16 bytes long, and the value for the - // DW_AT_addr_base attribute would then be 56). All attributes in demo1.dwo - // that use DW_FORM_addrx, DW_FORM_addrx1, DW_FORM_addrx2, DW_FORM_addrx3 - // or DW_FORM_addrx4 would then refer to address table slots relative to - // that offset. Likewise, the .debug_addr contribution from demo2.dwo begins - // at offset 72, and its first address slot is at offset 80. Because these - // contributions have been processed by the linker, they contain relocated - // values for the addresses in the program that are referred to by the - // debug information. - // " - // - // This seems to at least partially explain why the addr_base is showing up - // 8 bytes later than we are expecting it to. We can't actually just store - // the base that we read from the DW_Attrib_AddrBase attrib, because - // it's showing up *after* the header, so we need to bump it back. - - // NOTE(rjf): From the DWARF V5 spec (February 13, 2017), page 66: - // - // " - // A DW_AT_rnglists_base attribute, whose value is of class rnglistsptr. This - // attribute points to the beginning of the offsets table (immediately - // following the header) of the compilation unit's contribution to the - // .debug_rnglists section. References to range lists (using DW_FORM_rnglistx) - // within the compilation unit are interpreted relative to this base. - // " - // - // Similarly, we need to figure out where to go to parse the header. - - U64 max_header_size = 0; - U64 min_header_size = 0; - switch(section) - { - default: - case DW_Section_Addr: - { - max_header_size = 16; - min_header_size = 8; - } break; - case DW_Section_StrOffsets: - { - max_header_size = 16; - min_header_size = 8; - } break; - case DW_Section_RngLists: - { - max_header_size = 20; - min_header_size = 12; - } break; - case DW_Section_LocLists: - { - // TODO(rjf) - NotImplemented; - } break; - } - - U64 past_header = table_off; - void *addr_base = dw_base_from_sec(sections, section); - Rng1U64 addr_rng = dw_range_from_sec(sections, section); - - //- rjf: figure out which sized header we have - U64 header_size = 0; - { - // rjf: try max header, and if it works, the header is the max size, otherwise we will - // need to rely on the min header size - U32 first32 = 0; - dw_based_range_read_struct(addr_base, addr_rng, past_header-max_header_size, &first32); - if(first32 == max_U32) - { - header_size = max_header_size; - } - else - { - header_size = min_header_size; - } - } - - return table_off - header_size; -} - -internal Rng1U64List -dw_comp_unit_ranges_from_info(Arena *arena, DW_Section info) -{ - Rng1U64List result = {0}; - void *base = info.data.str; - Rng1U64 range = rng_1u64(0, info.data.size); - for(U64 cursor = 0; cursor < info.data.size; ) - { - // read unit length - U64 unit_length = 0; - U64 bytes_read = dw_based_range_read_length(base, range, cursor, &unit_length); - - // was read ok? - if(bytes_read == 0) - { - break; - } - - // push unit range - rng1u64_list_push(arena, &result, rng_1u64(cursor, cursor+unit_length+bytes_read)); - - // advance - cursor += unit_length+bytes_read; + String8 result = {0}; + if (form_kind == DW_Form_SecOffset) { + result = str8_skip(input->sec[DW_Section_Line].data, form.sec_offset); + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); } return result; } -internal DW_Ext -dw_ext_from_params(String8 producer, Arch arch, ImageType image_type) +internal DW_LineFile * +dw_interp_file(DW_LineVMHeader *line_vm, DW_FormKind form_kind, DW_Form form) { - DW_Ext ext = DW_Ext_Null; - switch (image_type) { - case Image_Null: break; - case Image_CoffPe: { - if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_GNU | DW_Ext_LLVM; - } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_GNU; - } - } break; - case Image_Elf32: - case Image_Elf64: { - if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_GNU | DW_Ext_LLVM; - } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_GNU; - } - } break; - case Image_Macho: { - if (str8_match_lit("clang", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_LLVM | DW_Ext_APPLE; - } else if (str8_match_lit("GNU", producer, StringMatchFlag_RightSideSloppy|StringMatchFlag_CaseInsensitive)) { - ext = DW_Ext_GNU | DW_Ext_APPLE; - } - } break; + DW_LineFile *result = 0; + U64 file_idx = dw_interp_const_u64(form_kind, form); + if (file_idx < line_vm->file_table.count) { + result = &line_vm->file_table.v[file_idx]; + } else { + Assert(!"out of bounds file index"); } - return ext; + return result; } -internal DW_CompRoot -dw_comp_root_from_range(Arena *arena, DW_SectionArray *sections, Rng1U64 range, B32 relaxed) +internal DW_Reference +dw_interp_ref(DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form) { - Temp scratch = scratch_begin(&arena, 1); - - void *info_base = dw_base_from_sec(sections, DW_Section_Info); - B32 is_info_dwo = sections->v[DW_Section_Info].is_dwo; - - //- rjf: up-front known parsing offsets (yep, that's right, it's only 1!) - U64 size_off = 0; - - //- rjf: parse size of this compilation unit's data - U64 size = 0; - U64 version_off = size_off; - { - U64 bytes_read = dw_based_range_read_length(info_base, range, size_off, &size); - version_off += bytes_read; + DW_Reference ref = {0}; + if (form_kind == DW_Form_Ref1 || form_kind == DW_Form_Ref2 || + form_kind == DW_Form_Ref4 || form_kind == DW_Form_Ref8 || + form_kind == DW_Form_RefUData) { + ref.cu = cu; + ref.info_off = form.ref; + } else if (form_kind == DW_Form_RefAddr) { + NotImplemented; + } else if (form_kind == DW_Form_RefSig8) { + NotImplemented; + } else if (form_kind == DW_Form_RefSup4 || form_kind == DW_Form_RefSup8) { + NotImplemented; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); } - - //- rjf: parse version - B32 got_version = 0; - DW_Version version = 0; - U64 unit_off = version_off; - if(dw_based_range_read_struct(info_base, range, version_off, &version)) - { - unit_off += sizeof(version); - got_version = 1; - } - - //- rjf: parse unit kind, abbrev_base, address size - B32 got_unit_kind = 0; - U64 next_off = unit_off; - DW_CompUnitKind unit_kind = DW_CompUnitKind_Reserved; - U64 abbrev_base = max_U64; - U64 address_size = 0; - U64 spec_dwo_id = 0; - if(got_version) - { - switch(version) - { - default: break; - case DW_Version_2: { - abbrev_base = 0; - next_off += dw_based_range_read(info_base, range, next_off, 4, &abbrev_base); - next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); - got_unit_kind = 1; - } break; - case DW_Version_3: - case DW_Version_4: - { - next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); - next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); - got_unit_kind = 1; - } break; - case DW_Version_5: - { - next_off += dw_based_range_read_struct(info_base, range, next_off, &unit_kind); - next_off += dw_based_range_read(info_base, range, next_off, 1, &address_size); - next_off += dw_based_range_read_length(info_base, range, next_off, &abbrev_base); - got_unit_kind = 1; - - //- rjf: parse DWO ID if appropriate - if(unit_kind == DW_CompUnitKind_Skeleton || is_info_dwo) - { - next_off += dw_based_range_read(info_base, range, next_off, 8, &spec_dwo_id); - } - } break; - } - } - - //- rjf: build abbrev table - DW_AbbrevTable abbrev_table = {0}; - if(got_unit_kind) - { - abbrev_table = dw_make_abbrev_table(arena, sections, abbrev_base); - } - - //- rjf: parse compilation unit's tag - B32 got_comp_unit_tag = 0; - DW_Tag *comp_unit_tag = 0; - if(got_unit_kind) - { - U64 comp_root_tag_off = range.min + next_off; - comp_unit_tag = dw_tag_from_info_offset(scratch.arena, sections, abbrev_table, version, DW_Ext_Null, DW_Language_Null, address_size, comp_root_tag_off, relaxed); - got_comp_unit_tag = 1; - } - - //- rjf: get all of the attribute values we need to start resolving attribute values - DW_AttribValueResolveParams resolve_params = { .version = version }; - if(got_comp_unit_tag) - { - for(DW_AttribNode *attrib_n = comp_unit_tag->attribs.first; attrib_n; attrib_n = attrib_n->next) - { - DW_Attrib *attrib = &attrib_n->attrib; - - // NOTE(rjf): We'll have to rely on just the form value at this point, - // since we can't use the unit yet (since we're currently in the process - // of building it). This should always be enough, otherwise there would - // be a cyclic dependency in the requirements of each part of the - // compilation unit's parse. DWARF is pretty crazy, but not *that* crazy, - // so this should be good. - switch(attrib->attrib_kind) - { - default: break; - case DW_Attrib_AddrBase: resolve_params.debug_addrs_base = attrib->form_value.v[0]; break; - case DW_Attrib_StrOffsetsBase: resolve_params.debug_str_offs_base = attrib->form_value.v[0]; break; - case DW_Attrib_RngListsBase: resolve_params.debug_rnglists_base = attrib->form_value.v[0]; break; - case DW_Attrib_LocListsBase: resolve_params.debug_loclists_base = attrib->form_value.v[0]; break; - } - } - } - - //- rjf: correct table offsets to header offsets (since DWARF V5 insists on being as useless as possible) - if(got_comp_unit_tag && version >= DW_Version_5) - { - resolve_params.debug_addrs_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_Addr, resolve_params.debug_addrs_base); - resolve_params.debug_str_offs_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_StrOffsets, resolve_params.debug_str_offs_base); - resolve_params.debug_loclists_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_LocLists, resolve_params.debug_loclists_base); - resolve_params.debug_rnglists_base = dw_v5_header_offset_from_table_offset(sections, DW_Section_RngLists, resolve_params.debug_rnglists_base); - } - - //- rjf: parse the rest of the compilation unit tag's attributes that we'd - // like to cache - String8 name = {0}; - String8 producer = {0}; - String8 compile_dir = {0}; - String8 external_dwo_name = {0}; - String8 external_gnu_dwo_name = {0}; - U64 gnu_dwo_id = 0; - DW_Language language = 0; - U64 name_case = 0; - B32 use_utf8 = 0; - U64 low_pc = 0; - U64 high_pc = 0; - B32 high_pc_is_relative = 0; - DW_AttribValue ranges_attrib_value = {DW_Section_Null}; - U64 line_base = 0; - if(got_comp_unit_tag) - { - for(DW_AttribNode *attrib_n = comp_unit_tag->attribs.first; attrib_n; attrib_n = attrib_n->next) - { - DW_Attrib *attrib = &attrib_n->attrib; - - //- rjf: form value => value - DW_AttribValue value = {0}; - B32 good_value = 0; - { - if(dw_are_attrib_class_and_form_kind_compatible(version, attrib->value_class, attrib->form_kind)) - { - value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); - good_value = 1; - } - } - - //- rjf: map value to extracted info - if(good_value) - { - switch(attrib->attrib_kind) - { - case DW_Attrib_Name: name = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_Producer: producer = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_CompDir: compile_dir = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_DwoName: external_dwo_name = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_GNU_DwoName: external_gnu_dwo_name = dw_string_from_attrib_value(sections, value); break; - case DW_Attrib_GNU_DwoId: gnu_dwo_id = value.v[0]; break; - case DW_Attrib_Language: language = safe_cast_u32(value.v[0]); break; - case DW_Attrib_IdentifierCase: name_case = value.v[0]; break; - case DW_Attrib_UseUtf8: use_utf8 = (B32)value.v[0]; break; - case DW_Attrib_LowPc: low_pc = value.v[0]; break; - case DW_Attrib_HighPc: high_pc = value.v[0]; high_pc_is_relative = attrib->value_class != DW_AttribClass_Address; break; - case DW_Attrib_Ranges: ranges_attrib_value = value; break; - case DW_Attrib_StmtList: line_base = value.v[0]; break; - default: break; - } - } - } - } - - //- rjf: build+fill unit - DW_CompRoot unit = {0}; - - //- rjf: fill header data - unit.size = size; - unit.kind = unit_kind; - unit.version = version; - unit.address_size = address_size; - unit.abbrev_off = abbrev_base; - unit.info_off = range.min; - unit.tags_info_range = rng_1u64(range.min+next_off, range.max); - unit.abbrev_table = abbrev_table; - - //- rjf: fill out offsets we need for attrib value resolution - unit.rnglist_base = resolve_params.debug_rnglists_base; - unit.loclist_base = resolve_params.debug_loclists_base; - unit.addrs_base = resolve_params.debug_addrs_base; - unit.stroffs_base = resolve_params.debug_str_offs_base; - - //- rjf: fill out general info - unit.name = name; - unit.producer = producer; - unit.compile_dir = compile_dir; - unit.external_dwo_name = external_dwo_name.size ? external_dwo_name : external_gnu_dwo_name; - if(external_dwo_name.size) - { - unit.dwo_id = spec_dwo_id; - } - else if(external_gnu_dwo_name.size) - { - unit.dwo_id = gnu_dwo_id; - } - unit.language = language; - unit.name_case = name_case; - unit.use_utf8 = use_utf8; - unit.line_off = line_base; - unit.low_pc = low_pc; - unit.high_pc = high_pc; - unit.ranges_attrib_value = ranges_attrib_value; - unit.base_addr = unit.low_pc; - - //- rjf: fill fixup of low/high PC situation - if(high_pc_is_relative) - { - unit.high_pc += unit.low_pc; - } - - scratch_end(scratch); - return unit; -} - -internal DW_ExtDebugRef -dw_ext_debug_ref_from_comp_root(DW_CompRoot *root) -{ - DW_ExtDebugRef ref = {0}; - ref.dwo_path = root->external_dwo_name; - ref.dwo_id = root->dwo_id; return ref; } -//- rjf: line info +internal DW_LocList +dw_interp_loclist(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form) +{ + DW_LocList loclist = {0}; + + if (cu->version < DW_Version_5) { + if (form_kind == DW_Form_SecOffset) { + U64 sec_offset = max_U64; + if (form_kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form_kind == DW_Form_Data8 || form_kind == DW_Form_Data4 || + form_kind == DW_Form_Data2 || form_kind == DW_Form_Data1) { + if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { + Assert(!"unable to extract section offset"); + } + } else if (form_kind == DW_Form_Null) { + Assert(!"unexpected form"); + } + + String8 sec = str8_skip(input->sec[DW_Section_Loc].data, sec_offset); + U64 base_addr = cu->low_pc; + U64 base_sel = DW_SentinelFromSize(cu->address_size); + for (U64 cursor = 0; cursor < sec.size; ) { + U64 range_min = 0; + U64 range_min_off = cursor; + U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); + if (range_min_size == 0) { + break; + } + U64 range_max = 0; + U64 range_max_off = cursor + cu->address_size; + U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); + if (range_max_size == 0) { + break; + } + cursor += cu->address_size * 2; + + // series terminator + if (range_min == 0 && range_max == 0) { + break; + } + // set new base address + else if (range_min == base_sel) { + base_addr = range_max; + } + // location + else { + U16 expr_size = 0; + U64 expr_size_size = str8_deserial_read_struct(sec, cursor, &expr_size); + if (expr_size_size == 0) { + Assert(!"unable to read expression size"); + break; + } + cursor += expr_size_size; + + Assert(cursor + expr_size <= sec.size); + Rng1U64 expr_range = rng_1u64(cursor, ClampTop(cursor + expr_size, sec.size)); + + DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); + loc_n->v.range = rng_1u64(base_addr + range_min, base_addr + range_max); + loc_n->v.expr = str8_substr(sec, expr_range); + + SLLQueuePush(loclist.first, loclist.last, loc_n); + ++loclist.count; + + // advance past expression + cursor += expr_size; + } + } + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + } else { + DW_Version version = DW_Version_Null; + String8 raw_lle = {0}; + if (form_kind == DW_Form_SecOffset) { + // offset is from beginning of the section + U64 sec_offset = form.sec_offset; + raw_lle = str8_skip(input->sec[DW_Section_LocLists].data, sec_offset); + } else if (form_kind == DW_Form_LocListx) { + // offset is from beginning of the entries + U64 entries_off = dw_offset_from_list_unit(cu->loclists_lu, form.xval); + raw_lle = str8_skip(cu->loclists_lu->entries, entries_off); + version = cu->loclists_lu->version; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + + for (U64 cursor = 0, keep_parsing = 1, base_addr = cu->low_pc; + cursor < raw_lle.size && keep_parsing; ) { + DW_LLE kind = DW_LLE_EndOfList; + cursor += str8_deserial_read_struct(raw_lle, cursor, &kind); + + Rng1U64 range = {0}; + switch (kind) { + default: + Assert(!"unknown kind"); + case DW_LLE_EndOfList: { + keep_parsing = 0; + } break; + case DW_LLE_BaseAddressx: { + if (!cu->addr_lu) { + keep_parsing = 0; + break; + } + + U64 addrx = 0; + U64 addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &addrx); + if (addrx_size == 0) { + keep_parsing = 0; + break; + } + + U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); + if (base_addr_new == max_U64) { + InvalidPath; + break; + } + + base_addr = base_addr_new; + cursor += addrx_size; + } break; + case DW_LLE_StartxEndx: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + U64 end_addrx = 0; + U64 end_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor + start_addrx_size, &end_addrx); + if (end_addrx_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_addrx_size; + cursor += end_addrx_size; + + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + U64 end = dw_addr_from_list_unit(cu->addr_lu, end_addrx); + Assert(start != max_U64); + Assert(end != max_U64); + + range = rng_1u64(start, end); + } break; + case DW_LLE_StartxLength: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_lle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + + // parse pre-standard & standard length + U64 length_off = cursor + start_addrx_size; + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_lle, length_off, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + + cursor += start_addrx_size; + cursor += length_size; + + if (cu->addr_lu) { + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + Assert(start < max_U64); + + range = rng_1u64(start, start + length); + } else { + Assert(!".debug_addr section is missing -- unable to interpret address index"); + } + } break; + case DW_LLE_OffsetPair: { + U64 start = 0; + U64 start_size = str8_deserial_read_uleb128(raw_lle, cursor, &start); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 end = 0; + U64 end_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &end); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(base_addr + start, base_addr + end); + } break; + case DW_LLE_DefaultLocation: { + // no range + int x = 0; + } break; + case DW_LLE_BaseAddress: { + U64 base_addr_size = str8_deserial_read(raw_lle, cursor, &base_addr, cu->address_size, cu->address_size); + if (base_addr_size == 0) { + keep_parsing = 0; + break; + } + cursor += base_addr_size; + } break; + case DW_LLE_StartEnd: { + U64 start = 0; + U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + + U64 end = 0; + U64 end_size = str8_deserial_read(raw_lle, cursor + start_size, &end, cu->address_size, cu->address_size); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(start, end); + } break; + case DW_LLE_StartLength: { + U64 start = 0; + U64 start_size = str8_deserial_read(raw_lle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_lle, cursor + start_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += length_size; + + range = rng_1u64(start, start + length); + } break; + } + + B32 has_expr = keep_parsing && kind != DW_LLE_BaseAddressx && kind != DW_LLE_BaseAddress; + if (has_expr) { + U64 expr_size = 0; + U64 expr_size_size = str8_deserial_read_uleb128(raw_lle, cursor, &expr_size); + if (expr_size_size == 0) { + keep_parsing = 0; + break; + } + + String8 expr = {0}; + U64 expr_read_size = str8_deserial_read_block(raw_lle, cursor + expr_size_size, expr_size, &expr); + if (expr_read_size != expr_size) { + keep_parsing = 0; + break; + } + + cursor += expr_size_size; + cursor += expr_size; + + DW_LocNode *loc_n = push_array(arena, DW_LocNode, 1); + loc_n->v.range = range; + loc_n->v.expr = expr; + + SLLQueuePush(loclist.first, loclist.last, loc_n); + ++loclist.count; + } + } + } + + return loclist; +} + +internal B32 +dw_interp_flag(DW_FormKind form_kind, DW_Form form) +{ + B32 flag = 0; + if (form_kind == DW_Form_Flag || form_kind == DW_Form_FlagPresent) { + flag = form.flag; + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + return flag; +} + +internal Rng1U64List +dw_interp_rnglist(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form) +{ + Rng1U64List rnglist = {0}; + + if (cu->version < DW_Version_5) { + // decode section offset + U64 sec_offset = max_U64; + if (form_kind == DW_Form_SecOffset) { + sec_offset = form.sec_offset; + } else if (form_kind == DW_Form_Data8 || form_kind == DW_Form_Data4 || + form_kind == DW_Form_Data2 || form_kind == DW_Form_Data1) { + if (!dw_try_u64_from_const_value(form.data.size, DW_ATE_Unsigned, form.data, &sec_offset)) { + Assert(!"unable to extract section offset"); + } + } else if (form_kind != DW_Form_Null) { + Assert(!"unexpected form"); + } + + String8 sec = str8_skip(input->sec[DW_Section_Ranges].data, sec_offset); + U64 base_addr = cu->low_pc; + U64 base_sel = DW_SentinelFromSize(cu->address_size); + for (U64 cursor = 0; cursor < sec.size; ) { + U64 range_min = 0; + U64 range_min_off = cursor; + U64 range_min_size = str8_deserial_read(sec, range_min_off, &range_min, cu->address_size, cu->address_size); + if (range_min_size == 0) { + break; + } + U64 range_max = 0; + U64 range_max_off = cursor + cu->address_size; + U64 range_max_size = str8_deserial_read(sec, range_max_off, &range_max, cu->address_size, cu->address_size); + if (range_max_size == 0) { + break; + } + cursor += cu->address_size * 2; + + // series terminator + if (range_min == 0 && range_max == 0) { + break; + } + // set new base address + else if (range_min == base_sel) { + base_addr = range_max; + } + // range + else { + Rng1U64 range = rng_1u64(base_addr + range_min, base_addr + range_max); + rng1u64_list_push(arena, &rnglist, range); + } + } + } else { + String8 raw_rle = {0}; + if (form_kind == DW_Form_SecOffset) { + // offset is from beginning of the section + U64 sec_offset = form.sec_offset; + raw_rle = str8_skip(input->sec[DW_Section_RngLists].data, sec_offset); + } else if (form_kind == DW_Form_RngListx) { + // offset is from beginning of the entries + U64 sec_offset = dw_offset_from_list_unit(cu->rnglists_lu, form.xval); + raw_rle = str8_skip(cu->rnglists_lu->entries, sec_offset); + } else if (form_kind != DW_Form_Null) { + AssertAlways(!"unexpected form"); + } + + U64 rle_invalid_value = DW_SentinelFromSize(cu->address_size); + U64 base_addr = cu->low_pc; + for (U64 cursor = 0, keep_parsing = 1; cursor < raw_rle.size && keep_parsing; ) { + DW_RLE kind = DW_RLE_EndOfList; + cursor += str8_deserial_read_struct(raw_rle, cursor, &kind); + + Rng1U64 range = rng_1u64(rle_invalid_value, rle_invalid_value); + switch (kind) { + default: + case DW_RLE_EndOfList: { + keep_parsing = 0; + } break; + case DW_RLE_BaseAddressx: { + U64 addrx = 0; + U64 addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &addrx); + if (addrx_size == 0) { + keep_parsing = 0; + break; + } + if (cu->addr_lu == 0) { + keep_parsing = 0; + break; + } + U64 base_addr_new = dw_addr_from_list_unit(cu->addr_lu, addrx); + if (base_addr_new < max_U64) { + base_addr = base_addr_new; + cursor += addrx_size; + } else { + keep_parsing = 0; + Assert(!"invalid addrx"); + } + } break; + case DW_RLE_StartxLength: { + U64 start_addrx = 0; + U64 start_addrx_size = str8_deserial_read_uleb128(raw_rle, cursor, &start_addrx); + if (start_addrx_size == 0) { + keep_parsing = 0; + break; + } + U64 length = 0; + U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_addrx_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_addrx_size; + cursor += length_size; + + if (cu->addr_lu) { + U64 start = dw_addr_from_list_unit(cu->addr_lu, start_addrx); + AssertAlways(start < max_U64); + range = rng_1u64(start, start + length); + } + } break; + case DW_RLE_OffsetPair: { + U64 offset_start, offset_end = 0; + U64 offset_start_size = str8_deserial_read_uleb128(raw_rle, cursor, &offset_start); + if (offset_start_size == 0) { + keep_parsing = 0; + break; + } + U64 offset_end_size = str8_deserial_read_uleb128(raw_rle, cursor + offset_start_size, &offset_end); + if (offset_end_size == 0) { + keep_parsing = 0; + break; + } + cursor += offset_start_size; + cursor += offset_end_size; + + range = rng_1u64(base_addr + offset_start, base_addr + offset_end); + } break; + case DW_RLE_BaseAddress: { + U64 base_addr_size = str8_deserial_read(raw_rle, cursor, &base_addr, cu->address_size, cu->address_size); + if (base_addr_size == 0) { + keep_parsing = 0; + break; + } + cursor += base_addr_size; + } break; + case DW_RLE_StartEnd: { + U64 start = 0, end = 0; + + U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 end_size = str8_deserial_read(raw_rle, cursor + start_size, &end, cu->address_size, cu->address_size); + if (end_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += end_size; + + range = rng_1u64(start, end); + } break; + case DW_RLE_StartLength: { + U64 start = 0, length = 0; + + U64 start_size = str8_deserial_read(raw_rle, cursor, &start, cu->address_size, cu->address_size); + if (start_size == 0) { + keep_parsing = 0; + break; + } + U64 length_size = str8_deserial_read_uleb128(raw_rle, cursor + start_size, &length); + if (length_size == 0) { + keep_parsing = 0; + break; + } + cursor += start_size; + cursor += length_size; + + range = rng_1u64(start, start + length); + } break; + } + + if (range.min != rle_invalid_value) { + rng1u64_list_push(arena, &rnglist, range); + } + } + } + + return rnglist; +} + +internal String8 +dw_interp_secptr(DW_Input *input, DW_SectionKind section, DW_FormKind form_kind, DW_Form form) +{ + String8 secptr = {0}; + if (form_kind == DW_Form_SecOffset) { + String8 sect = input->sec[section].data; + Rng1U64 range = rng_1u64(form.sec_offset, sect.size); + secptr = str8_substr(sect, range); + } else if (form_kind != DW_Form_Null) { + Assert(!"unexpected form"); + } + return secptr; +} + +internal String8 +dw_interp_addrptr(DW_Input *input, DW_FormKind form_kind, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_Addr, form_kind, form); +} + +internal String8 +dw_interp_str_offsets_ptr(DW_Input *input, DW_FormKind form_kind, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_StrOffsets, form_kind, form); +} + +internal String8 +dw_interp_rnglists_ptr(DW_Input *input, DW_FormKind form_kind, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_RngLists, form_kind, form); +} + +internal String8 +dw_interp_loclists_ptr(DW_Input *input, DW_FormKind form_kind, DW_Form form) +{ + return dw_interp_secptr(input, DW_Section_LocLists, form_kind, form); +} + +internal DW_AttribClass +dw_value_class_from_attrib(DW_CompUnit *cu, DW_Attrib *attrib) +{ + return dw_pick_attrib_value_class(cu->version, cu->ext, cu->relaxed, attrib->attrib_kind, attrib->form_kind); +} + +internal String8 +dw_exprloc_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_ExprLoc || value_class == DW_AttribClass_Block); + return dw_interp_exprloc(attrib->form_kind, attrib->form); +} + +internal U128 +dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u128(attrib->form_kind, attrib->form); +} + +internal U64 +dw_const_u64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u64(attrib->form_kind, attrib->form); +} + +internal U32 +dw_const_u32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_u32(attrib->form_kind, attrib->form); +} + +internal S64 +dw_const_s64_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_s64(attrib->form_kind, attrib->form); +} + +internal S32 +dw_const_s32_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_const_s32(attrib->form_kind, attrib->form); +} + +internal B32 +dw_flag_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Flag); + return dw_interp_flag(attrib->form_kind, attrib->form); +} + +internal U64 +dw_address_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || + value_class == DW_AttribClass_Address || + value_class == DW_AttribClass_AddrPtr); + DW_FormKind form_kind = attrib->form_kind; + DW_Form form = attrib->form; + if (value_class == DW_AttribClass_AddrPtr) { + + if (attrib->form_kind == DW_Form_SecOffset) { + + + } else { + AssertAlways(!"unexpected form"); + } + + + form_kind = DW_Form_Addr; + form.addr = dw_interp_addrptr(input, attrib->form_kind, attrib->form); + } + return dw_interp_address(cu->address_size, cu->low_pc, cu->addr_lu, form_kind, form); +} + +internal String8 +dw_block_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Block); + return dw_interp_block(input, cu, attrib->form_kind, attrib->form); +} + +internal String8 +dw_string_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_String || value_class == DW_AttribClass_StrOffsetsPtr); + return dw_interp_string(input, cu->format, cu->str_offsets_lu, attrib->form_kind, attrib->form); +} + +internal String8 +dw_line_ptr_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_LinePtr); + return dw_interp_line_ptr(input, attrib->form_kind, attrib->form); +} + +internal DW_LineFile * +dw_file_from_attrib_ptr(DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Const); + return dw_interp_file(line_vm, attrib->form_kind, attrib->form); +} + +internal DW_Reference +dw_ref_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || value_class == DW_AttribClass_Reference); + return dw_interp_ref(input, cu, attrib->form_kind, attrib->form); +} + +internal DW_LocList +dw_loclist_from_attrib_ptr(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + AssertAlways(value_class == DW_AttribClass_Null || + value_class == DW_AttribClass_LocList || + value_class == DW_AttribClass_LocListPtr); + return dw_interp_loclist(arena, input, cu, attrib->form_kind, attrib->form); +} + +internal Rng1U64List +dw_rnglist_from_attrib_ptr(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib) +{ + Rng1U64List rnglist = {0}; + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + if (value_class == DW_AttribClass_RngListPtr || value_class == DW_AttribClass_RngList) { + rnglist = dw_interp_rnglist(arena, input, cu, attrib->form_kind, attrib->form); + } else if (value_class != DW_AttribClass_Null) { + Assert(!"unexpected value class"); + } + return rnglist; +} + +internal DW_Attrib * +dw_attrib_from_tag_(DW_Tag tag, DW_AttribKind kind) +{ + local_persist read_only DW_Attrib null_attrib; + DW_Attrib *attrib = &null_attrib; + for (DW_AttribNode *attrib_n = tag.attribs.first; attrib_n != 0; attrib_n = attrib_n->next) { + if (attrib_n->v.attrib_kind == kind) { + attrib = &attrib_n->v; + break; + } + } + return attrib; +} + +internal DW_Attrib * +dw_attrib_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + DW_Attrib *attrib = dw_attrib_from_tag_(tag, kind); + + if (attrib->attrib_kind == DW_Attrib_Null) { + if (cu && cu->tag_ht) { + DW_Attrib *ao_attrib = dw_attrib_from_tag_(tag, DW_Attrib_AbstractOrigin); + if (ao_attrib->attrib_kind == DW_Attrib_AbstractOrigin) { + DW_Reference ref = dw_interp_ref(input, cu, ao_attrib->form_kind, ao_attrib->form); + DW_TagNode *ref_tag = dw_tag_node_from_info_off(ref.cu, ref.info_off); + attrib = dw_attrib_from_tag_(ref_tag->tag, kind); + } + } + } + + return attrib; +} + +internal B32 +dw_tag_has_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + B32 has_attrib = attrib->attrib_kind != DW_Attrib_Null; + return has_attrib; +} + +internal String8 +dw_exprloc_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_exprloc_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_block_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_block_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U128 +dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u128_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U64 +dw_const_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u64_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U32 +dw_const_u32_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_const_u32_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal U64 +dw_address_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_address_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_string_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_string_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal String8 +dw_line_ptr_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_line_ptr_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_Reference +dw_ref_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_ref_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_LocList +dw_loclist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_loclist_from_attrib_ptr(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal Rng1U64List +dw_rnglist_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_rnglist_from_attrib_ptr(arena, input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal B32 +dw_flag_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + return dw_flag_from_attrib_ptr(input, cu, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal DW_LineFile * +dw_file_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind) +{ + return dw_file_from_attrib_ptr(cu, line_vm, dw_attrib_from_tag(input, cu, tag, kind)); +} + +internal B32 +dw_try_byte_size_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, U64 *byte_size_out) +{ + B32 has_byte_size = dw_tag_has_attrib(input, cu, tag, DW_Attrib_ByteSize); + B32 has_bit_size = dw_tag_has_attrib(input, cu, tag, DW_Attrib_BitSize ); + + if (has_byte_size && has_bit_size) { + Assert(!"ill formated byte size"); + } + + if (has_byte_size) { + *byte_size_out = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_ByteSize); + return 1; + } else if (has_bit_size) { + U64 bit_size = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_BitSize); + *byte_size_out = bit_size / 8; + return 1; + } + + return 0; +} + +internal U64 +dw_byte_size_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag) +{ + U64 byte_size = max_U64; + dw_try_byte_size_from_tag(input, cu, tag, &byte_size); + return byte_size; +} + +internal U32 +dw_byte_size_32_from_tag(DW_Input *input, DW_CompUnit *cu, DW_Tag tag) +{ + U32 byte_size32 = 0; + U64 byte_size64; + if (dw_try_byte_size_from_tag(input, cu, tag, &byte_size64)) { + byte_size32 = safe_cast_u32(byte_size64); + } + return byte_size32; +} + +internal U64 +dw_u64_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + U64 result = 0; + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib); + if (attrib_class == DW_AttribClass_Const || attrib_class == DW_AttribClass_Block) { + if (dw_tag_has_attrib(input, cu, tag, DW_Attrib_Type)) { + Temp scratch = scratch_begin(0,0); + DW_Reference type_ref = dw_ref_from_attrib(input, cu, tag, DW_Attrib_Type); + DW_Tag type_tag = {0}; + dw_read_tag_cu(scratch.arena, input, type_ref.cu, type_ref.info_off, &type_tag); + U64 type_byte_size = dw_byte_size_from_tag(input, cu, type_tag); + DW_ATE type_encoding = dw_const_u64_from_attrib(input, type_ref.cu, type_tag, DW_Attrib_Encoding); + if (type_encoding == DW_ATE_Unsigned || type_encoding == DW_ATE_UnsignedChar) { + result = dw_interp_const64(type_byte_size, type_encoding, attrib->form_kind, attrib->form); + } + scratch_end(scratch); + } else { + result = dw_interp_const_u64(attrib->form_kind, attrib->form); + } + } else if (attrib_class == DW_AttribClass_Reference) { + NotImplemented; + } else if (attrib_class != DW_AttribClass_Null) { + AssertAlways(!"unexpected attrib class"); + } + return result; +} + +internal DW_CompUnit +dw_cu_from_info_off(Arena *arena, DW_Input *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed) +{ + DW_CompUnit cu = {0}; + + String8 info_data = input->sec[DW_Section_Info].data; + + // read unit size in bytes + U64 length = 0; + U64 length_size = str8_deserial_read_dwarf_packed_size(info_data, offset, &length); + + if (length_size) { + // compute unit range + Rng1U64 range = rng_1u64(offset, offset + length_size + length); + String8 data = str8_substr(info_data, range); + U64 cursor = length_size; + + // read version + DW_Version version = 0; + U64 version_size = str8_deserial_read_struct(data, cursor, &version); + cursor += version_size; + + if (version_size) { + DW_Format format = DW_FormatFromSize(length); + B32 is_header_ok = 0; + U64 abbrev_base = max_U64; + U8 address_size = 0; + DW_CompUnitKind unit_kind = DW_CompUnitKind_Reserved; + U64 spec_dwo_id = max_U64; + + switch (version) { + default: + case DW_Version_Null: + case DW_Version_1: + break; + case DW_Version_2: { + U32 abbrev_base32 = 0; + U64 abbrev_base_off = cursor; + U64 abbrev_base_size = str8_deserial_read_struct(data, abbrev_base_off, &abbrev_base32); + if (!abbrev_base_size) { + break; + } + + U64 address_size_off = abbrev_base_off + abbrev_base_size; + U64 address_size_size = str8_deserial_read_struct(data, address_size_off, &address_size); + if (!address_size_size) { + break; + } + + abbrev_base = abbrev_base32; + cursor = address_size_off + address_size_size; + is_header_ok = 1; + } break; + case DW_Version_3: + case DW_Version_4: { + U64 abbrev_base_off = cursor; + U64 abbrev_base_size = str8_deserial_read_dwarf_uint(data, abbrev_base_off, format, &abbrev_base); + if (!abbrev_base_size) { + break; + } + + U64 address_size_off = abbrev_base_off + abbrev_base_size; + U64 address_size_size = str8_deserial_read_struct(data, address_size_off, &address_size); + if (!address_size_size) { + break; + } + + cursor = address_size_off + address_size_size; + is_header_ok = 1; + } break; + case DW_Version_5: { + U64 unit_kind_off = cursor; + U64 unit_kind_size = str8_deserial_read_struct(data, unit_kind_off, &unit_kind); + if (unit_kind_size == 0) { + break; + } + + U64 address_size_off = unit_kind_off + unit_kind_size; + U64 address_size_size = str8_deserial_read_struct(data, address_size_off, &address_size); + if (!address_size_size) { + break; + } + + U64 abbrev_base_off = address_size_off + address_size_size; + U64 abbrev_base_size = str8_deserial_read_dwarf_uint(data, abbrev_base_off, format, &abbrev_base); + if (!abbrev_base_size) { + break; + } + + U64 spec_dwo_id_off = abbrev_base_off + abbrev_base_size; + U64 spec_dwo_id_size = 0; + if (unit_kind == DW_CompUnitKind_Skeleton || input->sec[DW_Section_Info].is_dwo) { + spec_dwo_id_size = str8_deserial_read_struct(data, spec_dwo_id_off, &spec_dwo_id); + if (!spec_dwo_id_size) { + break; + } + } + + cursor = spec_dwo_id_off + spec_dwo_id_size; + is_header_ok = 1; + } break; + } + + if (is_header_ok) { + Temp temp = temp_begin(arena); + + // TODO: cache abbrev tables with identical offsets + String8 abbrev_data = input->sec[DW_Section_Abbrev].data; + DW_AbbrevTable abbrev_table = dw_make_abbrev_table(arena, abbrev_data, abbrev_base); + + DW_Tag cu_tag = {0}; + dw_read_tag(arena, data, cursor, range.min, abbrev_table, abbrev_data, version, format, address_size, &cu_tag); + + // TODO: handle these unit types + Assert(cu_tag.kind != DW_Tag_SkeletonUnit); + Assert(cu_tag.kind != DW_Tag_TypeUnit); + + if (cu_tag.kind == DW_Tag_CompileUnit || cu_tag.kind == DW_Tag_PartialUnit) { + // fetch attribs for list sections + DW_Attrib *addr_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_AddrBase ); + DW_Attrib *str_offsets_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_StrOffsetsBase); + DW_Attrib *rnglists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_RngListsBase ); + DW_Attrib *loclists_base_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_LocListsBase ); + + // interp attribs as section offsets + U64 addr_sec_off = dw_interp_sec_offset(addr_base_attrib->form_kind, addr_base_attrib->form ); + U64 str_offsets_sec_off = dw_interp_sec_offset(str_offsets_base_attrib->form_kind, str_offsets_base_attrib->form); + U64 rnglists_sec_off = dw_interp_sec_offset(rnglists_base_attrib->form_kind, rnglists_base_attrib->form ); + U64 loclists_sec_off = dw_interp_sec_offset(loclists_base_attrib->form_kind, loclists_base_attrib->form ); + + // map section offset to unit index + U64 addr_lu_idx = rng_1u64_array_bsearch(lu_input.addr_ranges, addr_sec_off ); + U64 str_offsets_lu_idx = rng_1u64_array_bsearch(lu_input.str_offset_ranges, str_offsets_sec_off); + U64 rnglists_lu_idx = rng_1u64_array_bsearch(lu_input.rnglist_ranges, rnglists_sec_off ); + U64 loclists_lu_idx = rng_1u64_array_bsearch(lu_input.loclist_ranges, loclists_sec_off ); + + // map index to unit + DW_ListUnit *addr_lu = addr_lu_idx < lu_input.addr_count ? &lu_input.addrs[addr_lu_idx] : 0; + DW_ListUnit *str_offsets_lu = str_offsets_lu_idx < lu_input.str_offset_count ? &lu_input.str_offsets[str_offsets_lu_idx] : 0; + DW_ListUnit *rnglists_lu = rnglists_lu_idx < lu_input.rnglist_count ? &lu_input.rnglists[rnglists_lu_idx] : 0; + DW_ListUnit *loclists_lu = loclists_lu_idx < lu_input.loclist_count ? &lu_input.loclists[loclists_lu_idx] : 0; + + // find compile unit base address + DW_Attrib *low_pc_attrib = dw_attrib_from_tag(0, 0, cu_tag, DW_Attrib_LowPc); + U64 low_pc = dw_interp_address(address_size, max_U64, addr_lu, low_pc_attrib->form_kind, low_pc_attrib->form); + + // fill out compile unit + cu.relaxed = relaxed; + cu.ext = DW_Ext_All; + cu.kind = unit_kind; + cu.version = version; + cu.format = format; + cu.address_size = address_size; + cu.abbrev_off = abbrev_base; + cu.info_range = range; + cu.first_tag_info_off = range.min + cursor; + cu.abbrev_table = abbrev_table; + cu.abbrev_data = abbrev_data; + cu.addr_lu = addr_lu; + cu.str_offsets_lu = str_offsets_lu; + cu.rnglists_lu = rnglists_lu; + cu.loclists_lu = loclists_lu; + cu.low_pc = low_pc; + cu.tag = cu_tag; + } else { + // unexpected tag, release memory and exit + temp_end(temp); + } + } + } + } + + return cu; +} + +internal void +dw_tag_tree_from_data(Arena *arena, String8 info_data, String8 abbrev_data, DW_CompUnit *cu, DW_TagNode *parent, U64 *cursor, U64 *tag_count) +{ + while (*cursor < info_data.size) { + // read tag + DW_Tag tag = {0}; + U64 tag_size = dw_read_tag(arena, info_data, *cursor, cu->info_range.min, cu->abbrev_table, abbrev_data, cu->version, cu->format, cu->address_size, &tag); + if (tag_size == 0) { + break; + } + *cursor += tag_size; + + // is this sentinel tag? + if (tag.kind == DW_Tag_Null) { + break; + } + + // normal tag + DW_TagNode *tag_n = push_array(arena, DW_TagNode, 1); + tag_n->tag = tag; + + SLLQueuePush_N(parent->first_child, parent->last_child, tag_n, sibling); + + // update tag count + *tag_count += 1; + + if (tag.has_children) { + dw_tag_tree_from_data(arena, info_data, abbrev_data, cu, tag_n, cursor, tag_count); + } + } +} + +internal DW_TagTree +dw_tag_tree_from_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu) +{ + String8 abbrev_data = input->sec[DW_Section_Abbrev].data; + String8 info_data = str8_substr(input->sec[DW_Section_Info].data, cu->info_range); + DW_TagNode root = {0}; + U64 cursor = cu->first_tag_info_off; + U64 tag_count = 0; + dw_tag_tree_from_data(arena, info_data, abbrev_data, cu, &root, &cursor, &tag_count); + + DW_TagTree result = {0}; + result.root = root.first_child; + result.tag_count = tag_count; + + return result; +} + +internal HashTable * +dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree) +{ + Temp scratch = scratch_begin(&arena, 1); + + struct Frame { + struct Frame *next; + DW_TagNode *node; + }; + + struct Frame *free_frames = 0; + struct Frame *stack = push_array(scratch.arena, struct Frame, 1); + stack->node = tag_tree.root; + + HashTable *ht = hash_table_init(arena, (U64)((F64)tag_tree.tag_count * 1.3)); + + while (stack) { + while (stack->node) { + hash_table_push_u64_raw(arena, ht, stack->node->tag.info_off, stack->node); + + if (stack->node->first_child) { + struct Frame *frame = free_frames; + if (frame) { + SLLStackPop(free_frames); + MemoryZeroStruct(frame); + } else { + frame = push_array(scratch.arena, struct Frame, 1); + } + frame->node = stack->node->first_child; + SLLStackPush(stack, frame); + } else { + stack->node = stack->node->sibling; + } + } + + // recycle free frame + struct Frame *frame = stack; + SLLStackPop(stack); + SLLStackPush(free_frames, frame); + + if (stack) { + stack->node = stack->node->sibling; + } + } + + scratch_end(scratch); + return ht; +} + +internal DW_TagNode * +dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off) +{ + DW_TagNode *tag_node = hash_table_search_u64_raw(cu->tag_ht, info_off); + return tag_node; +} + +internal DW_LineVMFileArray +dw_line_vm_file_array_from_list(Arena *arena, DW_LineVMFileList list) +{ + DW_LineVMFileArray result = {0}; + result.count = 0; + result.v = push_array(arena, DW_LineFile, list.node_count); + + for (DW_LineVMFileNode *src = list.first; src != 0; src = src->next) { + DW_LineFile *dst = &result.v[result.count++]; + dst->file_name = push_str8_copy(arena, src->file.file_name); + dst->dir_idx = src->file.dir_idx; + dst->modify_time = src->file.modify_time; + dst->file_size = src->file.file_size; + } + + return result; +} + +internal U64 +dw_read_line_file(String8 data, + U64 off, + DW_Input *input, + DW_Version version, + DW_Format format, + DW_Ext ext, + U64 address_size, + DW_ListUnit *str_offsets, + U64 enc_count, + U64 *enc_arr, + DW_LineFile *line_file_out) +{ + MemoryZeroStruct(line_file_out); + U64 cursor = off; + for (U64 enc_idx = 0; enc_idx < enc_count; ++enc_idx) { + DW_LNCT lnct = enc_arr[enc_idx*2 + 0]; + DW_FormKind form_kind = enc_arr[enc_idx*2 + 1]; + DW_Form form = {0}; + U64 bytes_read; + switch (lnct) { + case DW_LNCT_Path: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->file_name = dw_interp_string(input, format, str_offsets, form_kind, form); + } break; + case DW_LNCT_DirectoryIndex: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->dir_idx = dw_interp_const_u64(form_kind, form); + } break; + case DW_LNCT_TimeStamp: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->modify_time = dw_interp_const_u64(form_kind, form); + } break; + case DW_LNCT_Size: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->file_size = dw_interp_const_u64(form_kind, form); + } break; + case DW_LNCT_MD5: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->md5_digest = dw_interp_const_u128(form_kind, form); + } break; + case DW_LNCT_LLVM_Source: { + if (ext & DW_Ext_LLVM) { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + line_file_out->source = dw_interp_string(input, format, str_offsets, form_kind, form); + } else { + Assert(!"extension not supported"); + } + } break; + default: { + bytes_read = dw_read_form(data, cursor, version, format, address_size, form_kind, max_U64, &form); + Assert(!"unexpected LNTC encoding"); + } break; + } + Assert(bytes_read); + cursor += bytes_read; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +dw_read_line_file_array(Arena *arena, + String8 data, + U64 off, + DW_Input *input, + DW_Version version, + DW_Format format, + DW_Ext ext, + U64 address_size, + DW_ListUnit *str_offsets, + U64 enc_count, + U64 *enc_arr, + U64 table_count, + DW_LineVMFileArray *table_out) +{ + Temp temp = temp_begin(arena); + + table_out->count = table_count; + table_out->v = push_array(arena, DW_LineFile, table_count); + + U64 i, cursor; + for (i = 0, cursor = off; i < table_count; ++i) { + U64 bytes_read = dw_read_line_file(data, + cursor, + input, + version, + format, + ext, + address_size, + str_offsets, + enc_count, + enc_arr, + &table_out->v[i]); + if (bytes_read == 0) { + break; + } + cursor += bytes_read; + } + + U64 bytes_read = 0; + if (i == table_count) { + bytes_read = cursor - off; + } else { + temp_end(temp); + table_out->count = 0; + table_out->v = 0; + } + + return bytes_read; +} + +internal U64 +dw_read_line_vm_header(Arena *arena, + String8 line_data, + U64 line_off, + DW_Input *input, + String8 cu_dir, + String8 cu_name, + U8 cu_address_size, + DW_ListUnit *cu_str_offsets, + DW_LineVMHeader *header_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 bytes_read = 0; + + // read unit length + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(line_data, line_off, &unit_length); + + U64 unit_opl = line_off + unit_length_size + unit_length; + Rng1U64 unit_range = rng_1u64(line_off, unit_opl); + DW_Format format = DW_FormatFromSize(unit_length); + U64 unit_cursor = unit_length_size; + String8 unit_data = str8_substr(line_data, unit_range); + + // read unit version + DW_Version version = DW_Version_Null; + U64 version_size = str8_deserial_read_struct(unit_data, unit_cursor, &version); + if (version_size == 0) { + goto exit; + } + unit_cursor += version_size; + + // read DWARF5 address & segment selector + U8 address_size = 0; + U8 segsel_size = 0; + if (version == DW_Version_5) { + U64 address_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &address_size); + if (address_size_size == 0) { + goto exit; + } + unit_cursor += address_size_size; + + U64 segsel_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &segsel_size); + if (segsel_size_size == 0) { + goto exit; + } + unit_cursor += segsel_size_size; + } else { + address_size = cu_address_size; + } + + // read header length + U64 header_length = 0; + U64 header_length_size = str8_deserial_read_dwarf_uint(unit_data, unit_cursor, format, &header_length); + if (header_length_size == 0) { + goto exit; + } + unit_cursor += header_length_size; + + // read min instruction length + U8 min_inst_len = 0; + U64 min_inst_len_size = str8_deserial_read_struct(unit_data, unit_cursor, &min_inst_len); + if (min_inst_len_size == 0) { + goto exit; + } + unit_cursor += min_inst_len_size; + + // read max operands for instruction + U8 max_ops_for_inst = 1; + if (version > DW_Version_3) { + U64 max_ops_for_inst_size = str8_deserial_read_struct(unit_data, unit_cursor, &max_ops_for_inst); + if (max_ops_for_inst_size == 0) { + goto exit; + } + unit_cursor += max_ops_for_inst_size; + } + Assert(max_ops_for_inst > 0); + + U8 default_is_stmt = 0; + U64 default_is_stmt_size = str8_deserial_read_struct(unit_data, unit_cursor, &default_is_stmt); + if (default_is_stmt_size == 0) { + goto exit; + } + unit_cursor += default_is_stmt_size; + + S8 line_base = 0; + U64 line_base_size = str8_deserial_read_struct(unit_data, unit_cursor, &line_base); + if (line_base_size == 0) { + goto exit; + } + unit_cursor += line_base_size; + + U8 line_range = 0; + U64 line_range_size = str8_deserial_read_struct(unit_data, unit_cursor, &line_range); + if (line_range_size == 0) { + goto exit; + } + unit_cursor += line_range_size; + + U8 opcode_base = 0; + U64 opcode_base_size = str8_deserial_read_struct(unit_data, unit_cursor, &opcode_base); + if (opcode_base_size == 0) { + goto exit; + } + unit_cursor += opcode_base_size; + + U64 num_opcode_lens = opcode_base > 0 ? opcode_base - 1 : 0; + U8 *opcode_lens = str8_deserial_get_raw_ptr(unit_data, unit_cursor, num_opcode_lens * sizeof(opcode_lens[0])); + if (opcode_lens == 0) { + goto exit; + } + unit_cursor += num_opcode_lens * sizeof(opcode_lens[0]); + + DW_LineVMFileArray dir_table = {0}; + DW_LineVMFileArray file_table = {0}; + if (version < DW_Version_5) { + // read directory table + DW_LineVMFileList dir_list = {0}; + { + // compile directory is always first in the table + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = cu_dir; + SLLQueuePush(dir_list.first, dir_list.last, node); + ++dir_list.node_count; + } + + // parse additional directories + for (; unit_cursor < unit_data.size; ) { + String8 dir = {0}; + unit_cursor += str8_deserial_read_cstr(unit_data, unit_cursor, &dir); + if (dir.size == 0) { + break; + } + + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = dir; + SLLQueuePush(dir_list.first, dir_list.last, node); + ++dir_list.node_count; + } + + DW_LineVMFileList file_list = {0}; + { + // compile unit name is always first in the file table + { + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = cu_name; + SLLQueuePush(file_list.first, file_list.last, node); + ++file_list.node_count; + } + + // read file table + for (; unit_cursor < unit_data.size; ) { + String8 file_name = {0}; + unit_cursor += str8_deserial_read_cstr(unit_data, unit_cursor, &file_name); + if (file_name.size == 0) { + break; + } + + U64 dir_index = 0; + U64 dir_index_size = str8_deserial_read_uleb128(unit_data, unit_cursor, &dir_index); + if (dir_index_size == 0) { + goto exit; + } + unit_cursor += dir_index_size; + + U64 modify_time = 0; + U64 modify_time_size = str8_deserial_read_uleb128(unit_data, unit_cursor, &modify_time); + if (modify_time_size == 0) { + goto exit; + } + unit_cursor += modify_time_size; + + U64 file_size = 0; + U64 file_size_size = str8_deserial_read_uleb128(unit_data, unit_cursor, &file_size); + if (file_size_size == 0) { + goto exit; + } + unit_cursor += file_size_size; + + DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); + node->file.file_name = file_name; + node->file.dir_idx = dir_index; + node->file.modify_time = modify_time; + node->file.file_size = file_size; + + SLLQueuePush(file_list.first, file_list.last, node); + ++file_list.node_count; + } + } + + // list -> array + dir_table = dw_line_vm_file_array_from_list(arena, dir_list); + file_table = dw_line_vm_file_array_from_list(arena, file_list); + } + // DWARF5 + else { + // directory table + { + // read table entry encoding count + U8 enc_count = 0; + U64 enc_count_size = str8_deserial_read_struct(unit_data, unit_cursor, &enc_count); + if (enc_count_size == 0) { + goto exit; + } + unit_cursor += enc_count_size; + + // read table entry encodings + U64 *enc_arr = 0; + U64 enc_arr_size = str8_deserial_read_uleb128_array(scratch.arena, unit_data, unit_cursor, enc_count*2, &enc_arr); + if (enc_arr_size == 0) { + goto exit; + } + unit_cursor += enc_arr_size; + + // read table count + U64 table_count = 0; + U64 table_count_size = str8_deserial_read_uleb128(unit_data, unit_cursor, &table_count); + if (table_count_size == 0) { + goto exit; + } + unit_cursor += table_count_size; + + // read table + U64 table_size = dw_read_line_file_array(arena, + unit_data, + unit_cursor, + input, + version, + format, + DW_Ext_All, + address_size, + cu_str_offsets, + enc_count, + enc_arr, + table_count, + &dir_table); + if (table_size == 0) { + goto exit; + } + unit_cursor += table_size; + } + + // file table + { + // read table entry encoding count + U8 enc_count = 0; + U64 enc_count_size = str8_deserial_read_struct(unit_data, unit_cursor, &enc_count); + if (enc_count == 0) { + goto exit; + } + unit_cursor += enc_count_size; + + // read table entry encodings + U64 *enc_arr = 0; + U64 enc_arr_size = str8_deserial_read_uleb128_array(scratch.arena, unit_data, unit_cursor, enc_count*2, &enc_arr); + if (enc_arr_size == 0) { + goto exit; + } + unit_cursor += enc_arr_size; + + // read table count + U64 table_count = 0; + U64 table_count_size = str8_deserial_read_uleb128(unit_data, unit_cursor, &table_count); + if (table_count_size == 0) { + goto exit; + } + unit_cursor += table_count_size; + + // read table + U64 file_table_size = dw_read_line_file_array(arena, + unit_data, + unit_cursor, + input, + version, + format, + DW_Ext_All, + address_size, + cu_str_offsets, + enc_count, + enc_arr, + table_count, + &file_table); + if (file_table_size == 0) { + goto exit; + } + unit_cursor += file_table_size; + } + } + + if (header_out) { + header_out->unit_range = unit_range; + header_out->version = version; + header_out->address_size = address_size; + header_out->segment_selector_size = segsel_size; + header_out->header_length = header_length; + header_out->min_inst_len = min_inst_len; + header_out->max_ops_for_inst = max_ops_for_inst; + header_out->default_is_stmt = default_is_stmt; + header_out->line_base = line_base; + header_out->line_range = line_range; + header_out->opcode_base = opcode_base; + header_out->num_opcode_lens = num_opcode_lens; + header_out->opcode_lens = opcode_lens; + header_out->dir_table = dir_table; + header_out->file_table = file_table; + } + + bytes_read = unit_cursor; + +exit:; + scratch_end(scratch); + return bytes_read; +} internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt) @@ -1775,286 +2768,44 @@ dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl) internal DW_LineNode * dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence) { - DW_LineNode *n = 0; - if(vm_state->busted_seq == 0) + DW_LineSeqNode *seq = tbl->last_seq; + if(seq == 0 || start_of_sequence) { - DW_LineSeqNode *seq = tbl->last_seq; - if(seq == 0 || start_of_sequence) - { - // ERROR! do not emit sequences with only one line... - Assert(seq && seq->count > 1); - seq = dw_push_line_seq(arena, tbl); - } - - n = push_array(arena, DW_LineNode, 1); - n->v.file_index = vm_state->file_index; - n->v.line = vm_state->line; - n->v.column = vm_state->column; - n->v.voff = vm_state->address; - - SLLQueuePush(seq->first, seq->last, n); - seq->count += 1; + seq = dw_push_line_seq(arena, tbl); } + + DW_LineNode *n = push_array(arena, DW_LineNode, 1); + n->v.file_index = vm_state->file_index; + n->v.line = vm_state->line; + n->v.column = vm_state->column; + n->v.address = vm_state->address; + + SLLQueuePush(seq->first, seq->last, n); + seq->count += 1; return n; } -internal DW_LineTableParseResult -dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root) -{ - DW_Mode mode = sections->v[DW_Section_Line].mode; - void *base = dw_base_from_sec(sections, DW_Section_Line); - Rng1U64 line_info_range = dw_range_from_sec(sections, DW_Section_Line); - U64 read_off_start = root->line_off - line_info_range.min; - U64 cursor = read_off_start; - - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(root); - - DW_LineVMHeader vm_header = {0}; - cursor += dw_read_line_vm_header(arena, base, line_info_range, cursor, mode, sections, resolve_params, root->compile_dir, root->name, &vm_header); - - //- rjf: prep state for VM - DW_LineVMState vm_state = {0}; - dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); - - //- rjf: VM loop; build output list - DW_LineTableParseResult result = {0}; - B32 end_of_seq = 0; - B32 error = 0; - for (;!error && cursor < vm_header.unit_opl;) { - //- rjf: parse opcode - U8 opcode = 0; - cursor += dw_based_range_read_struct(base, line_info_range, cursor, &opcode); - - //- rjf: do opcode action - switch (opcode) { - default: - { - //- rjf: special opcode case - if(opcode >= vm_header.opcode_base) - { - U32 adjusted_opcode = (U32)(opcode - vm_header.opcode_base); - U32 op_advance = adjusted_opcode / vm_header.line_range; - S32 line_inc = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; - // TODO: can we just call dw_advance_line_vm_state_pc - U64 addr_inc = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); - - vm_state.address += addr_inc; - vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; - vm_state.line = (U32)((S32)vm_state.line + line_inc); - vm_state.basic_block = 0; - vm_state.prologue_end = 0; - vm_state.epilogue_begin = 0; - vm_state.discriminator = 0; - - dw_push_line(arena, &result, &vm_state, end_of_seq); - end_of_seq = 0; - -#if 0 - // NOTE(rjf): DWARF has dummy lines at the end of groups of line ranges, where we'd like - // to break line info into sequences. - if(vm_state.line == 0) - { - end_of_seq = 1; - } -#endif - } - // Skipping unknown opcode. This is a valid case and - // it works because compiler stores operand lengths. - else - { - if(opcode > 0 && opcode <= vm_header.num_opcode_lens) - { - U8 num_operands = vm_header.opcode_lens[opcode - 1]; - for(U8 i = 0; i < num_operands; ++i) - { - U64 operand = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &operand); - } - } - else - { - error = 1; - goto exit; - } - } - } break; - - //- Standard opcodes - - case DW_StdOpcode_Copy: - { - dw_push_line(arena, &result, &vm_state, end_of_seq); - end_of_seq = 0; - vm_state.discriminator = 0; - vm_state.basic_block = 0; - vm_state.prologue_end = 0; - vm_state.epilogue_begin = 0; - } break; - - case DW_StdOpcode_AdvancePc: - { - U64 advance = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &advance); - dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); - } break; - - case DW_StdOpcode_AdvanceLine: - { - S64 s = 0; - cursor += dw_based_range_read_sleb128(base, line_info_range, cursor, &s); - vm_state.line += s; - } break; - - case DW_StdOpcode_SetFile: - { - U64 file_index = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_index); - vm_state.file_index = file_index; - } break; - - case DW_StdOpcode_SetColumn: - { - U64 column = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &column); - vm_state.column = column; - } break; - - case DW_StdOpcode_NegateStmt: - { - vm_state.is_stmt = !vm_state.is_stmt; - } break; - - case DW_StdOpcode_SetBasicBlock: - { - vm_state.basic_block = 1; - } break; - - case DW_StdOpcode_ConstAddPc: - { - U64 advance = (0xffu - vm_header.opcode_base)/vm_header.line_range; - dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); - } break; - - case DW_StdOpcode_FixedAdvancePc: - { - U16 operand = 0; - cursor += dw_based_range_read_struct(base, line_info_range, cursor, &operand); - vm_state.address += operand; - vm_state.op_index = 0; - } break; - - case DW_StdOpcode_SetPrologueEnd: - { - vm_state.prologue_end = 1; - } break; - - case DW_StdOpcode_SetEpilogueBegin: - { - vm_state.epilogue_begin = 1; - } break; - - case DW_StdOpcode_SetIsa: - { - U64 v = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); - vm_state.isa = v; - } break; - - //- Extended opcodes - case DW_StdOpcode_ExtendedOpcode: - { - U64 length = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &length); - U64 start_off = cursor; - U8 extended_opcode = 0; - cursor += dw_based_range_read_struct(base, line_info_range, cursor, &extended_opcode); - - switch (extended_opcode) { - case DW_ExtOpcode_EndSequence: - { - vm_state.end_sequence = 1; - dw_push_line(arena, &result, &vm_state, 0); - dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); - end_of_seq = 1; - } break; - - case DW_ExtOpcode_SetAddress: - { - U64 address = 0; - cursor += dw_based_range_read(base, line_info_range, cursor, root->address_size, &address); - vm_state.address = address; - vm_state.op_index = 0; - vm_state.busted_seq = address != 0; // !(dbg->acceptable_vrange.min <= address && address < dbg->acceptable_vrange.max); - } break; - - case DW_ExtOpcode_DefineFile: - { - String8 file_name = dw_based_range_read_string(base, line_info_range, cursor); - U64 dir_index = 0; - U64 modify_time = 0; - U64 file_size = 0; - cursor += file_name.size + 1; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &dir_index); - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &modify_time); - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &file_size); - - // TODO(rjf): Not fully implemented. By the DWARF V4 spec, the above is - // all that needs to be parsed, but the rest of the work that needs to - // happen here---allowing this file to be used by further opcodes---is - // not implemented. - // - // See the DWARF V4 spec (June 10, 2010), page 122. - error = 1; - AssertAlways(!"UNHANDLED DEFINE FILE!!!"); - } break; - - case DW_ExtOpcode_SetDiscriminator: - { - U64 v = 0; - cursor += dw_based_range_read_uleb128(base, line_info_range, cursor, &v); - vm_state.discriminator = v; - } break; - - default: break; - } - - U64 num_skip = cursor - (start_off + length); - cursor += num_skip; - if (dw_based_range_ptr(base, line_info_range, cursor) == 0 || start_off + length > cursor) { - error = 1; - } - - } break; - } - } - exit:; - - return result; -} - internal String8 -dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) +dw_path_from_file(Arena *arena, DW_LineVMHeader *vm, DW_LineFile *file) { Temp scratch = scratch_begin(&arena, 1); - - DW_LineFile *lf = &vm->file_table.v[file_idx]; - String8 dir = vm->dir_table.v[lf->dir_idx]; + String8 dir = vm->dir_table.v[file->dir_idx].file_name; PathStyle style = path_style_from_str8(dir); if (style == PathStyle_Null || style == PathStyle_Relative) { - style = path_style_from_str8(lf->file_name); + style = path_style_from_str8(file->file_name); } String8List path_list = {0}; if (str8_match_lit("..", dir, StringMatchFlag_RightSideSloppy)) { - String8List comp_dir_list = str8_split_path(scratch.arena, vm->dir_table.v[0]); + String8List comp_dir_list = str8_split_path(scratch.arena, vm->dir_table.v[0].file_name); str8_list_concat_in_place(&path_list, &comp_dir_list); } String8List dir_list = str8_split_path(scratch.arena, dir); str8_list_concat_in_place(&path_list, &dir_list); - str8_list_push(scratch.arena, &path_list, lf->file_name); + str8_list_push(scratch.arena, &path_list, file->file_name); str8_path_list_resolve_dots_in_place(&path_list, style); @@ -2064,299 +2815,298 @@ dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) return path; } -internal U64 -dw_read_line_file(void *line_base, - Rng1U64 line_rng, - U64 line_off, - DW_Mode mode, - DW_SectionArray *sections, - DW_AttribValueResolveParams resolve_params, - U8 address_size, - U64 format_count, - Rng1U64 *formats, - DW_LineFile *line_file_out) +internal String8 +dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx) { - MemoryZeroStruct(line_file_out); + return dw_path_from_file(arena, vm, &vm->file_table.v[file_idx]); +} + +internal DW_LineTableParseResult +dw_parsed_line_table_from_data(Arena *arena, + String8 unit_data, + DW_Input *input, + String8 cu_dir, + String8 cu_name, + U8 cu_address_size, + DW_ListUnit *cu_str_offsets) +{ + DW_LineVMHeader vm_header = {0}; + U64 vm_header_size = dw_read_line_vm_header(arena, unit_data, 0, input, cu_dir, cu_name, cu_address_size, cu_str_offsets, &vm_header); + + U64 unit_cursor = vm_header_size; - U64 line_off_start = line_off; - for (U64 format_idx = 0; format_idx < format_count; ++format_idx) - { - DW_LNCT lnct = (DW_LNCT)formats[format_idx].min; - DW_FormKind form_kind = (DW_FormKind)formats[format_idx].max; - DW_AttribValue form_value = {0}; - line_off += dw_based_range_read_attrib_form_value(line_base, line_rng, line_off, mode, address_size, form_kind, 0, &form_value); - switch (lnct) - { - case DW_LNCT_Path: + //- rjf: prep state for VM + DW_LineVMState vm_state = {0}; + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + + //- rjf: VM loop; build output list + DW_LineTableParseResult result = { .vm_header = vm_header }; + B32 end_of_seq = 0; + B32 error = 0; + for (; !error && unit_cursor < unit_data.size; ) { + //- rjf: parse opcode + U8 opcode = 0; + unit_cursor += str8_deserial_read_struct(unit_data, unit_cursor, &opcode); + + //- rjf: do opcode action + switch (opcode) { + default: { + //- rjf: special opcode case + if (opcode >= vm_header.opcode_base) { + U32 adjusted_opcode = (U32)(opcode - vm_header.opcode_base); + U32 op_advance = adjusted_opcode / vm_header.line_range; + S32 line_inc = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; + // TODO: can we just call dw_advance_line_vm_state_pc + U64 addr_inc = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); + + vm_state.address += addr_inc; + vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; + vm_state.line = (U32)((S32)vm_state.line + line_inc); + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + vm_state.discriminator = 0; + + if(vm_state.is_stmt) + { + dw_push_line(arena, &result, &vm_state, end_of_seq); + } + end_of_seq = 0; + +#if 0 + // NOTE(rjf): DWARF has dummy lines at the end of groups of line ranges, where we'd like + // to break line info into sequences. + if(vm_state.line == 0) + { + end_of_seq = 1; + } +#endif + } + // Skipping unknown opcode. This is a valid case and + // it works because compiler stores operand lengths. + else { + if (0 < opcode && opcode <= vm_header.num_opcode_lens) { + U8 num_operands = vm_header.opcode_lens[opcode - 1]; + for (U8 i = 0; i < num_operands; ++i) { + U64 operand = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &operand); + } + } else { + error = 1; + goto exit; + } + } + } break; + + //- Standard opcodes + + case DW_StdOpcode_Copy: { + if(vm_state.is_stmt) { - Assert(form_kind == DW_Form_String || form_kind == DW_Form_LineStrp || - form_kind == DW_Form_Strp || form_kind == DW_Form_StrpSup || - form_kind == DW_Form_Strx || form_kind == DW_Form_Strx1 || - form_kind == DW_Form_Strx2 || form_kind == DW_Form_Strx3 || - form_kind == DW_Form_Strx4); - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_String, form_value); - line_file_out->file_name = dw_string_from_attrib_value(sections, attrib_value); + dw_push_line(arena, &result, &vm_state, end_of_seq); + } + end_of_seq = 0; + vm_state.discriminator = 0; + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + } break; + + case DW_StdOpcode_AdvancePc: { + U64 advance = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &advance); + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + } break; + + case DW_StdOpcode_AdvanceLine: { + S64 s = 0; + unit_cursor += str8_deserial_read_sleb128(unit_data, unit_cursor, &s); + vm_state.line += s; + } break; + + case DW_StdOpcode_SetFile: { + U64 file_index = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &file_index); + vm_state.file_index = file_index; + } break; + + case DW_StdOpcode_SetColumn: { + U64 column = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &column); + vm_state.column = column; + } break; + + case DW_StdOpcode_NegateStmt: { + vm_state.is_stmt = !vm_state.is_stmt; + } break; + + case DW_StdOpcode_SetBasicBlock: { + vm_state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: { + U64 advance = (0xffu - vm_header.opcode_base) / vm_header.line_range; + dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); + } break; + + case DW_StdOpcode_FixedAdvancePc: { + U16 operand = 0; + unit_cursor += str8_deserial_read_struct(unit_data, unit_cursor, &operand); + vm_state.address += operand; + vm_state.op_index = 0; + } break; + + case DW_StdOpcode_SetPrologueEnd: { + vm_state.prologue_end = 1; + } break; + + case DW_StdOpcode_SetEpilogueBegin: { + vm_state.epilogue_begin = 1; + } break; + + case DW_StdOpcode_SetIsa: { + U64 v = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &v); + vm_state.isa = v; + } break; + + //- Extended opcodes + case DW_StdOpcode_ExtendedOpcode: { + U64 length = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &length); + + U64 extended_opl = unit_cursor + length; + U8 extended_opcode = 0; + unit_cursor += str8_deserial_read_struct(unit_data, unit_cursor, &extended_opcode); + + switch (extended_opcode) { + case DW_ExtOpcode_EndSequence: { + vm_state.end_sequence = 1; + if(vm_state.is_stmt) + { + dw_push_line(arena, &result, &vm_state, 0); + } + dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + end_of_seq = 1; } break; - case DW_LNCT_DirectoryIndex: - { - Assert(form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || - form_kind == DW_Form_UData); - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); - line_file_out->dir_idx = attrib_value.v[0]; + case DW_ExtOpcode_SetAddress: { + U64 address = 0; + unit_cursor += str8_deserial_read(unit_data, unit_cursor, &address, vm_header.address_size, vm_header.address_size); + vm_state.address = address; + vm_state.op_index = 0; } break; - case DW_LNCT_TimeStamp: - { - Assert(form_kind == DW_Form_UData || form_kind == DW_Form_Data4 || - form_kind == DW_Form_Data8 || form_kind == DW_Form_Block); - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Const, form_value); - line_file_out->modify_time = attrib_value.v[0]; + case DW_ExtOpcode_DefineFile: { + String8 file_name = {0}; + U64 dir_index = 0; + U64 modify_time = 0; + U64 file_size = 0; + + unit_cursor += str8_deserial_read_cstr(unit_data, unit_cursor, &file_name); + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &dir_index); + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &modify_time); + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &file_size); + + // TODO(rjf): Not fully implemented. By the DWARF V4 spec, the above is + // all that needs to be parsed, but the rest of the work that needs to + // happen here---allowing this file to be used by further opcodes---is + // not implemented. + // + // See the DWARF V4 spec (June 10, 2010), page 122. + error = 1; + AssertAlways(!"UNHANDLED DEFINE FILE!!!"); } break; - case DW_LNCT_Size: - { - Assert(form_kind == DW_Form_UData || form_kind == DW_Form_Data1 || - form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || - form_kind == DW_Form_Data8); - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); - line_file_out->file_size = attrib_value.v[0]; + case DW_ExtOpcode_SetDiscriminator: { + U64 v = 0; + unit_cursor += str8_deserial_read_uleb128(unit_data, unit_cursor, &v); + vm_state.discriminator = v; } break; - case DW_LNCT_MD5: - { - Assert(form_kind == DW_Form_Data16); - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, form_kind, DW_AttribClass_Block, form_value); - line_file_out->md5_digest[0] = attrib_value.v[0]; - line_file_out->md5_digest[1] = attrib_value.v[1]; - } break; + default: break; + } - default: - { - Assert(DW_LNCT_UserLo < lnct && lnct < DW_LNCT_UserHi); - } break; + unit_cursor = extended_opl; + } break; } } - U64 result = line_off - line_off_start; + + exit:; + return result; } -internal U64 -dw_read_line_vm_header(Arena *arena, - void *line_base, - Rng1U64 line_rng, - U64 line_off, - DW_Mode mode, - DW_SectionArray *sections, - DW_AttribValueResolveParams resolve_params, - String8 compile_dir, - String8 unit_name, - DW_LineVMHeader *header_out) +internal DW_PubStringsTable +dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_SectionKind section_kind) { Temp scratch = scratch_begin(&arena, 1); - MemoryZeroStruct(header_out); + DW_PubStringsTable names_table = {0}; + names_table.size = 16384; + names_table.buckets = push_array(arena, DW_PubStringsBucket*, names_table.size); - //- rjf: parse unit length - U64 unit_length = 0; - U64 unit_length_size = dw_based_range_read_length(line_base, line_rng, line_off, &unit_length); - - header_out->unit_length = unit_length; - header_out->unit_opl = line_off + unit_length + unit_length_size; + String8 section_data = input->sec[section_kind].data; + for(U64 cursor = 0; cursor < section_data.size; ) { - U64 cursor = unit_length_size; - Rng1U64 parse_rng = rng_1u64(line_off, header_out->unit_opl); + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(section_data, cursor, &unit_length); + if (unit_length_size == 0) { + break; + } + cursor += unit_length_size; - //- rjf: parse version and header length - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->version); - - if(header_out->version == DW_Version_5) - { - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->address_size); - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->segment_selector_size); - } - - cursor += dw_based_range_read(line_base, parse_rng, cursor, dw_offset_size_from_mode(mode), &header_out->header_length); - - //- rjf: calculate program offset - header_out->program_off = parse_rng.min + cursor + header_out->header_length; - - //- rjf: parse minimum instruction length - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->min_inst_len); - - //- rjf: parse max ops for instruction - switch(header_out->version) - { - case DW_Version_5: - case DW_Version_4: - { - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->max_ops_for_inst); - Assert(header_out->max_ops_for_inst > 0); - } break; - case DW_Version_3: - case DW_Version_2: - case DW_Version_1: - { - header_out->max_ops_for_inst = 1; - } break; - default: break; - } - - //- rjf: parse rest of program info - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->default_is_stmt); - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_base); - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->line_range); - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &header_out->opcode_base); - - //- rjf: calculate opcode length array - header_out->num_opcode_lens = header_out->opcode_base > 0 ? header_out->opcode_base - 1u : 0; - header_out->opcode_lens = dw_based_range_ptr_size(line_base, parse_rng, cursor, header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0])); - cursor += header_out->num_opcode_lens * sizeof(header_out->opcode_lens[0]); - - if(header_out->version == DW_Version_5) - { - //- parse directory names - U8 directory_entry_format_count = 0; - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &directory_entry_format_count); - Assert(directory_entry_format_count == 1); - Rng1U64 *directory_entry_formats = push_array(scratch.arena, Rng1U64, directory_entry_format_count); - for(U8 format_idx = 0; format_idx < directory_entry_format_count; ++format_idx) - { - U64 content_type_code = 0, form_code = 0; - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); - directory_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); + U64 cursor_opl = Min(cursor + unit_length, section_data.size); + if (cursor >= cursor_opl) { + break; } - U64 directories_count = 0; - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &directories_count); - header_out->dir_table.count = directories_count; - header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); - for(U64 dir_idx = 0; dir_idx < directories_count; ++dir_idx) - { - DW_LineFile line_file; - cursor += dw_read_line_file(line_base, - parse_rng, - cursor, - mode, - sections, - resolve_params, - header_out->address_size, - directory_entry_format_count, - directory_entry_formats, - &line_file); - header_out->dir_table.v[dir_idx] = push_str8_copy(arena, line_file.file_name); + DW_Version unit_version = 0; + cursor += str8_deserial_read_struct(section_data, cursor, &unit_version); + if (cursor >= cursor_opl) { + break; } - //- parse file table - U8 file_name_entry_format_count = 0; - cursor += dw_based_range_read_struct(line_base, parse_rng, cursor, &file_name_entry_format_count); - Rng1U64 *file_name_entry_formats = push_array(scratch.arena, Rng1U64, file_name_entry_format_count); - for(U8 format_idx = 0; format_idx < file_name_entry_format_count; ++format_idx) - { - U64 content_type_code = 0, form_code = 0; - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &content_type_code); - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &form_code); - file_name_entry_formats[format_idx] = rng_1u64(content_type_code, form_code); + DW_Format format = DW_FormatFromSize(unit_length); + + U64 debug_info_off = 0; + cursor += str8_deserial_read_dwarf_uint(section_data, cursor, format, &debug_info_off); + if (cursor >= cursor_opl) { + break; } - U64 file_names_count = 0; - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_names_count); - header_out->file_table.count = file_names_count; - header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); - for(U64 file_idx = 0; file_idx < file_names_count; ++file_idx) - { - cursor += dw_read_line_file(line_base, - parse_rng, - cursor, - mode, - sections, - resolve_params, - header_out->address_size, - file_name_entry_format_count, - file_name_entry_formats, - &header_out->file_table.v[file_idx]); + U64 debug_info_length = 0; + cursor += str8_deserial_read_dwarf_packed_size(section_data, cursor, &debug_info_length); + if (cursor >= cursor_opl) { + break; } - } - else - { - String8List dir_list = {0}; - str8_list_push(scratch.arena, &dir_list, compile_dir); - for (;;) - { - String8 dir = dw_based_range_read_string(line_base, parse_rng, cursor); - cursor += dir.size + 1; - if (dir.size == 0) - { + + U64 off_size = dw_size_from_format(format); + for (; (cursor + off_size) <= cursor_opl;) { + U64 info_off = 0; + U64 info_off_size = str8_deserial_read_dwarf_uint(section_data, cursor, format, &info_off); + cursor += info_off_size; + + if (info_off_size == 0 || info_off == 0) { break; } - str8_list_push(scratch.arena, &dir_list, dir); - } - - DW_LineVMFileList file_list = {0}; - - //- rjf: push 0-index file (compile file) - { - DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); - node->file.file_name = unit_name; - SLLQueuePush(file_list.first, file_list.last, node); - file_list.node_count += 1; - } - - for(;;) - { - String8 file_name = dw_based_range_read_string(line_base, parse_rng, cursor); - U64 dir_index = 0; - U64 modify_time = 0; - U64 file_size = 0; - cursor += file_name.size + 1; - if(file_name.size == 0) - { - break; - } - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &dir_index); - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &modify_time); - cursor += dw_based_range_read_uleb128(line_base, parse_rng, cursor, &file_size); - DW_LineVMFileNode *node = push_array(scratch.arena, DW_LineVMFileNode, 1); - node->file.file_name = file_name; - node->file.dir_idx = dir_index; - node->file.modify_time = modify_time; - node->file.file_size = file_size; - SLLQueuePush(file_list.first, file_list.last, node); - file_list.node_count += 1; - } - - //- rjf: build dir table - { - header_out->dir_table.count = dir_list.node_count; - header_out->dir_table.v = push_array(arena, String8, header_out->dir_table.count); + String8 string = {0}; + cursor += str8_deserial_read_cstr(section_data, cursor, &string); - String8Node *n = dir_list.first; - for(U64 idx = 0; n != 0 && idx < header_out->dir_table.count; idx += 1, n = n->next) - { - header_out->dir_table.v[idx] = push_str8_copy(arena, n->string); - } - } - - //- rjf: build file table - { - header_out->file_table.count = file_list.node_count; - header_out->file_table.v = push_array(arena, DW_LineFile, header_out->file_table.count); - - U64 file_idx = 0; - DW_LineVMFileNode *file_node = file_list.first; - for(; file_node != 0; file_idx += 1, file_node = file_node->next) - { - header_out->file_table.v[file_idx].file_name = push_str8_copy(arena, file_node->file.file_name); - header_out->file_table.v[file_idx].dir_idx = file_node->file.dir_idx; - header_out->file_table.v[file_idx].modify_time = file_node->file.modify_time; - header_out->file_table.v[file_idx].file_size = file_node->file.file_size; - } + U64 hash = dw_hash_from_string(string); + U64 bucket_idx = hash % names_table.size; + + DW_PubStringsBucket *bucket = push_array(arena, DW_PubStringsBucket, 1); + bucket->next = names_table.buckets[bucket_idx]; + bucket->string = string; + bucket->info_off = info_off; + bucket->cu_info_off = debug_info_off; + names_table.buckets[bucket_idx] = bucket; } } - + scratch_end(scratch); - return cursor; + return names_table; } diff --git a/src/dwarf/dwarf_parse.h b/src/dwarf/dwarf_parse.h index 6cce84b8..99a589d6 100644 --- a/src/dwarf/dwarf_parse.h +++ b/src/dwarf/dwarf_parse.h @@ -4,38 +4,49 @@ #ifndef DWARF_PARSE_H #define DWARF_PARSE_H -// NOTE(rjf): Some rules about the spaces of offsets and ranges: -// -// - Every stored/passed offset is relative to the base of its section. -// - Every stored/passed range has endpoints relative to the base of their section. -// - Upon calling a syms_based_range_* function, these offsets need to be -// converted into range-relative. - -//////////////////////////////// -//~ rjf: Constants - -#define DWARF_VOID_TYPE_ID 0xffffffffffffffffull - -//////////////////////////////// -//~ rjf: Files + External Debug References - -typedef struct DW_ExtDebugRef DW_ExtDebugRef; -struct DW_ExtDebugRef +typedef struct DW_Section { - // NOTE(rjf): .dwo => an external DWARF V5 .dwo file - String8 dwo_path; - U64 dwo_id; -}; + String8 name; + String8 data; + B32 is_dwo; +} DW_Section; -//////////////////////////////// -//~ rjf: Abbrev Table +typedef struct DW_Input +{ + DW_Section sec[DW_Section_Count]; + DW_Section sup[DW_Section_Count]; +} DW_Input; -typedef struct DW_AbbrevTableEntry DW_AbbrevTableEntry; -struct DW_AbbrevTableEntry +typedef struct DW_ListUnit +{ + DW_Version version; + U64 address_size; + U64 segment_selector_size; + U64 entry_size; + String8 entries; +} DW_ListUnit; + +typedef struct DW_ListUnitInput +{ + U64 addr_count; + U64 str_offset_count; + U64 rnglist_count; + U64 loclist_count; + Rng1U64Array addr_ranges; + Rng1U64Array str_offset_ranges; + Rng1U64Array rnglist_ranges; + Rng1U64Array loclist_ranges; + DW_ListUnit *addrs; + DW_ListUnit *str_offsets; + DW_ListUnit *rnglists; + DW_ListUnit *loclists; +} DW_ListUnitInput; + +typedef struct DW_AbbrevTableEntry { U64 id; U64 off; -}; +} DW_AbbrevTableEntry; typedef struct DW_AbbrevTable DW_AbbrevTable; struct DW_AbbrevTable @@ -44,62 +55,6 @@ struct DW_AbbrevTable DW_AbbrevTableEntry *entries; }; -//////////////////////////////// -//~ Sections - -typedef struct DW_Section DW_Section; -struct DW_Section -{ - String8 name; - String8 data; - DW_Mode mode; - B32 is_dwo; -}; - -typedef struct DW_SectionArray DW_SectionArray; -struct DW_SectionArray -{ - DW_Section v[DW_Section_Count]; -}; - -//////////////////////////////// -//~ rjf: Basic Line Info - -typedef struct DW_LineFile DW_LineFile; -struct DW_LineFile -{ - String8 file_name; - U64 dir_idx; - U64 modify_time; - U64 md5_digest[2]; - U64 file_size; -}; - -typedef struct DW_LineVMFileNode DW_LineVMFileNode; -struct DW_LineVMFileNode -{ - DW_LineVMFileNode *next; - DW_LineFile file; -}; - -typedef struct DW_LineVMFileList DW_LineVMFileList; -struct DW_LineVMFileList -{ - U64 node_count; - DW_LineVMFileNode *first; - DW_LineVMFileNode *last; -}; - -typedef struct DW_LineVMFileArray DW_LineVMFileArray; -struct DW_LineVMFileArray -{ - U64 count; - DW_LineFile *v; -}; - -//////////////////////////////// -//~ rjf: Abbrevs - typedef enum DW_AbbrevKind { DW_Abbrev_Null, @@ -108,215 +63,169 @@ typedef enum DW_AbbrevKind DW_Abbrev_AttribSequenceEnd, DW_Abbrev_DIEBegin, DW_Abbrev_DIEEnd, -} -DW_AbbrevKind; +} DW_AbbrevKind; typedef U32 DW_AbbrevFlags; -enum{ - DW_AbbrevFlag_HasImplicitConst = (1<<0), - DW_AbbrevFlag_HasChildren = (1<<1), +enum +{ + DW_AbbrevFlag_HasImplicitConst = (1 << 0), + DW_AbbrevFlag_HasChildren = (1 << 1), }; -typedef struct DW_Abbrev DW_Abbrev; -struct DW_Abbrev +typedef struct DW_Abbrev { DW_AbbrevKind kind; - Rng1U64 abbrev_range; U64 sub_kind; U64 id; U64 const_value; DW_AbbrevFlags flags; -}; +} DW_Abbrev; -//////////////////////////////// -//~ rjf: Attribs - -typedef struct DW_AttribValueResolveParams DW_AttribValueResolveParams; -struct DW_AttribValueResolveParams +typedef union DW_Form { - DW_Version version; - DW_Language language; - U64 addr_size; // NOTE(rjf): size in bytes of containing compilation unit's addresses - U64 containing_unit_info_off; // NOTE(rjf): containing compilation unit's offset into the .debug_info section - U64 debug_addrs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_addrs section (DWARF V5 ONLY) - U64 debug_rnglists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_rnglists section (DWARF V5 ONLY) - U64 debug_str_offs_base; // NOTE(rjf): containing compilation unit's offset into the .debug_str_offsets section (DWARF V5 ONLY) - U64 debug_loclists_base; // NOTE(rjf): containing compilation unit's offset into the .debug_loclists section (DWARF V5 ONLY) -}; + String8 addr; + String8 block; + String8 data; + String8 string; + String8 exprloc; + B8 flag; + S64 sdata; + U64 udata; + U64 sec_offset; + U64 ref; + U64 strp_sup; + U64 xval; + U64 addrx; + U64 strx; + U64 rnglistx; + U64 ptr; + U64 implicit_const; +} DW_Form; -typedef struct DW_AttribValue DW_AttribValue; -struct DW_AttribValue -{ - DW_SectionKind section; - U64 v[2]; -}; - -typedef struct DW_Attrib DW_Attrib; -struct DW_Attrib +typedef struct DW_Attrib { U64 info_off; + U64 abbrev_off; U64 abbrev_id; DW_AttribKind attrib_kind; DW_FormKind form_kind; - DW_AttribClass value_class; - DW_AttribValue form_value; -}; + DW_Form form; +} DW_Attrib; -typedef struct DW_AttribArray DW_AttribArray; -struct DW_AttribArray +typedef struct DW_AttribNode { - DW_Attrib *v; - U64 count; -}; + struct DW_AttribNode *next; + DW_Attrib v; +} DW_AttribNode; -typedef struct DW_AttribNode DW_AttribNode; -struct DW_AttribNode -{ - DW_AttribNode *next; - DW_Attrib attrib; -}; - -typedef struct DW_AttribList DW_AttribList; -struct DW_AttribList +typedef struct DW_AttribList { DW_AttribNode *first; DW_AttribNode *last; U64 count; -}; +} DW_AttribList; -typedef struct DW_AttribListParseResult DW_AttribListParseResult; -struct DW_AttribListParseResult +typedef struct DW_Tag { - DW_AttribList attribs; - U64 max_info_off; - U64 max_abbrev_off; -}; - -//////////////////////////////// -//~ rjf: Compilation Units + Accelerators - -typedef struct DW_CompRoot DW_CompRoot; -struct DW_CompRoot -{ - // NOTE(rjf): Header Data - U64 size; - DW_CompUnitKind kind; - DW_Version version; - U64 address_size; - U64 abbrev_off; - U64 info_off; - Rng1U64 tags_info_range; - DW_AbbrevTable abbrev_table; - - // NOTE(rjf): [parsed from DWARF attributes] Offsets For More Info (DWARF V5 ONLY) - U64 rnglist_base; // NOTE(rjf): Offset into the .debug_rnglists section where this comp unit's data is. - U64 loclist_base; // NOTE(rjf): Offset into the .debug_loclists section where this comp unit's data is. - U64 addrs_base; // NOTE(rjf): Offset into the .debug_addr section where this comp unit's data is. - U64 stroffs_base; // NOTE(rjf): Offset into the .debug_str_offsets section where this comp unit's data is. - - // NOTE(rjf): [parsed from DWARF attributes] General Info - String8 name; - String8 producer; - String8 compile_dir; - String8 external_dwo_name; - U64 dwo_id; - DW_Language language; - U64 name_case; - B32 use_utf8; - U64 line_off; - U64 low_pc; - U64 high_pc; - DW_AttribValue ranges_attrib_value; - U64 base_addr; -}; - -//////////////////////////////// -//~ rjf: Tags - -typedef struct DW_Tag DW_Tag; -struct DW_Tag -{ - DW_Tag *next_sibling; - DW_Tag *first_child; - DW_Tag *last_child; - DW_Tag *parent; - Rng1U64 info_range; - Rng1U64 abbrev_range; B32 has_children; U64 abbrev_id; DW_TagKind kind; - U64 attribs_info_off; - U64 attribs_abbrev_off; DW_AttribList attribs; -}; + U64 info_off; +} DW_Tag; -typedef U32 DW_TagStubFlags; -enum +typedef struct DW_TagNode { - DW_TagStubFlag_HasObjectPointerArg = (1<<0), - DW_TagStubFlag_HasLocation = (1<<1), - DW_TagStubFlag_HasExternal = (1<<2), - DW_TagStubFlag_HasSpecification = (1<<3), -}; + DW_Tag tag; + struct DW_TagNode *sibling; + struct DW_TagNode *first_child; + struct DW_TagNode *last_child; +} DW_TagNode; -typedef struct DW_TagStub DW_TagStub; -struct DW_TagStub +typedef struct DW_Loc { - U64 info_off; - DW_TagKind kind; - DW_TagStubFlags flags; - U64 children_info_off; - U64 attribs_info_off; - U64 attribs_abbrev_off; - - // NOTE(rjf): DW_Attrib_Specification is tacked onto definitions that - // are filling out more info about a "prototype". That attribute is a reference - // that points back at the declaration tag. The declaration tag has the - // DW_Attrib_Declaration attribute, which is sort of like the reverse - // of that, except there's no reference. So what we're doing here is just storing - // a reference on both, that point back to each other, so it's always easy to - // get from decl => spec, or from spec => decl. - //SYMS_SymbolID ref; - - // NOTE(rjf): DW_Attrib_AbstractOrigin is tacked onto some definitions - // that are used to specify information more specific to inlining, while wanting - // to refer to an "abstract" function DIE, that is not specific to any inline - // sites. The DWARF generator will not duplicate information across these, so - // we will occasionally need to look at an abstract origin to get abstract - // information, like name/linkage-name/etc. - //SYMS_SymbolID abstract_origin; - - U64 _unused_; -}; + Rng1U64 range; + String8 expr; +} DW_Loc; -typedef struct DW_TagStubNode DW_TagStubNode; -struct DW_TagStubNode +typedef struct DW_LocNode { - DW_TagStubNode *next; - DW_TagStub stub; -}; + DW_Loc v; + struct DW_LocNode *next; +} DW_LocNode; -typedef struct DW_TagStubList DW_TagStubList; -struct DW_TagStubList +typedef struct DW_LocList { - DW_TagStubNode *first; - DW_TagStubNode *last; - U64 count; -}; + U64 count; + DW_LocNode *first; + DW_LocNode *last; +} DW_LocList; -//////////////////////////////// -//~ rjf: Line Info VM Types - -typedef struct DW_LineVMHeader DW_LineVMHeader; -struct DW_LineVMHeader +typedef struct DW_CompUnit { - U64 unit_length; - U64 unit_opl; + B32 relaxed; + DW_Ext ext; + DW_CompUnitKind kind; + DW_Version version; + DW_Format format; + U64 address_size; + U64 abbrev_off; + Rng1U64 info_range; + U64 first_tag_info_off; + DW_AbbrevTable abbrev_table; + String8 abbrev_data; + DW_ListUnit *addr_lu; + DW_ListUnit *str_offsets_lu; + DW_ListUnit *rnglists_lu; + DW_ListUnit *loclists_lu; + U64 low_pc; + U64 dwo_id; + DW_Tag tag; + HashTable *tag_ht; +} DW_CompUnit; + +typedef struct DW_TagTree +{ + DW_TagNode *root; + U64 tag_count; +} DW_TagTree; + +typedef struct DW_LineFile +{ + String8 file_name; + U64 dir_idx; + U64 modify_time; + U64 file_size; + U128 md5_digest; + String8 source; +} DW_LineFile; + +typedef struct DW_LineVMFileNode +{ + struct DW_LineVMFileNode *next; + DW_LineFile file; +} DW_LineVMFileNode; + +typedef struct DW_LineVMFileList +{ + U64 node_count; + DW_LineVMFileNode *first; + DW_LineVMFileNode *last; +} DW_LineVMFileList; + +typedef struct DW_LineVMFileArray +{ + U64 count; + DW_LineFile *v; +} DW_LineVMFileArray; + +typedef struct DW_LineVMHeader +{ + Rng1U64 unit_range; DW_Version version; U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str. U8 segment_selector_size; U64 header_length; - U64 program_off; U8 min_inst_len; U8 max_ops_for_inst; U8 default_is_stmt; @@ -325,12 +234,11 @@ struct DW_LineVMHeader U8 opcode_base; U64 num_opcode_lens; U8 *opcode_lens; - String8Array dir_table; + DW_LineVMFileArray dir_table; DW_LineVMFileArray file_table; -}; +} DW_LineVMHeader; -typedef struct DW_LineVMState DW_LineVMState; -struct DW_LineVMState +typedef struct DW_LineVMState { U64 address; // Address of a machine instruction. U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction. @@ -351,144 +259,195 @@ struct DW_LineVMState // prepare stack for a function. B32 prologue_end; - B32 epilogue_begin; // NOTE(nick): Indicates that "address" points to section where function exits and unwinds stack. - U64 isa; // NOTE(nick): Instruction set that is used. - U64 discriminator; // NOTE(nick): Arbitrary id that indicates to which block these instructions belong. - B32 end_sequence; // NOTE(nick): Indicates that "address" points to the first instruction in the instruction block that follows. - - // NOTE(rjf): it looks like LTO might sometimes zero out high PC and low PCs, causing a - // swath of line info to map to a range starting at 0. This causes overlapping ranges - // which we do not want to report. So this B32 will turn on emission. - B32 busted_seq; -}; + B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack. + U64 isa; // Instruction set that is used. + U64 discriminator; // Arbitrary id that indicates to which block these instructions belong. + B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows. +} DW_LineVMState; -typedef struct DW_Line DW_Line; -struct DW_Line +typedef struct DW_Line { U64 file_index; U32 line; U32 column; - U64 voff; -}; + U64 address; +} DW_Line; -typedef struct DW_LineNode DW_LineNode; -struct DW_LineNode +typedef struct DW_LineNode { - DW_LineNode *next; - DW_Line v; -}; + struct DW_LineNode *next; + DW_Line v; +} DW_LineNode; -typedef struct DW_LineSeqNode DW_LineSeqNode; -struct DW_LineSeqNode +typedef struct DW_LineSeqNode { - DW_LineSeqNode *next; - U64 count; - DW_LineNode *first; - DW_LineNode *last; -}; + struct DW_LineSeqNode *next; + U64 count; + DW_LineNode *first; + DW_LineNode *last; +} DW_LineSeqNode; -typedef struct DW_LineTableParseResult DW_LineTableParseResult; -struct DW_LineTableParseResult +typedef struct DW_LineTableParseResult { + DW_LineVMHeader vm_header; U64 seq_count; DW_LineSeqNode *first_seq; DW_LineSeqNode *last_seq; -}; +} DW_LineTableParseResult; //////////////////////////////// -//~ rjf: .debug_pubnames and .debug_pubtypes +// .debug_pubnames and .debug_pubtypes -typedef struct DW_PubStringsBucket DW_PubStringsBucket; -struct DW_PubStringsBucket +typedef struct DW_PubStringsBucket { - DW_PubStringsBucket *next; - String8 string; - U64 info_off; - U64 cu_info_off; -}; + struct DW_PubStringsBucket *next; + String8 string; + U64 info_off; + U64 cu_info_off; +} DW_PubStringsBucket; -typedef struct DW_PubStringsTable DW_PubStringsTable; -struct DW_PubStringsTable +typedef struct DW_PubStringsTable { - U64 size; + U64 size; DW_PubStringsBucket **buckets; -}; +} DW_PubStringsTable; -//////////////////////////////// -//~ rjf: Basic Helpers +typedef struct DW_Reference +{ + DW_CompUnit *cu; + U64 info_off; +} DW_Reference; + +// hasher internal U64 dw_hash_from_string(String8 string); -//////////////////////////////// -//~ Specific Based Range Helpers +// deserial helpers -#define dw_based_range_read_struct(base, range, offset, out) dw_based_range_read(base, range, offset, sizeof(*out), out) +internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out); +internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out); +internal U64 str8_deserial_read_uleb128 (String8 string, U64 off, U64 *value_out); +internal U64 str8_deserial_read_sleb128 (String8 string, U64 off, S64 *value_out); +internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out); +internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out); -internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 offset, U64 size, void *out); -internal String8 dw_based_range_read_string(void *base, Rng1U64 range, U64 offset); -internal void* dw_based_range_ptr(void *base, Rng1U64 range, U64 offset); -internal void* dw_based_range_ptr_size(void *base, Rng1U64 range, U64 offset, U64 size); -internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 offset, U64 *out_value); -internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 offset, S64 *out_value); -internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 offset, U64 *out_value); -internal U64 dw_based_range_read_abbrev_tag(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_abbrev_attrib_info(void *base, Rng1U64 range, U64 offset, DW_Abbrev *out_abbrev); -internal U64 dw_based_range_read_attrib_form_value(void *base, Rng1U64 range, U64 offset, DW_Mode mode, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_AttribValue *form_value_out); +internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data); -internal DW_Mode dw_mode_from_sec(DW_SectionArray *sections, DW_SectionKind kind); -internal B32 dw_sec_is_present(DW_SectionArray *sections, DW_SectionKind kind); -internal void* dw_base_from_sec(DW_SectionArray *sections, DW_SectionKind kind); -internal Rng1U64 dw_range_from_sec(DW_SectionArray *sections, DW_SectionKind kind); +// list units -//////////////////////////////// -//~ rjf: Abbrev Table +internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out); +internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out); +internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out); -internal DW_AbbrevTable dw_make_abbrev_table(Arena *arena, DW_SectionArray *sections, U64 start_abbrev_off); +internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Input *input); + +internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index); +internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index); + +// abbrev table + +internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev); +internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev); +internal DW_AbbrevTable dw_make_abbrev_table(Arena *arena, String8 abbrev_data, U64 start_abbrev_off); internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id); -//////////////////////////////// -//~ rjf: Miscellaneous DWARF Section Parsing +// form and tag -//- rjf: .debug_ranges (DWARF V4) -internal Rng1U64List dw_v4_range_list_from_range_offset(Arena *arena, DW_SectionArray *sections, U64 addr_size, U64 comp_unit_base_addr, U64 range_off); +internal U64 dw_read_form(String8 data, U64 off, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, U64 implicit_const, DW_Form *form_out); +internal U64 dw_read_tag (Arena *arena, String8 tag_data, U64 tag_off, U64 tag_base, DW_AbbrevTable abbrev_table, String8 abbrev_data, DW_Version version, DW_Format unit_format, U64 address_size, DW_Tag *tag_out); +internal U64 dw_read_tag_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out); -//- rjf: .debug_pubtypes + .debug_pubnames (DWARF V4) -internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_SectionArray *sections, DW_SectionKind section_kind); +// attrib interp -//- rjf: .debug_str_offsets (DWARF V5) -internal U64 dw_v5_offset_from_offs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index); +internal U64 dw_interp_sec_offset(DW_FormKind form_kind, DW_Form form); +internal String8 dw_interp_exprloc (DW_FormKind form_kind, DW_Form form); +internal U128 dw_interp_const_u128(DW_FormKind form_kind, DW_Form form); +internal U64 dw_interp_const_u64 (DW_FormKind form_kind, DW_Form form); +internal U32 dw_interp_const_u32 (DW_FormKind form_kind, DW_Form form); +internal S64 dw_interp_const_s64 (DW_FormKind form_kind, DW_Form form); +internal S32 dw_interp_const_s32 (DW_FormKind form_kind, DW_Form form); +internal B32 dw_interp_flag (DW_FormKind form_kind, DW_Form form); +internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_FormKind form_kind, DW_Form form); +internal String8 dw_interp_block (DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); +internal String8 dw_interp_string (DW_Input *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_FormKind form_kind, DW_Form form); +internal String8 dw_interp_line_ptr (DW_Input *input, DW_FormKind form_kind, DW_Form form); +internal DW_LineFile * dw_interp_file (DW_LineVMHeader *line_vm, DW_FormKind form_kind, DW_Form form); +internal DW_Reference dw_interp_ref (DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); +internal DW_LocList dw_interp_loclist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); +internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_FormKind form_kind, DW_Form form); -//- rjf: .debug_addr (DWARF V5) -internal U64 dw_v5_addr_from_addrs_section_base_index(DW_SectionArray *sections, DW_SectionKind section, U64 base, U64 index); +internal String8 dw_exprloc_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U128 dw_const_u128_from_attrib_ptr(DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U64 dw_const_u64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U32 dw_const_u32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal S64 dw_const_s64_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal S32 dw_const_s32_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal B32 dw_flag_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal U64 dw_address_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_block_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_string_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal String8 dw_line_ptr_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal DW_LineFile * dw_file_from_attrib_ptr (DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Attrib *attrib); +internal DW_Reference dw_ref_from_attrib_ptr (DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal DW_LocList dw_loclist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); +internal Rng1U64List dw_rnglist_from_attrib_ptr (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Attrib *attrib); -//- rjf: .debug_rnglists parsing (DWARF V5) -internal U64 dw_v5_sec_offset_from_rnglist_or_loclist_section_base_index(DW_SectionArray *sections, DW_SectionKind section_kind, U64 base, U64 index); -internal Rng1U64List dw_v5_range_list_from_rnglist_offset(Arena *arena, DW_SectionArray *sections, DW_SectionKind section, U64 addr_size, U64 addr_section_base, U64 offset); +internal String8 dw_exprloc_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U128 dw_const_u128_from_attrib(DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U64 dw_const_u64_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U32 dw_const_u32_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal B32 dw_flag_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal U64 dw_address_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_block_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_string_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal String8 dw_line_ptr_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal DW_LineFile * dw_file_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_LineVMHeader *line_vm, DW_Tag tag, DW_AttribKind kind); +internal DW_Reference dw_ref_from_attrib (DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); +internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind); -//////////////////////////////// -//~ rjf: Attrib Value Parsing +// compile unit -internal DW_AttribValueResolveParams dw_attrib_value_resolve_params_from_comp_root(DW_CompRoot *root); -internal DW_AttribValue dw_attrib_value_from_form_value(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_FormKind form_kind, DW_AttribClass value_class, DW_AttribValue form_value); -internal String8 dw_string_from_attrib_value(DW_SectionArray *sections, DW_AttribValue value); -internal Rng1U64List dw_range_list_from_high_low_pc_and_ranges_attrib_value(Arena *arena, DW_SectionArray *sections, U64 address_size, U64 comp_unit_base_addr, U64 addr_section_base, U64 low_pc, U64 high_pc, DW_AttribValue ranges_value); +internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Input *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed); +internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Input *input, DW_CompUnit *cu); +internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree); +internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off); -//////////////////////////////// -//~ rjf: Tag Parsing +// line info -internal DW_AttribListParseResult dw_parse_attrib_list_from_info_abbrev_offsets(Arena *arena, DW_SectionArray *sections, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_off, U64 abbrev_off, B32 relaxed); -internal DW_Tag* dw_tag_from_info_offset(Arena *arena, DW_SectionArray *sections, DW_AbbrevTable abbrev_table, DW_Version ver, DW_Ext ext, DW_Language lang, U64 address_size, U64 info_offset, B32 relaxed); -internal DW_TagStub dw_stub_from_tag(DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, DW_Tag *tag); +internal U64 dw_read_line_file(String8 line_data, + U64 line_off, + DW_Input *input, + DW_Version unit_version, + DW_Format unit_format, + DW_Ext ext, + U64 address_size, + DW_ListUnit *str_offsets, + U64 enc_count, + U64 *enc_arr, + DW_LineFile *line_file_out); +internal U64 dw_read_line_vm_header(Arena *arena, + String8 line_data, + U64 line_off, + DW_Input *input, + String8 cu_dir, + String8 cu_name, + U8 cu_address_size, + DW_ListUnit *cu_str_offsets, + DW_LineVMHeader *header_out); -//- rjf: line info -internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt); -internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst); +internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt); +internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst); +internal DW_LineSeqNode * dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); +internal DW_LineNode * dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); +internal String8 dw_path_from_file(Arena *arena, DW_LineVMHeader *vm, DW_LineFile *file); +internal String8 dw_path_from_file_idx(Arena *arena, DW_LineVMHeader *vm, U64 file_idx); -internal DW_LineSeqNode* dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl); -internal DW_LineNode* dw_push_line(Arena *arena, DW_LineTableParseResult *tbl, DW_LineVMState *vm_state, B32 start_of_sequence); -internal DW_LineTableParseResult dw_parsed_line_table_from_comp_root(Arena *arena, DW_SectionArray *sections, DW_CompRoot *root); -internal U64 dw_read_line_file(void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, U8 address_size, U64 format_count, Rng1U64 *formats, DW_LineFile *line_file_out); -internal U64 dw_read_line_vm_header(Arena *arena, void *line_base, Rng1U64 line_rng, U64 line_off, DW_Mode mode, DW_SectionArray *sections, DW_AttribValueResolveParams resolve_params, String8 compile_dir, String8 unit_name, DW_LineVMHeader *header_out); +internal DW_LineTableParseResult dw_parsed_line_table_from_data(Arena *arena, String8 unit_data, DW_Input *input, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets); + +// helper for .debug_pubtypes and .debug_pubnames + +internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_SectionKind section_kind); #endif // DWARF_PARSE_H - diff --git a/src/dwarf/dwarf_unwind.c b/src/dwarf/dwarf_unwind.c index 2731dd9c..81cc93de 100644 --- a/src/dwarf/dwarf_unwind.c +++ b/src/dwarf/dwarf_unwind.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal U64 dw_based_range_read(void *base, Rng1U64 range, U64 off, U64 size, void *out) { return 0; } +internal U64 dw_based_range_read_uleb128(void *base, Rng1U64 range, U64 off, U64 *out) { return 0; } +internal U64 dw_based_range_read_sleb128(void *base, Rng1U64 range, U64 off, S64 *out) { return 0; } +internal U64 dw_based_range_read_length(void *base, Rng1U64 range, U64 off, U64 *out) { return 0; } + //////////////////////////////// // x64 Unwind Function @@ -148,7 +153,7 @@ dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, // is this a roll-over CFA? B32 is_roll_over_cfa = 0; - if (reg_idx == DW_Reg_x64_Rsp) { + if (reg_idx == DW_RegX64_Rsp) { DW_CFIRegisterRule rule = row->cells[reg_idx].rule; if (rule == DW_CFIRegisterRule_Undefined || rule == DW_CFIRegisterRule_SameValue) { is_roll_over_cfa = 1; @@ -410,6 +415,8 @@ dw_unwind_parse_pointer_x64(void *frame_base, Rng1U64 frame_range, DW_EhPtrCtx * internal void dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out) { + NotImplemented; +#if 0 MemoryZeroStruct(cie_out); // get version @@ -521,6 +528,7 @@ dw_unwind_parse_cie_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, U64 off cie_out->cfi_range.min = cfi_off; cie_out->cfi_range.max = cfi_off + cfi_size; } +#endif } internal void diff --git a/src/elf/elf.c b/src/elf/elf.c new file mode 100644 index 00000000..ac3473cb --- /dev/null +++ b/src/elf/elf.c @@ -0,0 +1,143 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: 32 => 64 bit conversions + +internal ELF_Hdr64 +elf_hdr64_from_hdr32(ELF_Hdr32 h32) +{ + ELF_Hdr64 h64 = {0}; + MemoryCopy(h64.e_ident, h32.e_ident, sizeof(h64.e_ident)); + h64.e_type = h32.e_type; + h64.e_machine = h32.e_machine; + h64.e_version = h32.e_version; + h64.e_entry = (U64)h32.e_entry; + h64.e_phoff = (U64)h32.e_phoff; + h64.e_shoff = (U64)h32.e_shoff; + h64.e_flags = h32.e_flags; + h64.e_ehsize = h32.e_ehsize; + h64.e_phentsize = h32.e_phentsize; + h64.e_phnum = h32.e_phnum; + h64.e_shentsize = h32.e_shentsize; + h64.e_shnum = h32.e_shnum; + h64.e_shstrndx = h32.e_shstrndx; + return h64; +} + +internal ELF_Shdr64 +elf_shdr64_from_shdr32(ELF_Shdr32 h32) +{ + ELF_Shdr64 h64 = {0}; + h64.sh_name = h32.sh_name; + h64.sh_type = h32.sh_type; + h64.sh_flags = (U64)h32.sh_flags; + h64.sh_addr = (U64)h32.sh_addr; + h64.sh_offset = (U64)h32.sh_offset; + h64.sh_size = (U64)h32.sh_size; + h64.sh_link = h32.sh_link; + h64.sh_info = h32.sh_info; + h64.sh_addralign = (U64)h32.sh_addralign; + h64.sh_entsize = (U64)h32.sh_entsize; + return h64; +} + +internal ELF_Phdr64 +elf_phdr64_from_phdr32(ELF_Phdr32 h32) +{ + ELF_Phdr64 h64 = {0}; + h64.p_type = h32.p_type; + h64.p_flags = h32.p_flags; + h64.p_offset = (U64)h32.p_offset; + h64.p_vaddr = (U64)h32.p_vaddr; + h64.p_paddr = (U64)h32.p_paddr; + h64.p_filesz = (U64)h32.p_filesz; + h64.p_memsz = (U64)h32.p_memsz; + h64.p_align = (U64)h32.p_align; + return h64; +} + +internal ELF_Dyn64 +elf_dyn64_from_dyn32(ELF_Dyn32 h32) +{ + ELF_Dyn64 h64 = {0}; + h64.tag = (U64)h32.tag; + h64.val = (U64)h32.val; + return h64; +} + +internal ELF_Sym64 +elf_sym64_from_sym32(ELF_Sym32 sym32) +{ + ELF_Sym64 sym64 = {0}; + sym64.st_name = sym32.st_name; + sym64.st_value = sym32.st_value; + sym64.st_size = sym32.st_size; + sym64.st_info = sym32.st_info; + sym64.st_other = sym32.st_other; + sym64.st_shndx = sym32.st_shndx; + return sym64; +} + +internal ELF_Rel64 +elf_rel64_from_rel32(ELF_Rel32 rel32) +{ + U32 sym = ELF32_R_SYM(rel32.r_info); + U32 type = ELF32_R_TYPE(rel32.r_info); + ELF_Rel64 rel64 = {0}; + rel64.r_info = ELF64_R_INFO(sym, type); + rel64.r_offset = rel32.r_offset; + return rel64; +} + +internal ELF_Rela64 +elf_rela64_from_rela32(ELF_Rela32 rela32) +{ + U32 sym = ELF32_R_SYM(rela32.r_info); + U32 type = ELF32_R_TYPE(rela32.r_info); + ELF_Rela64 rela64 = {0}; + rela64.r_offset = rela32.r_info; + rela64.r_info = ELF64_R_INFO(sym, type); + rela64.r_addend = rela32.r_addend; + return rela64; +} + +internal ELF_Chdr64 +elf_chdr64_from_chdr32(ELF_Chdr32 chdr32) +{ + ELF_Chdr64 chdr64 = {0}; + chdr64.ch_type = chdr32.ch_type; + chdr64.ch_size = chdr32.ch_size; + chdr64.ch_addr_align = chdr32.ch_addr_align; + return chdr64; +} + +//////////////////////////////// + +internal String8 +elf_string_from_class(Arena *arena, ELF_Class v) +{ + switch (v) { + case ELF_Class_None: return str8_lit("None"); + case ELF_Class_32: return str8_lit("32Bit"); + case ELF_Class_64: return str8_lit("64Bit"); + } + return push_str8f(arena, "%#x", v); +} + +//////////////////////////////// + +internal Arch +arch_from_elf_machine(ELF_MachineKind e_machine) +{ + Arch arch = Arch_Null; + switch (e_machine) { + case ELF_MachineKind_None: arch = Arch_Null; break; + case ELF_MachineKind_AARCH64: arch = Arch_arm32; break; + case ELF_MachineKind_ARM: arch = Arch_arm32; break; + case ELF_MachineKind_386: arch = Arch_x86; break; + case ELF_MachineKind_X86_64: arch = Arch_x64; break; + default: NotImplemented; break; + } + return arch; +} diff --git a/src/elf/elf.h b/src/elf/elf.h new file mode 100644 index 00000000..791b8351 --- /dev/null +++ b/src/elf/elf.h @@ -0,0 +1,996 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ELF_H +#define ELF_H + +typedef U8 ELF_Class; +enum +{ + ELF_Class_None = 0, + ELF_Class_32 = 1, + ELF_Class_64 = 2, + ELF_Class_Count = 3 +}; + +typedef U8 ELF_OsAbi; +enum +{ + ELF_OsAbi_None, + ELF_OsAbi_SYSV, + ELF_OsAbi_HPUX, + ELF_OsAbi_NETBSD, + ELF_OsAbi_GNU, + ELF_OsAbi_LINUX, + ELF_OsAbi_SOLARIS, + ELF_OsAbi_IRIX, + ELF_OsAbi_FREEBSD, + ELF_OsAbi_TRU64, + ELF_OsAbi_ARM = 97, + ELF_OsAbi_STANDALONE = 255, +}; + +typedef U8 ELF_Version; +enum +{ + ELF_Version_None, + ELF_Version_Current, +}; + +typedef U16 ELF_MachineKind; +enum +{ + ELF_MachineKind_None = 0, + ELF_MachineKind_M32 = 1, + ELF_MachineKind_SPARC = 2, + ELF_MachineKind_386 = 3, + ELF_MachineKind_68K = 4, + ELF_MachineKind_88K = 5, + ELF_MachineKind_IAMCU = 6, + ELF_MachineKind_860 = 7, + ELF_MachineKind_MIPS = 8, + ELF_MachineKind_S370 = 9, + ELF_MachineKind_MIPS_RS3_LE = 10, + // 11-14 reserved + ELF_MachineKind_PARISC = 15, + // 16 reserved + ELF_MachineKind_VPP500 = 17, + ELF_MachineKind_SPARC32PLUS = 18, + // nick: Sun's "v8plus" + ELF_MachineKind_INTEL960 = 19, + ELF_MachineKind_PPC = 20, + ELF_MachineKind_PPC64 = 21, + ELF_MachineKind_S390 = 22, + ELF_MachineKind_SPU = 23, + // 24-35 reserved + ELF_MachineKind_V800 = 36, + ELF_MachineKind_FR20 = 37, + ELF_MachineKind_RH32 = 38, + ELF_MachineKind_MCORE = 39, + ELF_MachineKind_ARM = 40, + ELF_MachineKind_SH = 42, + ELF_MachineKind_ALPHA = 41, + ELF_MachineKind_SPARCV9 = 43, + ELF_MachineKind_TRICORE = 44, + ELF_MachineKind_ARC = 45, + ELF_MachineKind_H8_300 = 46, + ELF_MachineKind_H8_300H = 47, + ELF_MachineKind_H8S = 48, + ELF_MachineKind_H8_500 = 49, + ELF_MachineKind_IA_64 = 50, + ELF_MachineKind_MIPS_X = 51, + ELF_MachineKind_COLDFILE = 52, + ELF_MachineKind_68HC12 = 53, + ELF_MachineKind_MMA = 54, + ELF_MachineKind_PCP = 55, + ELF_MachineKind_NCPU = 56, + ELF_MachineKind_NDR1 = 57, + ELF_MachineKind_STARCORE = 58, + ELF_MachineKind_ME16 = 59, + ELF_MachineKind_ST100 = 60, + ELF_MachineKind_TINYJ = 61, + ELF_MachineKind_X86_64 = 62, + ELF_MachineKind_AARCH64 = 183, + ELF_MachineKind_TI_C6000 = 140, + ELF_MachineKind_L1OM = 180, + ELF_MachineKind_K1OM = 181, + ELF_MachineKind_RISCV = 243, + ELF_MachineKind_S390_OLD = 0xA390, +}; + +typedef U8 ELF_Data; +enum +{ + ELF_Data_None = 0, + ELF_Data_2LSB = 1, + ELF_Data_2MSB = 2, +}; + +typedef U32 ELF_PType; +enum +{ + ELF_PType_Null = 0, + ELF_PType_Load = 1, + ELF_PType_Dynamic = 2, + ELF_PType_Interp = 3, + ELF_PType_Note = 4, + ELF_PType_ShLib = 5, + ELF_PType_PHdr = 6, + ELF_PType_Tls = 7, + ELF_PType_LoOs = 0x60000000, + ELF_PType_HiOs = 0x6fffffff, + + ELF_PType_LowProc = 0x70000000, + ELF_PType_HighProc = 0x7fffffff, + + // specific to Sun + ELF_PType_LowSunW = 0x6ffffffa, + ELF_PType_SunWBSS = 0x6ffffffb, + ELF_PType_GnuEHFrame = 0x6474E550, + + ELF_PType_GnuStack = ELF_PType_LoOs + 0x474e550, // frame unwind information + ELF_PType_GnuRelro = ELF_PType_LoOs + 0x474e551, // stack flags + ELF_PType_GnuProperty = ELF_PType_LoOs + 0x474e552, // read-only after relocations + ELF_PType_SunEHFrame = ELF_PType_GnuEHFrame, +}; + +typedef U32 ELF_PFlag; +enum +{ + ELF_PFlag_Exec = (1 << 0), + ELF_PFlag_Write = (1 << 1), + ELF_PFlag_Read = (1 << 2), +}; + +typedef U32 ELF_SectionCode; +enum +{ + ELF_SectionCode_Null = 0, + ELF_SectionCode_ProgBits = 1, + ELF_SectionCode_Symtab = 2, + ELF_SectionCode_Strtab = 3, + ELF_SectionCode_Rela = 4, + ELF_SectionCode_Hash = 5, + ELF_SectionCode_Dynamic = 6, + ELF_SectionCode_Note = 7, + ELF_SectionCode_NoBits = 8, + ELF_SectionCode_Rel = 9, + ELF_SectionCode_Shlib = 10, + ELF_SectionCode_Dynsym = 11, + ELF_SectionCode_InitArray = 14, + ELF_SectionCode_FiniArray = 15, // Array of ptrs to init functions + ELF_SectionCode_PreinitArray = 16, // Array of ptrs to finish functions + ELF_SectionCode_Group = 17, // Array of ptrs to pre-init funcs + ELF_SectionCode_SymtabShndx = 18, // Section contains a section group + ELF_SectionCode_GNU_IncrementalInputs = 0x6fff4700, // Indices for SHN_XINDEX entries + ELF_SectionCode_GNU_Attributes = 0x6ffffff5, // Incremental build data + ELF_SectionCode_GNU_Hash = 0x6ffffff6, // Object attributes + ELF_SectionCode_GNU_LibList = 0x6ffffff7, // GNU style symbol hash table + ELF_SectionCode_SUNW_verdef = 0x6ffffffd, + ELF_SectionCode_SUNW_verneed = 0x6ffffffe, // Versions defined by file + ELF_SectionCode_SUNW_versym = 0x6fffffff, // Versions needed by file + + // Symbol versions + ELF_SectionCode_GNU_verdef = ELF_SectionCode_SUNW_verdef, + ELF_SectionCode_GNU_verneed = ELF_SectionCode_SUNW_verneed, + ELF_SectionCode_GNU_versym = ELF_SectionCode_SUNW_versym, + ELF_SectionCode_Proc, + ELF_SectionCode_User, +}; + +typedef U32 ELF_SectionIndex; +enum +{ + + ELF_SectionIndex_Undef = 0, // Symbol with section index is undefined and must be resolved by the link editor + ELF_SectionIndex_Abs = 0xfff1, // Symbol has absolute value and wont change after relocations + ELF_SectionIndex_Common = 0xfff2, // This symbol indicates to linker to allocate the storage at address multiple of st_value + + ELF_SectionIndex_LoReserve = 0xff00, + ELF_SectionIndex_HiReserve = 0xffff, + + // Processor specific + ELF_SectionIndex_LoProc = ELF_SectionIndex_LoReserve, + ELF_SectionIndex_HiProc = 0xff1f, + + // Reserved for OS + ELF_SectionIndex_LoOs = 0xff20, + ELF_SectionIndex_HiOs = 0xff3f, + + ELF_SectionIndex_IA64_ASNI_Common = ELF_SectionIndex_LoProc, + ELF_SectionIndex_X8664_LCommon = 0xff02, + ELF_SectionIndex_MIPS_SCommon = 0xff03, + + ELF_SectionIndex_TIC6X_Common = ELF_SectionIndex_LoReserve, + ELF_SectionIndex_MIPS_SUndefined = 0xff04, +}; + +typedef U32 ELF_SectionFlag; +enum +{ + ELF_Shf_Write = (1 << 0), + ELF_Shf_Alloc = (1 << 1), + ELF_Shf_ExecInstr = (1 << 2), + ELF_Shf_Merge = (1 << 4), + ELF_Shf_Strings = (1 << 5), + ELF_Shf_InfoLink = (1 << 6), + ELF_Shf_LinkOrder = (1 << 7), + ELF_Shf_OsNonConforming = (1 << 8), + ELF_Shf_Group = (1 << 9), + ELF_Shf_Tls = (1 << 10), + ELF_Shf_Compressed = (1 << 11), + ELF_Shf_MaskOs_Shift = 16, ELF_Shf_MaskOs_Mask = 0xff, + ELF_Shf_AMD64Large = (1 << 28), + ELF_Shf_Ordered = (1 << 30), + ELF_Shf_Exclude = (1 << 31), + ELF_Shf_MaskProc_Shift = 28, ELF_Shf_MaskProc_Mask = 0xf, +}; + +#define ELF_SectionFlag_Extract_MaskOs(f) (U8)(((f) >> ELF_SectionFlag_MaskOs_Shift) & ELF_SectionFlag_MaskOs_Mask) +#define ELF_SectionFlag_Extract_MaskProc(f) (U8)(((f) >> ELF_SectionFlag_MaskProc_shift) & ELF_SectionFlag_MaskProc_Mask) +typedef U32 ELF_AuxType; +enum +{ + ELF_AuxType_Null = 0, + ELF_AuxType_Phdr = 3, // program headers + ELF_AuxType_Phent = 4, // size of a program header + ELF_AuxType_Phnum = 5, // number of program headers + ELF_AuxType_Pagesz = 6, // system page size + ELF_AuxType_Base = 7, // interpreter base address + ELF_AuxType_Flags = 8, + ELF_AuxType_Entry = 9, // program entry point + ELF_AuxType_Uid = 11, + ELF_AuxType_Euid = 12, + ELF_AuxType_Gid = 13, + ELF_AuxType_Egid = 14, + ELF_AuxType_Platform = 15, + ELF_AuxType_Hwcap = 16, + ELF_AuxType_Clktck = 17, + ELF_AuxType_DCacheBSize = 19, + ELF_AuxType_ICacheBSize = 20, + ELF_AuxType_UCacheBSize = 21, + ELF_AuxType_IgnorePPC = 22, + ELF_AuxType_Secure = 23, + ELF_AuxType_BasePlatform = 24, + ELF_AuxType_Random = 25, + ELF_AuxType_Hwcap2 = 26, // addres to 16 random bytes + ELF_AuxType_ExecFn = 31, + ELF_AuxType_SysInfo = 32, // file name of executable + ELF_AuxType_SysInfoEhdr = 33, + ELF_AuxType_L1I_CacheSize = 40, + ELF_AuxType_L1I_CacheGeometry = 41, + ELF_AuxType_L1D_CacheSize = 42, + ELF_AuxType_L1D_CacheGeometry = 43, + ELF_AuxType_L2_CacheSize = 44, + ELF_AuxType_L2_CacheGeometry = 45, + ELF_AuxType_L3_CacheSize = 46, + ELF_AuxType_L3_CacheGeometry = 47, +}; + +typedef U32 ELF_DynTag; +enum +{ + ELF_DynTag_Null = 0, + + ELF_DynTag_Needed = 1, + ELF_DynTag_PltRelsz = 2, + ELF_DynTag_PltGot = 3, + ELF_DynTag_Hash = 4, + ELF_DynTag_Strtab = 5, + ELF_DynTag_Symtab = 6, + ELF_DynTag_Rela = 7, + ELF_DynTag_Relasz = 8, + ELF_DynTag_Relaent = 9, + ELF_DynTag_Strsz = 10, + ELF_DynTag_Syment = 11, + ELF_DynTag_Init = 12, + ELF_DynTag_Fini = 13, + ELF_DynTag_SoName = 14, + ELF_DynTag_RPath = 15, + ELF_DynTag_Symbolic = 16, + ELF_DynTag_Rel = 17, + ELF_DynTag_Relsz = 18, + ELF_DynTag_Relent = 19, + ELF_DynTag_Pltrel = 20, + ELF_DynTag_Debug = 21, + ELF_DynTag_TextRel = 22, + ELF_DynTag_JmpRel = 23, + ELF_DynTag_BindNow = 24, + ELF_DynTag_InitArray = 25, + ELF_DynTag_FiniArray = 26, + ELF_DynTag_InitArraysz = 27, + ELF_DynTag_FIniArraysz = 28, + ELF_DynTag_RunPath = 29, + ELF_DynTag_Flags = 30, + ELF_DynTag_PreInitArray = 32, + ELF_DynTag_PreInitArraysz = 33, + ELF_DynTag_SymtabShndx = 34, + + ELF_DynTag_LoOs = 0x6000000D, + ELF_DynTag_HiOs = 0x6ffff000, + + ELF_DynTag_ValRngLo = 0x6ffffd00, + ELF_DynTag_GNU_PreLinked = 0x6ffffdf5, + ELF_DynTag_GNU_Conflictsz = 0x6ffffdf6, + ELF_DynTag_GNU_LibListsz = 0x6ffffdf7, + ELF_DynTag_Checksum = 0x6ffffdf8, + ELF_DynTag_Pltpadsz = 0x6ffffdf9, + ELF_DynTag_Moveent = 0x6ffffdfa, + ELF_DynTag_Movesz = 0x6ffffdfb, + ELF_DynTag_Feature = 0x6ffffdfc, + ELF_DynTag_PosFlag_1 = 0x6ffffdfd, + ELF_DynTag_SymInSz = 0x6ffffdfe, + ELF_DynTag_SymInEnt = 0x6ffffdff, + ELF_DynTag_ValRngHi = ELF_DynTag_SymInEnt, + + ELF_DynTag_AddrRngLo = 0x6ffffe00, + ELF_DynTag_GNU_Hash = 0x6ffffef5, + ELF_DynTag_TlsDescPlt = 0x6ffffef6, + ELF_DynTag_TlsDescGot = 0x6ffffef7, + ELF_DynTag_GNU_Conflict = 0x6ffffef8, + ELF_DynTag_GNU_LibList = 0x6ffffef9, + ELF_DynTag_Config = 0x6ffffefa, + ELF_DynTag_DepAudit = 0x6ffffefb, + ELF_DynTag_Audit = 0x6ffffefc, + ELF_DynTag_PltPad = 0x6ffffefd, + ELF_DynTag_MoveTab = 0x6ffffefe, + ELF_DynTag_SymInfo = 0x6ffffeff, + ELF_DynTag_AddrRngHi = ELF_DynTag_SymInfo, + + ELF_DynTag_RelaCount = 0x6ffffff9, + ELF_DynTag_RelCount = 0x6ffffffa, + ELF_DynTag_Flags_1 = 0x6ffffffb, + ELF_DynTag_VerDef = 0x6ffffffc, + ELF_DynTag_VerDefNum = 0x6ffffffd, + ELF_DynTag_VerNeed = 0x6ffffffe, + ELF_DynTag_VerNeedNum = 0x6fffffff, + ELF_DynTag_VerSym = 0x6ffffff0, + ELF_DynTag_LoProc = 0x70000000, + ELF_DynTag_HiProc = 0x7fffffff, +}; + +typedef U32 ELF_DynFlag; +enum +{ + ELF_DynFlag_Origin = (1 << 0), + ELF_DynFlag_Symbolic = (1 << 1), + ELF_DynFlag_TextTel = (1 << 2), + ELF_DynFlag_BindNow = (1 << 3), + ELF_DynFlag_StaticTls = (1 << 4), +}; + +typedef U32 ELF_DynFeatureFlag; +enum +{ + ELF_DynFeatureFlag_ParInit = (1 << 0), + ELF_DynFeatureFlag_ConfExp = (1 << 1), +}; + +typedef U8 ELF_SymBind; +enum +{ + // the same name may exists in multiple files without interfering with each other. + ELF_SymBind_Local = 0, + // Visible to all objects that are linked together. + ELF_SymBind_Global = 1, + // If there is a global symbol with identical name linker doesn't issue an error. + ELF_SymBind_Weak = 2, + ELF_SymBind_LoProc = 13, + ELF_SymBind_HiProc = 15, +}; + +typedef U8 ELF_SymType; +enum +{ + ELF_SymType_NoType = 0, + // Type is not specified. + ELF_SymType_Object = 1, + // Symbol is associated with data object, such as a variable, an array, etc. + ELF_SymType_Func = 2, + // Symbol is associated with a function. + ELF_SymType_Section = 3, + // Symbol is used to relocate sections and normally have LOCAL binding. + ELF_SymType_File = 4, + // Gives name of the source file associated with object. + ELF_SymType_Common = 5, + ELF_SymType_Tls = 6, + ELF_SymType_LoProc = 13, + ELF_SymType_HiProc = 15, +}; + +typedef U8 ELF_SymVisibility; +enum +{ + ELF_SymVisibility_Default = 0, + ELF_SymVisibility_Internal = 1, + ELF_SymVisibility_Hidden = 2, + ELF_SymVisibility_Protected = 3, +}; + +typedef U32 ELF_RelocI386; +enum +{ + ELF_RelocI386_None = 0, + ELF_RelocI386_32 = 1, + ELF_RelocI386_PC32 = 2, + ELF_RelocI386_GOT32 = 3, + ELF_RelocI386_PLT32 = 4, + ELF_RelocI386_Copy = 5, + ELF_RelocI386_GlobDat = 6, + ELF_RelocI386_JumpSlot = 7, + ELF_RelocI386_Relative = 8, + ELF_RelocI386_GotOff = 9, + ELF_RelocI386_GotPc = 10, + ELF_RelocI386_32Plt = 11, + ELF_RelocI386_Tls_tpoff = 14, + ELF_RelocI386_Tls_ie = 15, + ELF_RelocI386_Tls_gotie = 16, + ELF_RelocI386_Tls_le = 17, + ELF_RelocI386_Tls_gd = 18, + ELF_RelocI386_Tls_ldm = 19, + ELF_RelocI386_16 = 20, + ELF_RelocI386_PC16 = 21, + ELF_RelocI386_8 = 22, + ELF_RelocI386_Pc8 = 23, + ELF_RelocI386_TlsGd32 = 24, + ELF_RelocI386_TlsGdPush = 25, + ELF_RelocI386_TlsGdCall = 26, + ELF_RelocI386_TlsGdPop = 27, + ELF_RelocI386_TlsLdm32 = 28, + ELF_RelocI386_TlsLdmPush = 29, + ELF_RelocI386_TlsLdmCall = 30, + ELF_RelocI386_TlsLdmPop = 31, + ELF_RelocI386_TlsLdo32 = 32, + ELF_RelocI386_TlsIe32 = 33, + ELF_RelocI386_TlsLe32 = 34, + ELF_RelocI386_TlsDtpmod32 = 35, + ELF_RelocI386_TlsDtpoff32 = 36, + ELF_RelocI386_TlsTpoff32 = 37, + // 38 is not taken + ELF_RelocI386_TlsGotDesc = 39, + ELF_RelocI386_TlsDescCall = 40, + ELF_RelocI386_TlsDesc = 41, + ELF_RelocI386_IRelative = 42, + ELF_RelocI386_Gotx32x = 43, + ELF_RelocI386_UsedByIntel200 = 200, + ELF_RelocI386_GNU_VTInherit = 250, + ELF_RelocI386_GNU_VTEntry = 251, +}; + +typedef U32 ELF_RelocX8664; +enum +{ + ELF_RelocX8664_None = 0, + ELF_RelocX8664_64 = 1, + ELF_RelocX8664_Pc32 = 2, + ELF_RelocX8664_Got32 = 3, + ELF_RelocX8664_Plt32 = 4, + ELF_RelocX8664_Copy = 5, + ELF_RelocX8664_GlobDat = 6, + ELF_RelocX8664_JumpSlot = 7, + ELF_RelocX8664_Relative = 8, + ELF_RelocX8664_GotPcRel = 9, + ELF_RelocX8664_32 = 10, + ELF_RelocX8664_32S = 11, + ELF_RelocX8664_16 = 12, + ELF_RelocX8664_Pc16 = 13, + ELF_RelocX8664_8 = 14, + ELF_RelocX8664_Pc8 = 15, + ELF_RelocX8664_DtpMod64 = 16, + ELF_RelocX8664_DtpOff64 = 17, + ELF_RelocX8664_TpOff64 = 18, + ELF_RelocX8664_TlsGd = 19, + ELF_RelocX8664_TlsLd = 20, + ELF_RelocX8664_DtpOff32 = 21, + ELF_RelocX8664_GotTpOff = 22, + ELF_RelocX8664_TpOff32 = 23, + ELF_RelocX8664_Pc64 = 24, + ELF_RelocX8664_GotOff64 = 25, + ELF_RelocX8664_GotPc32 = 26, + ELF_RelocX8664_Got64 = 27, + ELF_RelocX8664_GotPcRel64 = 28, + ELF_RelocX8664_GotPc64 = 29, + ELF_RelocX8664_GotPlt64 = 30, + ELF_RelocX8664_PltOff64 = 31, + ELF_RelocX8664_Size32 = 32, + ELF_RelocX8664_Size64 = 33, + ELF_RelocX8664_GotPc32TlsDesc = 34, + ELF_RelocX8664_TlsDescCall = 35, + ELF_RelocX8664_TlsDesc = 36, + ELF_RelocX8664_IRelative = 37, + ELF_RelocX8664_Relative64 = 38, + ELF_RelocX8664_Pc32Bnd = 39, + ELF_RelocX8664_Plt32Bnd = 40, + ELF_RelocX8664_GotPcRelx = 41, + ELF_RelocX8664_RexGotPcRelx = 42, + ELF_RelocX8664_GNU_VTInherit = 250, + ELF_RelocX8664_GNU_VTEntry = 251, +}; + +typedef U32 ELF_ExternalVerFlag; +enum +{ + ELF_ExternalVerFlag_Base = (1 << 0), + ELF_ExternalVerFlag_Weak = (1 << 1), + ELF_ExternalVerFlag_Info = (1 << 2), +}; + +typedef U32 ELF_NoteType; +enum +{ + ELF_NoteType_GNU_Abi = 1, + ELF_NoteType_GNU_HwCap = 2, + ELF_NoteType_GNU_BuildId = 3, + ELF_NoteType_GNU_GoldVersion = 4, + ELF_NoteType_GNU_PropertyType0 = 5, +}; + +typedef U32 ELF_GnuABITag; +enum +{ + ELF_GnuABITag_Linux = 0, + ELF_GnuABITag_Hurd = 1, + ELF_GnuABITag_Solaris = 2, + ELF_GnuABITag_FreeBsd = 3, + ELF_GnuABITag_NetBsd = 4, + ELF_GnuABITag_Syllable = 5, + ELF_GnuABITag_Nacl = 6, +}; + +typedef S32 ELF_GnuProperty; +enum +{ + ELF_GnuProperty_LoProc = 0xc0000000, + // processor-specific range + ELF_GnuProperty_HiProc = 0xdfffffff, + ELF_GnuProperty_LoUser = 0xe0000000, + // application-specific range + ELF_GnuProperty_HiUser = 0xffffffff, + ELF_GnuProperty_StackSize = 1, + ELF_GnuProperty_NoCopyOnProtected = 2, +}; + +typedef U32 ELF_GnuPropertyX86Isa1; +enum +{ + ELF_GnuPropertyX86Isa1_BaseLine = (1 << 0), + ELF_GnuPropertyX86Isa1_V2 = (1 << 1), + ELF_GnuPropertyX86Isa1_V3 = (1 << 2), + ELF_GnuPropertyX86Isa1_V4 = (1 << 3), +}; + +typedef U32 ELF_GnuPropertyX86Compat1Isa1; +enum +{ + ELF_GnuPropertyX86Compat1Isa1_486 = (1 << 0), + ELF_GnuPropertyX86Compat1Isa1_586 = (1 << 1), + ELF_GnuPropertyX86Compat1Isa1_686 = (1 << 2), + ELF_GnuPropertyX86Compat1Isa1_SSE = (1 << 3), + ELF_GnuPropertyX86Compat1Isa1_SSE2 = (1 << 4), + ELF_GnuPropertyX86Compat1Isa1_SSE3 = (1 << 5), + ELF_GnuPropertyX86Compat1Isa1_SSSE3 = (1 << 6), + ELF_GnuPropertyX86Compat1Isa1_SSE4_1 = (1 << 7), + ELF_GnuPropertyX86Compat1Isa1_SSE4_2 = (1 << 8), + ELF_GnuPropertyX86Compat1Isa1_AVX = (1 << 9), + ELF_GnuPropertyX86Compat1Isa1_AVX2 = (1 << 10), + ELF_GnuPropertyX86Compat1Isa1_AVX512F = (1 << 11), + ELF_GnuPropertyX86Compat1Isa1_AVX512ER = (1 << 12), + ELF_GnuPropertyX86Compat1Isa1_AVX512PF = (1 << 13), + ELF_GnuPropertyX86Compat1Isa1_AVX512VL = (1 << 14), + ELF_GnuPropertyX86Compat1Isa1_AVX512DQ = (1 << 15), + ELF_GnuPropertyX86Compat1Isa1_AVX512BW = (1 << 16), +}; + +typedef U32 ELF_GnuPropertyX86Compat2Isa1; +enum +{ + ELF_GnuPropertyX86Compat2Isa1_CMOVE = (1 << 0), + ELF_GnuPropertyX86Compat2Isa1_SSE = (1 << 1), + ELF_GnuPropertyX86Compat2Isa1_SSE2 = (1 << 2), + ELF_GnuPropertyX86Compat2Isa1_SSE3 = (1 << 3), + ELF_GnuPropertyX86Compat2Isa1_SSE4_1 = (1 << 4), + ELF_GnuPropertyX86Compat2Isa1_SSE4_2 = (1 << 5), + ELF_GnuPropertyX86Compat2Isa1_AVX = (1 << 6), + ELF_GnuPropertyX86Compat2Isa1_AVX2 = (1 << 7), + ELF_GnuPropertyX86Compat2Isa1_FMA = (1 << 8), + ELF_GnuPropertyX86Compat2Isa1_AVX512F = (1 << 9), + ELF_GnuPropertyX86Compat2Isa1_AVX512CD = (1 << 10), + ELF_GnuPropertyX86Compat2Isa1_AVX512ER = (1 << 11), + ELF_GnuPropertyX86Compat2Isa1_AVX512PF = (1 << 12), + ELF_GnuPropertyX86Compat2Isa1_AVX512VL = (1 << 13), + ELF_GnuPropertyX86Compat2Isa1_AVX512DQ = (1 << 14), + ELF_GnuPropertyX86Compat2Isa1_AVX512BW = (1 << 15), + ELF_GnuPropertyX86Compat2Isa1_AVX512_4FMAPS = (1 << 16), + ELF_GnuPropertyX86Compat2Isa1_AVX512_4VNNIW = (1 << 17), + ELF_GnuPropertyX86Compat2Isa1_AVX512_BITALG = (1 << 18), + ELF_GnuPropertyX86Compat2Isa1_AVX512_IFMA = (1 << 19), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VBMI = (1 << 20), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VBMI2 = (1 << 21), + ELF_GnuPropertyX86Compat2Isa1_AVX512_VNNI = (1 << 22), + ELF_GnuPropertyX86Compat2Isa1_AVX512_BF16 = (1 << 23), +}; + +typedef S32 ELF_GnuPropertyX86; +enum +{ + ELF_GnuPropertyX86_Feature1And = 0xc0000002, + ELF_GnuPropertyX86_Feature2Used = 0xc0010001, + ELF_GnuPropertyX86_Isa1needed = 0xc0008002, + ELF_GnuPropertyX86_Isa2Needed = 0xc0008001, + ELF_GnuPropertyX86_Isa1Used = 0xc0010002, + ELF_GnuPropertyX86_Compat_isa_1_used = 0xc0000000, + ELF_GnuPropertyX86_Compat_isa_1_needed = 0xc0000001, + ELF_GnuPropertyX86_UInt32AndLo = ELF_GnuPropertyX86_Feature1And, + ELF_GnuPropertyX86_UInt32AndHi = 0xc0007fff, + ELF_GnuPropertyX86_UInt32OrLo = 0xc0008000, + ELF_GnuPropertyX86_UInt32OrHi = 0xc000ffff, + ELF_GnuPropertyX86_UInt32OrAndLo = 0xc0010000, + ELF_GnuPropertyX86_UInt32OrAndHi = 0xc0017fff, +}; + +typedef U32 ELF_GnuPropertyX86Feature1; +enum +{ + ELF_GnuPropertyX86Feature1_Ibt = (1 << 0), + ELF_GnuPropertyX86Feature1_Shstk = (1 << 1), + ELF_GnuPropertyX86Feature1_LamU48 = (1 << 2), + ELF_GnuPropertyX86Feature1_LamU57 = (1 << 3), +}; + +typedef U32 ELF_GnuPropertyX86Feature2; +enum +{ + ELF_GnuPropertyX86Feature2_X86 = (1 << 0), + ELF_GnuPropertyX86Feature2_X87 = (1 << 1), + ELF_GnuPropertyX86Feature2_MMX = (1 << 2), + ELF_GnuPropertyX86Feature2_XMM = (1 << 3), + ELF_GnuPropertyX86Feature2_YMM = (1 << 4), + ELF_GnuPropertyX86Feature2_ZMM = (1 << 5), + ELF_GnuPropertyX86Feature2_FXSR = (1 << 6), + ELF_GnuPropertyX86Feature2_XSAVE = (1 << 7), + ELF_GnuPropertyX86Feature2_XSAVEOPT = (1 << 8), + ELF_GnuPropertyX86Feature2_XSAVEC = (1 << 9), + ELF_GnuPropertyX86Feature2_TMM = (1 << 10), + ELF_GnuPropertyX86Feature2_MASK = (1 << 11), +}; + +#define ELF_HdrIs64Bit(e_ident) (e_ident[ELF_Identifier_Class] == ELF_Class_64) +#define ELF_HdrIs32Bit(e_ident) (e_ident[ELF_Identifier_Class] == ELF_Class_32) + +typedef enum ELF_Identifier +{ + ELF_Identifier_Mag0 = 0, + ELF_Identifier_Mag1 = 1, + ELF_Identifier_Mag2 = 2, + ELF_Identifier_Mag3 = 3, + ELF_Identifier_Class = 4, + ELF_Identifier_Data = 5, + ELF_Identifier_Version = 6, + ELF_Identifier_OsAbi = 7, + ELF_Identfiier_AbiBersion = 8, + ELF_Identifier_Max = 16, +} ELF_Identifier; + +typedef U16 ELF_Type; +typedef enum ELF_TypeEnum +{ + ELF_Type_None = 0, + ELF_Type_Rel = 1, + ELF_Type_Exec = 2, + ELF_Type_Dyn = 3, + ELF_Type_Core = 4, + ELF_Type_LoOs = 0xfe00, + ELF_Type_HiOs = 0xfeff, + ELF_Type_LoProc = 0xff00, + ELF_Type_HiProc = 0xffff, +} ELF_TypeEnum; + +typedef struct ELF_Hdr64 +{ + U8 e_ident[ELF_Identifier_Max]; + ELF_Type e_type; + ELF_MachineKind e_machine; + U32 e_version; + U64 e_entry; + U64 e_phoff; + U64 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Hdr64; + +typedef struct ELF_Hdr32 +{ + U8 e_ident[ELF_Identifier_Max]; + ELF_Type e_type; + ELF_MachineKind e_machine; + U32 e_version; + U32 e_entry; + U32 e_phoff; + U32 e_shoff; + U32 e_flags; + U16 e_ehsize; + U16 e_phentsize; + U16 e_phnum; + U16 e_shentsize; + U16 e_shnum; + U16 e_shstrndx; +} ELF_Hdr32; + +typedef struct ELF_Shdr64 +{ + U32 sh_name; + U32 sh_type; + U64 sh_flags; + U64 sh_addr; + U64 sh_offset; + U64 sh_size; + U32 sh_link; + U32 sh_info; + U64 sh_addralign; + U64 sh_entsize; +} ELF_Shdr64; + +typedef struct ELF_Shdr32 +{ + U32 sh_name; + U32 sh_type; + U32 sh_flags; + U32 sh_addr; + U32 sh_offset; + U32 sh_size; + U32 sh_link; + U32 sh_info; + U32 sh_addralign; + U32 sh_entsize; +} ELF_Shdr32; + +typedef struct ELF_Phdr64 +{ + U32 p_type; + U32 p_flags; + U64 p_offset; + U64 p_vaddr; + U64 p_paddr; + U64 p_filesz; + U64 p_memsz; + U64 p_align; +} ELF_Phdr64; + +typedef struct ELF_Phdr32 +{ + U32 p_type; + U32 p_offset; + U32 p_vaddr; + U32 p_paddr; + U32 p_filesz; + U32 p_memsz; + U32 p_flags; + U32 p_align; +} ELF_Phdr32; + +//////////////////////////////// +// Auxiliary Vectors + +// these appear in /proc//auxv of a process, they are not in elf files + +typedef struct ELF_Auxv32 +{ + U32 a_type; + U32 a_val; +} ELF_Auxv32; + +typedef struct ELF_Auxv64 +{ + U64 a_type; + U64 a_val; +} ELF_Auxv64; + +//////////////////////////////// +// Dynamic Structures + +// these appear in the virtual address space of a process, they are not in elf files + +typedef struct ELF_Dyn32 +{ + U32 tag; + U32 val; +} ELF_Dyn32; + +typedef struct ELF_Dyn64 +{ + U64 tag; + U64 val; +} ELF_Dyn64; + +typedef struct ELF_LinkMap32 +{ + U32 base; + U32 name; + U32 ld; + U32 next; +} ELF_LinkMap32; + +typedef struct ELF_LinkMap64 +{ + U64 base; + U64 name; + U64 ld; + U64 next; +} ELF_LinkMap64; + +//////////////////////////////// +// Imports and Exports + +typedef struct +{ + U32 st_name; // Holds index into files string table. + U32 st_value; // Depending on the context, this may be address, size, etc. + U32 st_size; // Data size in bytes. Zero when size is unknown. + U8 st_info; // Contains symbols type and binding. + U8 st_other; // Reserved for future use, currenly zero. + U16 st_shndx; // Section index to which symbol is relevant. +} ELF_Sym32; + +typedef struct +{ + U32 st_name; + U8 st_info; + U8 st_other; + U16 st_shndx; + U64 st_value; + U64 st_size; +} ELF_Sym64; + +#define ELF_ST_INFO(b,t) (((b) << 4) + ((t) & 0xF)) +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) ((x) & 0xF) +#define ELF_ST_VISIBILITY(v) ((v) & 0x3) + +typedef struct +{ + U32 r_offset; + U32 r_info; +} ELF_Rel32; + +typedef struct +{ + U32 r_offset; + U32 r_info; + S32 r_addend; +} ELF_Rela32; + +typedef struct +{ + U64 r_offset; + U64 r_info; +} ELF_Rel64; + +typedef struct +{ + U64 r_offset; + U64 r_info; + S64 r_addend; +} ELF_Rela64; + +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xFF) + +#define ELF64_R_INFO(s,t) (((U64)(s) << 32) | (U64)t) +#define ELF64_R_SYM(x) ((x) >> 32) +#define ELF64_R_TYPE(x) ((x) & 0xffffffff) + +// This flag is set to indicate that symbol is not available outside shared object +#define ELF_EXTERNAL_VERSYM_HIDDEN 0x8000 +#define ELF_EXTERNAL_VERSYM_MASK 0x7FFF + +// Appears in .gnu.verdef (SHT_GNU_verdef) +typedef struct +{ + U16 vd_version; + U16 vd_flags; + U16 vd_ndx; + U16 vd_cnt; + U32 vd_hash; + U32 vd_aux; + U32 vd_next; +} ELF_ExternalVerdef; + +// Appears in .gnu.verdef (SHT_GNU_verdef) +typedef struct +{ + U32 vda_name; + U32 vda_next; +} ELF_ExternalVerdaux; + +// Appears in .gnu.verneed (SHT_GNU_verneed) +typedef struct +{ + U16 vn_version; + U16 vn_cnt; + U32 vn_file; + U32 vn_aux; + U32 vn_next; +} ELF_ExternalVerneed; + +// Appears in .gnu.verneed (SHT_GNU_verneed) +typedef struct +{ + U32 vna_hash; + U16 vna_flags; + U16 vna_other; + U32 vna_name; + U32 vna_next; +} ELF_ExternalVernaux; + +// Appears in .gnu.version (SHT_GNU_versym) +typedef struct +{ + U16 vs_vers; +} ELF_ExternalVersym; + +typedef struct +{ + U32 name_size; + U32 desc_size; + U32 type; + // name + desc + // U8 data[1]; +} ELF_Note; + +//////////////////////////////// +// Extensions + +typedef U8 ELF_CompressType; +enum ELF_CompressTypeEnum +{ + ELF_CompressType_None = 0, + ELF_CompressType_ZLib = 1, + ELF_CompressType_ZStd = 2, + + ELF_CompressType_LoOs = 0x60000000, + ELF_CompressType_HiOs = 0x6fffffff, + + ELF_CompressType_LoProc = 0x70000000, + ELF_CompressType_HiProc = 0x7fffffff, +}; + +typedef struct ELF_Chdr32 +{ + U32 ch_type; + U32 ch_size; + U32 ch_addr_align; +} ELF_Chdr32; + +typedef struct ELF_Chdr64 +{ + U64 ch_type; + U64 ch_size; + U64 ch_addr_align; +} ELF_Chdr64; + +//////////////////////////////// + +internal ELF_Hdr64 elf_hdr64_from_ehdr32(ELF_Hdr32 h32); +internal ELF_Shdr64 elf_shdr64_from_shdr32(ELF_Shdr32 h32); +internal ELF_Phdr64 elf_phdr64_from_phdr32(ELF_Phdr32 h32); +internal ELF_Dyn64 elf_dyn64_from_dyn32 (ELF_Dyn32 h32); +internal ELF_Sym64 elf_sym64_from_sym32 (ELF_Sym32 sym32); +internal ELF_Rel64 elf_rel64_from_rel32 (ELF_Rel32 rel32); +internal ELF_Rela64 elf_rela64_from_rela32(ELF_Rela32 rela32); +internal ELF_Chdr64 elf_chdr64_from_chdr32(ELF_Chdr32 chdr32); + +//////////////////////////////// + +internal String8 elf_string_from_class(Arena *arena, ELF_Class v); + +//////////////////////////////// + +internal Arch arch_from_elf_machine(ELF_MachineKind machine); + +#endif // ELF_H + diff --git a/src/elf/elf_parse.c b/src/elf/elf_parse.c new file mode 100644 index 00000000..ebd58bfd --- /dev/null +++ b/src/elf/elf_parse.c @@ -0,0 +1,143 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal B32 +elf_check_magic(String8 data) +{ + U8 sig[ELF_Identifier_Max] = {0}; + str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1); + B32 is_magic_valid = (sig[ELF_Identifier_Mag0] == 0x7f && sig[ELF_Identifier_Mag1] == 'E' && sig[ELF_Identifier_Mag2] == 'L' && sig[ELF_Identifier_Mag3] == 'F'); + return is_magic_valid; +} + +internal ELF_BinInfo +elf_bin_from_data(String8 data) +{ + ELF_Hdr64 hdr64 = {0}; + Rng1U64 sh_name_range = rng_1u64(0,0); + + if (elf_check_magic(data)) { + U8 sig[ELF_Identifier_Max] = {0}; + str8_deserial_read(data, 0, &sig[0], sizeof(sig), 1); + + switch (sig[ELF_Identifier_Class]) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Hdr32 hdr32 = {0}; + U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr32); + if (hdr_size == sizeof(hdr32)) { + hdr64 = elf_hdr64_from_hdr32(hdr32); + + U64 shstr_off = hdr32.e_shoff + hdr32.e_shentsize*hdr32.e_shstrndx; + ELF_Shdr32 shdr = {0}; + U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr); + + if (shdr_size == sizeof(shdr)) { + sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size); + } + } + } break; + case ELF_Class_64: { + U64 hdr_size = str8_deserial_read_struct(data, 0, &hdr64); + if (hdr_size == sizeof(hdr64)) { + U64 shstr_off = hdr64.e_shoff + hdr64.e_shentsize*hdr64.e_shstrndx; + ELF_Shdr64 shdr = {0}; + U64 shdr_size = str8_deserial_read_struct(data, shstr_off, &shdr); + + if (shdr_size == sizeof(shdr)) { + sh_name_range = rng_1u64(shdr.sh_offset, shdr.sh_offset + shdr.sh_size); + } + } + } break; + default: Assert(!"invalid elf header"); break; + } + } + + ELF_BinInfo info = {0}; + info.hdr = hdr64; + info.sh_name_range = sh_name_range; + + return info; +} + +internal ELF_Shdr64Array +elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr) +{ + Rng1U64 shdr_range = rng_1u64(hdr->e_shoff, hdr->e_shoff + hdr->e_shentsize*hdr->e_shnum); + String8 shdr_data = str8_substr(raw_data, shdr_range); + + ELF_Shdr64Array result = {0}; + result.count = hdr->e_shnum; + result.v = push_array(arena, ELF_Shdr64, hdr->e_shnum); + + for(U64 shdr_idx = 0; shdr_idx < hdr->e_shnum; ++shdr_idx) { + switch (hdr->e_ident[ELF_Identifier_Class]) { + case ELF_Class_None: break; + case ELF_Class_32: { + ELF_Shdr32 shdr32 = {0}; + str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr32), &shdr32); + result.v[shdr_idx] = elf_shdr64_from_shdr32(shdr32); + } break; + case ELF_Class_64: { + str8_deserial_read_struct(shdr_data, shdr_idx * sizeof(ELF_Shdr64), &result.v[shdr_idx]); + } break; + default: InvalidPath; break; + } + } + + return result; +} + +internal String8 +elf_name_from_shdr64(String8 raw_data, ELF_Hdr64 *hdr, Rng1U64 sh_name_range, ELF_Shdr64 *shdr) +{ + String8 sh_names = str8_substr(raw_data, sh_name_range); + String8 name = {0}; + str8_deserial_read_cstr(sh_names, shdr->sh_name, &name); + return name; +} + +internal U64 +elf_base_addr_from_bin(ELF_Hdr64 *hdr) +{ + NotImplemented; + return 0; +} + +internal B32 +elf_parse_debug_link(String8 raw_data, ELF_BinInfo *elf, ELF_GnuDebugLink *debug_link_out) +{ + Temp scratch = scratch_begin(0,0); + + B32 is_debug_link_present = 0; + ELF_Shdr64Array sections = elf_shdr64_array_from_bin(scratch.arena, raw_data, &elf->hdr); + for (U64 i = 0; i < sections.count; ++i) { + ELF_Shdr64 *shdr = §ions.v[i]; + String8 name = elf_name_from_shdr64(raw_data, &elf->hdr, elf->sh_name_range, shdr); + + if (str8_match(name, str8_lit(".gnu_debuglink"), 0)) { + Rng1U64 raw_data_range = rng_1u64(shdr->sh_offset, shdr->sh_offset + shdr->sh_size); + String8 data = str8_substr(raw_data, raw_data_range); + + String8 path = {0}; + U32 checksum = 0; + { + U64 cursor = 0; + cursor += str8_deserial_read_cstr(data, cursor, &path); + + cursor = AlignPow2(cursor, 4); + cursor += str8_deserial_read_struct(data, cursor, &checksum); + } + + debug_link_out->path = path; + debug_link_out->checksum = checksum; + + is_debug_link_present = 1; + break; + } + } + + scratch_end(scratch); + return is_debug_link_present; +} + diff --git a/src/elf/elf_parse.h b/src/elf/elf_parse.h new file mode 100644 index 00000000..1d1d1ba4 --- /dev/null +++ b/src/elf/elf_parse.h @@ -0,0 +1,36 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef ELF_PARSE_H +#define ELF_PARSE_H + +//////////////////////////////// + +typedef struct ELF_BinInfo +{ + ELF_Hdr64 hdr; + Rng1U64 sh_name_range; +} ELF_BinInfo; + +typedef struct ELF_Shdr64Array +{ + U64 count; + ELF_Shdr64 *v; +} ELF_Shdr64Array; + +typedef struct ELF_GnuDebugLink +{ + String8 path; + U32 checksum; +} ELF_GnuDebugLink; + +//////////////////////////////// + +internal B32 elf_check_magic(String8 data); +internal ELF_BinInfo elf_bin_from_data(String8 data); + +internal ELF_Shdr64Array elf_shdr64_array_from_bin(Arena *arena, String8 raw_data, ELF_Hdr64 *hdr); +internal String8 elf_name_from_shdr64(String8 raw_data, ELF_Hdr64 *hdr, Rng1U64 sh_name_range, ELF_Shdr64 *shdr); +internal U64 elf_base_addr_from_bin(ELF_Hdr64 *hdr); + +#endif // ELF_PARSE_H diff --git a/src/eval/eval.mdesk b/src/eval/eval.mdesk index f6de6560..f7f382ed 100644 --- a/src/eval/eval.mdesk +++ b/src/eval/eval.mdesk @@ -26,32 +26,32 @@ E_TypeKindTable: {UChar8 "uchar8" 1 } {UChar16 "uchar16" 2 } {UChar32 "uchar32" 4 } - {U8 "U8" 1 } - {U16 "U16" 2 } - {U32 "U32" 4 } - {U64 "U64" 8 } - {U128 "U128" 16 } - {U256 "U256" 32 } - {U512 "U512" 64 } - {S8 "S8" 1 } - {S16 "S16" 2 } - {S32 "S32" 4 } - {S64 "S64" 8 } - {S128 "S128" 16 } - {S256 "S256" 32 } - {S512 "S512" 64 } + {U8 "uint8" 1 } + {U16 "uint16" 2 } + {U32 "uint32" 4 } + {U64 "uint64" 8 } + {U128 "uint128" 16 } + {U256 "uint256" 32 } + {U512 "uint512" 64 } + {S8 "int8" 1 } + {S16 "int16" 2 } + {S32 "int32" 4 } + {S64 "int64" 8 } + {S128 "int128" 16 } + {S256 "int256" 32 } + {S512 "int512" 64 } {Bool "bool" 1 } - {F16 "F16" 2 } - {F32 "F32" 4 } - {F32PP "F32PP" 4 } - {F48 "F48" 6 } - {F64 "F64" 8 } - {F80 "F80" 10 } - {F128 "F128" 16 } - {ComplexF32 "ComplexF32" 8 } - {ComplexF64 "ComplexF64" 16 } - {ComplexF80 "ComplexF80" 20 } - {ComplexF128 "ComplexF128" 32 } + {F16 "float16" 2 } + {F32 "float32" 4 } + {F32PP "float32PP" 4 } + {F48 "float48" 6 } + {F64 "float64" 8 } + {F80 "float80" 10 } + {F128 "float128" 16 } + {ComplexF32 "complex_float32" 8 } + {ComplexF64 "complex_float64" 16 } + {ComplexF80 "complex_float80" 20 } + {ComplexF128 "complex_float128" 32 } {Modifier "modifier" 0 } {Ptr "ptr" 0 } {LRef "lref" 0 } @@ -71,68 +71,75 @@ E_TypeKindTable: {IncompleteEnum "enum" 0 } {Bitfield "bitfield" 0 } {Variadic "variadic" 0 } - {Collection "collection" 0 } + {Set "set" 0 } + {Lens "lens" 0 } + {LensSpec "lens_spec" 0 } + {MetaExpr "meta_expr" 0 } + {MetaDisplayName "meta_display_name" 0 } + {MetaDescription "meta_description" 0 } } -@table(name op_kind precedence string op_pre op_sep op_pos) +@table(name op_kind precedence op_pre op_sep op_pos op_chain) E_ExprKindTable: { - { Nil Null 0 "" "" "" "" } - { Ref Null 0 "" "" "" "" } + { Nil Null 0 "" "" "" "" } + { Ref Null 0 "" "" "" "" } - { ArrayIndex Null 0 "[]" "" "[" "]"} - { MemberAccess Null 0 "." "" "." "" } - { Deref UnaryPrefix 2 "*" "*" "" "" } - { Address UnaryPrefix 2 "&" "&" "" "" } + { ArrayIndex Null 0 "" "[" "]" "" } + { MemberAccess Null 0 "" "." "" "" } + { Deref UnaryPrefix 2 "*" "" "" "" } + { Address UnaryPrefix 2 "&" "" "" "" } - { Cast Null 1 "cast" "(" ")" "" } - { Sizeof UnaryPrefix 1 "sizeof" "sizeof" "(" ")"} - { Typeof UnaryPrefix 1 "typeof" "typeof" "(" ")"} - { ByteSwap UnaryPrefix 1 "bswap" "bswap" "(" ")"} + { Cast Null 1 "cast(" ")" "" "" } + { Sizeof UnaryPrefix 1 "sizeof " "" "" "" } + { Typeof UnaryPrefix 1 "typeof " "" "" "" } + { ByteSwap UnaryPrefix 1 "bswap " "" "" "" } - { Pos UnaryPrefix 2 "+" "+" "" "" } - { Neg UnaryPrefix 2 "-" "-" "" "" } - { LogNot UnaryPrefix 2 "!" "!" "" "" } - { BitNot UnaryPrefix 2 "~" "~" "" "" } - { Mul Binary 3 "*" "" "*" "" } - { Div Binary 3 "/" "" "/" "" } - { Mod Binary 3 "%" "" "%" "" } - { Add Binary 4 "+" "" "+" "" } - { Sub Binary 4 "-" "" "-" "" } - { LShift Binary 5 "<<" "" "<<" "" } - { RShift Binary 5 ">>" "" ">>" "" } - { Less Binary 6 "<" "" "<" "" } - { LsEq Binary 6 "<=" "" "<=" "" } - { Grtr Binary 6 ">" "" ">" "" } - { GrEq Binary 6 ">=" "" ">=" "" } - { EqEq Binary 7 "==" "" "==" "" } - { NtEq Binary 7 "!=" "" "!=" "" } + { Pos UnaryPrefix 2 "+" "" "" "" } + { Neg UnaryPrefix 2 "-" "" "" "" } + { LogNot UnaryPrefix 2 "!" "" "" "" } + { BitNot UnaryPrefix 2 "~" "" "" "" } + { Mul Binary 3 "" " * " "" "" } + { Div Binary 3 "" " / " "" "" } + { Mod Binary 3 "" " % " "" "" } + { Add Binary 4 "" " + " "" "" } + { Sub Binary 4 "" " - " "" "" } + { LShift Binary 5 "" " << " "" "" } + { RShift Binary 5 "" " >> " "" "" } + { Less Binary 6 "" " < " "" "" } + { LsEq Binary 6 "" " <= " "" "" } + { Grtr Binary 6 "" " > " "" "" } + { GrEq Binary 6 "" " >= " "" "" } + { EqEq Binary 7 "" " == " "" "" } + { NtEq Binary 7 "" " != " "" "" } - { BitAnd Binary 8 "&" "" "&" "" } - { BitXor Binary 9 "^" "" "^" "" } - { BitOr Binary 10 "|" "" "|" "" } - { LogAnd Binary 11 "&&" "" "&&" "" } - { LogOr Binary 12 "||" "" "||" "" } + { BitAnd Binary 8 "" " & " "" "" } + { BitXor Binary 9 "" " ^ " "" "" } + { BitOr Binary 10 "" " | " "" "" } + { LogAnd Binary 11 "" " && " "" "" } + { LogOr Binary 12 "" " || " "" "" } - { Ternary Null 0 "? " "" "?" ":"} + { Ternary Null 0 "" " ? " "" " : "} - { LeafBytecode Null 0 "bytecode" "" "" "" } - { LeafMember Null 0 "member" "" "" "" } - { LeafStringLiteral Null 0 "string_literal" "" "" "" } - { LeafBool Null 0 "B32" "" "" "" } - { LeafU64 Null 0 "U64" "" "" "" } - { LeafF64 Null 0 "F64" "" "" "" } - { LeafF32 Null 0 "F32" "" "" "" } - { LeafIdent Null 0 "leaf_ident" "" "" "" } - { LeafOffset Null 0 "leaf_offset" "" "" "" } - { LeafFilePath Null 0 "leaf_filepath" "" "" "" } + { Call Null 15 "" "(" ")" ", "} - { TypeIdent Null 0 "type_ident" "" "" "" } - { Ptr Null 0 "ptr" "" "" "" } - { Array Null 0 "array" "" "" "" } - { Func Null 0 "function" "" "" "" } + { LeafBytecode Null 0 "" "" "" "" } + { LeafStringLiteral Null 0 "" "" "" "" } + { LeafU64 Null 0 "" "" "" "" } + { LeafF64 Null 0 "" "" "" "" } + { LeafF32 Null 0 "" "" "" "" } + { LeafIdentifier Null 0 "" "" "" "" } + { LeafOffset Null 0 "" "" "" "" } + { LeafValue Null 0 "" "" "" "" } + { LeafFilePath Null 0 "" "" "" "" } - { Define Binary 13 "=" "" "=" "" } + { TypeIdent Null 0 "" "" "" "" } + { Ptr Null 0 "" "" "" "" } + { Array Null 0 "" "" "" "" } + { Func Null 0 "" "" "" "" } + { Unsigned Null 0 "unsigned " "" "" "" } + + { Define Binary 13 "" " = " "" "" } } @table(name display_string) @@ -157,6 +164,12 @@ E_InterpretationCodeTable: COUNT, } +@data(String8) +e_token_kind_strings: +{ + @expand(E_TokenKindTable a) `str8_lit_comp("$(a.name)")` +} + @enum E_TypeKind: { @expand(E_TypeKindTable a) `$(a.name)`, @@ -171,6 +184,18 @@ E_InterpretationCodeTable: `LastSigned2 = E_TypeKind_S512`, `FirstIncomplete = E_TypeKind_IncompleteStruct`, `LastIncomplete = E_TypeKind_IncompleteEnum`, + `FirstMeta = E_TypeKind_MetaExpr`, + `LastMeta = E_TypeKind_MetaDescription`, +} + +@data(String8) e_type_kind_basic_string_table: +{ + @expand(E_TypeKindTable a) `str8_lit_comp("$(a.basic_string)")`; +} + +@data(U8) e_type_kind_basic_byte_size_table: +{ + @expand(E_TypeKindTable a) `$(a.basic_byte_size)`; } @enum(U32) E_ExprKind: @@ -179,40 +204,24 @@ E_InterpretationCodeTable: COUNT, } -@enum E_InterpretationCode: -{ - @expand(E_InterpretationCodeTable a) `$(a.name)`, - COUNT, -} - -@data(String8) -e_token_kind_strings: -{ - @expand(E_TokenKindTable a) `str8_lit_comp("$(a.name)")` -} - @data(String8) e_expr_kind_strings: { @expand(E_ExprKindTable a) `str8_lit_comp("$(a.name)")` } +@data(E_OpInfo) e_expr_kind_op_info_table: +{ + @expand(E_ExprKindTable a) `{ E_OpKind_$(a.op_kind), $(a.precedence), str8_lit_comp("$(a.op_pre)"), str8_lit_comp("$(a.op_sep)"), str8_lit_comp("$(a.op_pos)"), str8_lit_comp("$(a.op_chain)") }` +} + +@enum E_InterpretationCode: +{ + @expand(E_InterpretationCodeTable a) `$(a.name)`, + COUNT, +} + @data(String8) e_interpretation_code_display_strings: { @expand(E_InterpretationCodeTable a) `str8_lit_comp("$(a.display_string)")` } - -@data(E_OpInfo) e_expr_kind_op_info_table: -{ - @expand(E_ExprKindTable a) `{ E_OpKind_$(a.op_kind), $(a.precedence), str8_lit_comp("$(a.op_pre)"), str8_lit_comp("$(a.op_sep)"), str8_lit_comp("$(a.op_pos)") }` -} - -@data(U8) e_kind_basic_byte_size_table: -{ - @expand(E_TypeKindTable a) `$(a.basic_byte_size)`; -} - -@data(String8) e_kind_basic_string_table: -{ - @expand(E_TypeKindTable a) `str8_lit_comp("$(a.basic_string)")`; -} diff --git a/src/eval/eval_bundles.c b/src/eval/eval_bundles.c deleted file mode 100644 index 5cdf357c..00000000 --- a/src/eval/eval_bundles.c +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Bundled Evaluation Functions - -internal E_Eval -e_eval_from_expr(Arena *arena, E_Expr *expr) -{ - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(arena, expr); - E_OpList oplist = e_oplist_from_irtree(arena, irtree.root); - String8 bytecode = e_bytecode_from_oplist(arena, &oplist); - E_Interpretation interp = e_interpret(bytecode); - E_Space zero_space = {0}; - E_Space space = (MemoryMatchStruct(&zero_space, &irtree.space) ? e_interpret_ctx->primary_space : irtree.space); - E_Eval eval = - { - .value = interp.value, - .mode = irtree.mode, - .space = space, - .expr = expr, - .type_key = irtree.type_key, - .code = interp.code, - }; - e_msg_list_concat_in_place(&eval.msgs, &irtree.msgs); - if(E_InterpretationCode_Good < eval.code && eval.code < E_InterpretationCode_COUNT) - { - e_msg(arena, &eval.msgs, E_MsgKind_InterpretationError, 0, e_interpretation_code_display_strings[eval.code]); - } - return eval; -} - -internal E_Eval -e_eval_from_string(Arena *arena, String8 string) -{ - E_TokenArray tokens = e_token_array_from_text(arena, string); - E_Parse parse = e_parse_expr_from_text_tokens(arena, string, &tokens); - E_Eval eval = e_eval_from_expr(arena, parse.expr); - e_msg_list_concat_in_place(&eval.msgs, &parse.msgs); - return eval; -} - -internal E_Eval -e_autoresolved_eval_from_eval(E_Eval eval) -{ - if(e_parse_ctx && - e_interpret_ctx && - e_parse_ctx->modules_count > 0 && - e_interpret_ctx->module_base != 0 && - (e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_S64)) || - e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_U64)) || - e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_S32)) || - e_type_key_match(eval.type_key, e_type_key_basic(E_TypeKind_U32)))) - { - U64 vaddr = eval.value.u64; - U64 voff = vaddr - e_interpret_ctx->module_base[0]; - RDI_Parsed *rdi = e_parse_ctx->primary_module->rdi; - RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); - RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); - RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); - U32 string_idx = 0; - if(string_idx == 0) { string_idx = procedure->name_string_idx; } - if(string_idx == 0) { string_idx = gvar->name_string_idx; } - if(string_idx != 0) - { - eval.type_key = e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, e_type_key_basic(E_TypeKind_Void), 0); - } - } - return eval; -} - -internal E_Eval -e_dynamically_typed_eval_from_eval(E_Eval eval) -{ - E_TypeKey type_key = eval.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - if(e_type_state != 0 && - e_interpret_ctx != 0 && - e_interpret_ctx->space_read != 0 && - e_interpret_ctx->module_base != 0 && - type_kind == E_TypeKind_Ptr) - { - Temp scratch = scratch_begin(0, 0); - E_TypeKey ptee_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(type_key))); - E_TypeKind ptee_type_kind = e_type_kind_from_key(ptee_type_key); - if(ptee_type_kind == E_TypeKind_Struct || ptee_type_kind == E_TypeKind_Class) - { - E_Type *ptee_type = e_type_from_key(scratch.arena, ptee_type_key); - B32 has_vtable = 0; - for(U64 idx = 0; idx < ptee_type->count; idx += 1) - { - if(ptee_type->members[idx].kind == E_MemberKind_VirtualMethod) - { - has_vtable = 1; - break; - } - } - if(has_vtable) - { - U64 ptr_vaddr = eval.value.u64; - U64 addr_size = e_type_byte_size_from_key(e_type_unwrap(type_key)); - U64 class_base_vaddr = 0; - U64 vtable_vaddr = 0; - if(e_space_read(eval.space, &class_base_vaddr, r1u64(ptr_vaddr, ptr_vaddr+addr_size)) && - e_space_read(eval.space, &vtable_vaddr, r1u64(class_base_vaddr, class_base_vaddr+addr_size))) - { - Arch arch = e_type_state->ctx->primary_module->arch; - U32 rdi_idx = 0; - RDI_Parsed *rdi = 0; - U64 module_base = 0; - for(U64 idx = 0; idx < e_type_state->ctx->modules_count; idx += 1) - { - if(contains_1u64(e_type_state->ctx->modules[idx].vaddr_range, vtable_vaddr)) - { - arch = e_type_state->ctx->modules[idx].arch; - rdi_idx = (U32)idx; - rdi = e_type_state->ctx->modules[idx].rdi; - module_base = e_type_state->ctx->modules[idx].vaddr_range.min; - break; - } - } - if(rdi != 0) - { - U64 vtable_voff = vtable_vaddr - module_base; - U64 global_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, vtable_voff); - RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, global_idx); - if(global_var->link_flags & RDI_LinkFlag_TypeScoped) - { - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, global_var->container_idx); - RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, rdi_idx); - E_TypeKey ptr_to_derived_type_key = e_type_key_cons_ptr(arch, derived_type_key, 0); - eval.type_key = ptr_to_derived_type_key; - } - } - } - } - } - scratch_end(scratch); - } - return eval; -} - -internal E_Eval -e_value_eval_from_eval(E_Eval eval) -{ - ProfBeginFunction(); - if(eval.mode == E_Mode_Offset) - { - E_TypeKey type_key = e_type_unwrap(eval.type_key); - E_TypeKind type_kind = e_type_kind_from_key(type_key); - if(type_kind == E_TypeKind_Array) - { - eval.mode = E_Mode_Value; - } - else - { - U64 type_byte_size = e_type_byte_size_from_key(type_key); - Rng1U64 value_vaddr_range = r1u64(eval.value.u64, eval.value.u64 + type_byte_size); - MemoryZeroStruct(&eval.value); - if(!e_type_key_match(type_key, e_type_key_zero()) && - type_byte_size <= sizeof(E_Value) && - e_space_read(eval.space, &eval.value, value_vaddr_range)) - { - eval.mode = E_Mode_Value; - - // rjf: mask&shift, for bitfields - if(type_kind == E_TypeKind_Bitfield && type_byte_size <= sizeof(U64)) - { - Temp scratch = scratch_begin(0, 0); - E_Type *type = e_type_from_key(scratch.arena, type_key); - U64 valid_bits_mask = 0; - for(U64 idx = 0; idx < type->count; idx += 1) - { - valid_bits_mask |= (1ull<> type->off; - eval.value.u64 = eval.value.u64 & valid_bits_mask; - eval.type_key = type->direct_type_key; - scratch_end(scratch); - } - - // rjf: manually sign-extend - switch(type_kind) - { - default: break; - case E_TypeKind_Char8: - case E_TypeKind_S8: {eval.value.s64 = (S64)*((S8 *)&eval.value.u64);}break; - case E_TypeKind_Char16: - case E_TypeKind_S16: {eval.value.s64 = (S64)*((S16 *)&eval.value.u64);}break; - case E_TypeKind_Char32: - case E_TypeKind_S32: {eval.value.s64 = (S64)*((S32 *)&eval.value.u64);}break; - } - } - } - } - ProfEnd(); - return eval; -} - -internal E_Eval -e_element_eval_from_array_eval_index(E_Eval eval, U64 index) -{ - E_Eval result = {0}; - result.mode = eval.mode; - result.space = eval.space; - result.type_key = e_type_direct_from_key(eval.type_key); - result.code = eval.code; - result.msgs = eval.msgs; - U64 element_size = e_type_byte_size_from_key(result.type_key); - switch(eval.mode) - { - default:{}break; - case E_Mode_Value: - if(element_size <= sizeof(E_Value) && - index < sizeof(E_Value)/element_size) - { - MemoryCopy((U8 *)(&result.value.u512[0]), - (U8 *)(&eval.value.u512[0]) + index*element_size, - element_size); - }break; - case E_Mode_Offset: - { - result.value.u64 = eval.value.u64 + element_size*index; - }break; - } - return result; -} - -internal E_Eval -e_member_eval_from_eval_member_name(E_Eval eval, String8 member_name) -{ - E_Eval result = {0}; - { - E_Member member = e_type_member_from_key_name__cached(eval.type_key, member_name); - if(member.kind != E_MemberKind_Null) - { - result.mode = eval.mode; - result.space = eval.space; - result.type_key = member.type_key; - result.code = eval.code; - result.msgs = eval.msgs; - switch(eval.mode) - { - default:{}break; - case E_Mode_Value: - if(member.off < sizeof(eval.value)) - { - U64 member_size = e_type_byte_size_from_key(member.type_key); - MemoryCopy((U8 *)(&result.value.u512[0]), - (U8 *)(&eval.value.u512[0]) + member.off, - Min(member_size, sizeof(eval.value) - member.off)); - }break; - case E_Mode_Offset: - { - result.value.u64 = eval.value.u64 + member.off; - }break; - } - } - } - return result; -} diff --git a/src/eval/eval_bundles.h b/src/eval/eval_bundles.h deleted file mode 100644 index 957ff123..00000000 --- a/src/eval/eval_bundles.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef EVAL_BUNDLES_H -#define EVAL_BUNDLES_H - -//////////////////////////////// -//~ rjf: Bundled Evaluation Path Types - -typedef struct E_Eval E_Eval; -struct E_Eval -{ - E_Value value; - E_Mode mode; - E_Space space; - E_Expr *expr; - E_TypeKey type_key; - E_InterpretationCode code; - E_MsgList msgs; -}; - -//////////////////////////////// -//~ rjf: Bundled Evaluation Functions - -internal E_Eval e_eval_from_expr(Arena *arena, E_Expr *expr); -internal E_Eval e_eval_from_string(Arena *arena, String8 string); -internal E_Eval e_autoresolved_eval_from_eval(E_Eval eval); -internal E_Eval e_dynamically_typed_eval_from_eval(E_Eval eval); -internal E_Eval e_value_eval_from_eval(E_Eval eval); -internal E_Eval e_element_eval_from_array_eval_index(E_Eval eval, U64 index); -internal E_Eval e_member_eval_from_eval_member_name(E_Eval eval, String8 member_name); - -#endif // EVAL_BUNDLES_H diff --git a/src/eval/eval_core.c b/src/eval/eval_core.c index 0acb895e..158dc310 100644 --- a/src/eval/eval_core.c +++ b/src/eval/eval_core.c @@ -7,42 +7,147 @@ #include "eval/generated/eval.meta.c" //////////////////////////////// -//~ rjf: Basic Helper Functions +//~ rjf: Basic Helpers + +#if !defined(XXH_IMPLEMENTATION) +# define XXH_IMPLEMENTATION +# define XXH_STATIC_LINKING_ONLY +# include "third_party/xxHash/xxhash.h" +#endif internal U64 e_hash_from_string(U64 seed, String8 string) { - U64 result = seed; - for(U64 i = 0; i < string.size; i += 1) + U64 result = XXH3_64bits_withSeed(string.str, string.size, seed); + return result; +} + +//////////////////////////////// +//~ rjf: Expr Kind Enum Functions + +internal RDI_EvalOp +e_opcode_from_expr_kind(E_ExprKind kind) +{ + RDI_EvalOp result = RDI_EvalOp_Stop; + switch(kind) { - result = ((result << 5) + result) + string.str[i]; + case E_ExprKind_Neg: result = RDI_EvalOp_Neg; break; + case E_ExprKind_LogNot: result = RDI_EvalOp_LogNot; break; + case E_ExprKind_BitNot: result = RDI_EvalOp_BitNot; break; + case E_ExprKind_Mul: result = RDI_EvalOp_Mul; break; + case E_ExprKind_Div: result = RDI_EvalOp_Div; break; + case E_ExprKind_Mod: result = RDI_EvalOp_Mod; break; + case E_ExprKind_Add: result = RDI_EvalOp_Add; break; + case E_ExprKind_Sub: result = RDI_EvalOp_Sub; break; + case E_ExprKind_LShift: result = RDI_EvalOp_LShift; break; + case E_ExprKind_RShift: result = RDI_EvalOp_RShift; break; + case E_ExprKind_Less: result = RDI_EvalOp_Less; break; + case E_ExprKind_LsEq: result = RDI_EvalOp_LsEq; break; + case E_ExprKind_Grtr: result = RDI_EvalOp_Grtr; break; + case E_ExprKind_GrEq: result = RDI_EvalOp_GrEq; break; + case E_ExprKind_EqEq: result = RDI_EvalOp_EqEq; break; + case E_ExprKind_NtEq: result = RDI_EvalOp_NtEq; break; + case E_ExprKind_BitAnd: result = RDI_EvalOp_BitAnd; break; + case E_ExprKind_BitXor: result = RDI_EvalOp_BitXor; break; + case E_ExprKind_BitOr: result = RDI_EvalOp_BitOr; break; + case E_ExprKind_LogAnd: result = RDI_EvalOp_LogAnd; break; + case E_ExprKind_LogOr: result = RDI_EvalOp_LogOr; break; } return result; } +internal B32 +e_expr_kind_is_comparison(E_ExprKind kind) +{ + B32 result = 0; + switch(kind) + { + default:{}break; + case E_ExprKind_EqEq: + case E_ExprKind_NtEq: + case E_ExprKind_Less: + case E_ExprKind_Grtr: + case E_ExprKind_LsEq: + case E_ExprKind_GrEq: + { + result = 1; + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: Key Type Functions + +internal B32 +e_key_match(E_Key a, E_Key b) +{ + B32 result = (a.u64 == b.u64); + return result; +} + +internal E_Key +e_key_zero(void) +{ + E_Key key = {0}; + return key; +} + +//////////////////////////////// +//~ rjf: Type Key Type Functions + +internal void +e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key) +{ + E_TypeKeyNode *n = push_array(arena, E_TypeKeyNode, 1); + n->v = key; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal void +e_type_key_list_push_front(Arena *arena, E_TypeKeyList *list, E_TypeKey key) +{ + E_TypeKeyNode *n = push_array(arena, E_TypeKeyNode, 1); + n->v = key; + SLLQueuePushFront(list->first, list->last, n); + list->count += 1; +} + +internal E_TypeKeyList +e_type_key_list_copy(Arena *arena, E_TypeKeyList *src) +{ + E_TypeKeyList dst = {0}; + for(E_TypeKeyNode *n = src->first; n != 0; n = n->next) + { + e_type_key_list_push(arena, &dst, n->v); + } + return dst; +} + //////////////////////////////// //~ rjf: Message Functions internal void -e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, String8 text) +e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, String8 text) { E_Msg *msg = push_array(arena, E_Msg, 1); SLLQueuePush(msgs->first, msgs->last, msg); msgs->count += 1; msgs->max_kind = Max(kind, msgs->max_kind); msg->kind = kind; - msg->location = location; + msg->range = range; msg->text = text; } internal void -e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, char *fmt, ...) +e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, char *fmt, ...) { va_list args; va_start(args, fmt); String8 text = push_str8fv(arena, fmt, args); va_end(args); - e_msg(arena, msgs, kind, location, text); + e_msg(arena, msgs, kind, range, text); } internal void @@ -62,6 +167,17 @@ e_msg_list_concat_in_place(E_MsgList *dst, E_MsgList *to_push) MemoryZeroStruct(to_push); } +internal E_MsgList +e_msg_list_copy(Arena *arena, E_MsgList *src) +{ + E_MsgList dst = {0}; + for(E_Msg *msg = src->first; msg != 0; msg = msg->next) + { + e_msg(arena, &dst, msg->kind, msg->range, msg->text); + } + return dst; +} + //////////////////////////////// //~ rjf: Space Functions @@ -72,3 +188,1215 @@ e_space_make(E_SpaceKind kind) space.kind = kind; return space; } + +//////////////////////////////// +//~ rjf: Map Functions + +//- rjf: string -> num + +internal E_String2NumMap +e_string2num_map_make(Arena *arena, U64 slot_count) +{ + E_String2NumMap map = {0}; + map.slots_count = slot_count; + map.slots = push_array(arena, E_String2NumMapSlot, map.slots_count); + return map; +} + +internal void +e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num) +{ + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + E_String2NumMapNode *existing_node = 0; + for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) + { + if(str8_match(node->string, string, 0) && node->num == num) + { + existing_node = node; + break; + } + } + if(existing_node == 0) + { + E_String2NumMapNode *node = push_array(arena, E_String2NumMapNode, 1); + SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); + SLLQueuePush_N(map->first, map->last, node, order_next); + node->string = push_str8_copy(arena, string); + node->num = num; + map->node_count += 1; + } +} + +internal U64 +e_num_from_string(E_String2NumMap *map, String8 string) +{ + U64 num = 0; + if(map->slots_count != 0) + { + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + E_String2NumMapNode *existing_node = 0; + for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) + { + if(str8_match(node->string, string, 0)) + { + existing_node = node; + break; + } + } + if(existing_node != 0) + { + num = existing_node->num; + } + } + return num; +} + +internal E_String2NumMapNodeArray +e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map) +{ + E_String2NumMapNodeArray result = {0}; + result.count = map->node_count; + result.v = push_array(arena, E_String2NumMapNode *, result.count); + U64 idx = 0; + for(E_String2NumMapNode *n = map->first; n != 0; n = n->order_next, idx += 1) + { + result.v[idx] = n; + } + return result; +} + +internal int +e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b) +{ + int result = 0; + if(a[0]->num < b[0]->num) + { + result = -1; + } + else if(a[0]->num > b[0]->num) + { + result = +1; + } + return result; +} + +internal void +e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array) +{ + quick_sort(array->v, array->count, sizeof(array->v[0]), e_string2num_map_node_qsort_compare__num_ascending); +} + +//- rjf: string -> expr + +internal E_String2ExprMap +e_string2expr_map_make(Arena *arena, U64 slot_count) +{ + E_String2ExprMap map = {0}; + map.slots_count = slot_count; + map.slots = push_array(arena, E_String2ExprMapSlot, map.slots_count); + return map; +} + +internal void +e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr) +{ + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + E_String2ExprMapNode *existing_node = 0; + for(E_String2ExprMapNode *node = map->slots[slot_idx].first; + node != 0; + node = node->hash_next) + { + if(str8_match(node->string, string, 0)) + { + existing_node = node; + break; + } + } + if(existing_node == 0) + { + E_String2ExprMapNode *node = push_array(arena, E_String2ExprMapNode, 1); + SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); + node->string = push_str8_copy(arena, string); + existing_node = node; + existing_node->expr = expr; + } +} + +internal void +e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string) +{ + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + for(E_String2ExprMapNode *node = map->slots[slot_idx].first; + node != 0; + node = node->hash_next) + { + if(str8_match(node->string, string, 0)) + { + node->poison_count += 1; + break; + } + } +} + +internal void +e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string) +{ + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + for(E_String2ExprMapNode *node = map->slots[slot_idx].first; + node != 0; + node = node->hash_next) + { + if(str8_match(node->string, string, 0) && node->poison_count > 0) + { + node->poison_count -= 1; + break; + } + } +} + +internal E_Expr * +e_string2expr_map_lookup(E_String2ExprMap *map, String8 string) +{ + E_Expr *expr = &e_expr_nil; + if(map->slots_count != 0) + { + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + E_String2ExprMapNode *existing_node = 0; + for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) + { + if(str8_match(node->string, string, 0) && node->poison_count == 0) + { + existing_node = node; + break; + } + } + if(existing_node != 0) + { + expr = existing_node->expr; + } + } + return expr; +} + +//- rjf: string -> type-key + +internal E_String2TypeKeyMap +e_string2typekey_map_make(Arena *arena, U64 slots_count) +{ + E_String2TypeKeyMap map = {0}; + map.slots_count = slots_count; + map.slots = push_array(arena, E_String2TypeKeySlot, map.slots_count); + return map; +} + +internal void +e_string2typekey_map_insert(Arena *arena, E_String2TypeKeyMap *map, String8 string, E_TypeKey key) +{ + E_String2TypeKeyNode *n = push_array(arena, E_String2TypeKeyNode, 1); + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, n); + n->string = push_str8_copy(arena, string); + n->key = key; +} + +internal E_TypeKey +e_string2typekey_map_lookup(E_String2TypeKeyMap *map, String8 string) +{ + E_TypeKey key = zero_struct; + U64 hash = e_hash_from_string(5381, string); + U64 slot_idx = hash%map->slots_count; + for(E_String2TypeKeyNode *n = map->slots[slot_idx].first; n != 0; n = n->next) + { + if(str8_match(n->string, string, 0)) + { + key = n->key; + break; + } + } + return key; +} + +//- rjf: auto hooks + +internal E_AutoHookMap +e_auto_hook_map_make(Arena *arena, U64 slots_count) +{ + E_AutoHookMap map = {0}; + map.slots_count = slots_count; + map.slots = push_array(arena, E_AutoHookSlot, map.slots_count); + return map; +} + +internal void +e_auto_hook_map_insert_new_(Arena *arena, E_AutoHookMap *map, E_AutoHookParams *params) +{ + // rjf: get type key + E_TypeKey type_key = params->type_key; + if(params->type_pattern.size != 0) + { + E_Parse parse = e_push_parse_from_string(arena, params->type_pattern); + type_key = e_type_key_from_expr(parse.expr); + } + + // rjf: get type pattern parts + String8List pattern_parts = {0}; + if(e_type_key_match(e_type_key_zero(), type_key)) + { + U8 pattern_split = '?'; + pattern_parts = str8_split(arena, params->type_pattern, &pattern_split, 1, StringSplitFlag_KeepEmpties); + } + + // rjf: if the type key is nonzero, *or* we have type patterns, then insert + // into map accordingle + if(!e_type_key_match(e_type_key_zero(), type_key) || + pattern_parts.node_count != 0) + { + E_AutoHookNode *node = push_array(arena, E_AutoHookNode, 1); + node->type_string = str8_skip_chop_whitespace(e_type_string_from_key(arena, type_key)); + node->type_pattern_parts = pattern_parts; + node->expr_string = push_str8_copy(arena, params->tag_expr_string); + if(!e_type_key_match(e_type_key_zero(), type_key)) + { + U64 hash = e_hash_from_string(5381, node->type_string); + U64 slot_idx = hash%map->slots_count; + SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); + } + else + { + SLLQueuePush_N(map->first_pattern, map->last_pattern, node, pattern_order_next); + } + } +} + +//////////////////////////////// +//~ rjf: Debug-Info-Driven Map Building Functions + +internal E_String2NumMap * +e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: gather scopes to walk + typedef struct Task Task; + struct Task + { + Task *next; + RDI_Scope *scope; + }; + Task *first_task = 0; + Task *last_task = 0; + + //- rjf: voff -> tightest scope + RDI_Scope *tightest_scope = 0; + { + U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + Task *task = push_array(scratch.arena, Task, 1); + task->scope = scope; + SLLQueuePush(first_task, last_task, task); + tightest_scope = scope; + } + + //- rjf: voff-1 -> scope + if(voff > 0) + { + U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff-1); + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + if(scope != tightest_scope) + { + Task *task = push_array(scratch.arena, Task, 1); + task->scope = scope; + SLLQueuePush(first_task, last_task, task); + } + } + + //- rjf: tightest scope -> walk up the tree & build tasks for each parent scope + if(tightest_scope != 0) + { + RDI_Scope *nil_scope = rdi_element_from_name_idx(rdi, Scopes, 0); + for(RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, tightest_scope->parent_scope_idx); + scope != 0 && scope != nil_scope; + scope = rdi_element_from_name_idx(rdi, Scopes, scope->parent_scope_idx)) + { + Task *task = push_array(scratch.arena, Task, 1); + task->scope = scope; + SLLQueuePush(first_task, last_task, task); + } + } + + //- rjf: build blank map + E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); + *map = e_string2num_map_make(arena, 1024); + + //- rjf: accumulate locals for all tasks + for(Task *task = first_task; task != 0; task = task->next) + { + RDI_Scope *scope = task->scope; + if(scope != 0) + { + U32 local_opl_idx = scope->local_first + scope->local_count; + for(U32 local_idx = scope->local_first; local_idx < local_opl_idx; local_idx += 1) + { + RDI_Local *local_var = rdi_element_from_name_idx(rdi, Locals, local_idx); + U64 local_name_size = 0; + U8 *local_name_str = rdi_string_from_idx(rdi, local_var->name_string_idx, &local_name_size); + String8 name = push_str8_copy(arena, str8(local_name_str, local_name_size)); + e_string2num_map_insert(arena, map, name, (U64)local_idx+1); + } + } + } + + scratch_end(scratch); + return map; +} + +internal E_String2NumMap * +e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) +{ + //- rjf: voff -> tightest scope + U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); + RDI_Scope *tightest_scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + + //- rjf: tightest scope -> procedure + U32 proc_idx = tightest_scope->proc_idx; + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); + + //- rjf: procedure -> udt + U32 udt_idx = procedure->container_idx; + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); + + //- rjf: build blank map + E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); + *map = e_string2num_map_make(arena, 64); + + //- rjf: udt -> fill member map + if(!(udt->flags & RDI_UDTFlag_EnumMembers)) + { + U64 data_member_num = 1; + for(U32 member_idx = udt->member_first; + member_idx < udt->member_first+udt->member_count; + member_idx += 1) + { + RDI_Member *m = rdi_element_from_name_idx(rdi, Members, member_idx); + if(m->kind == RDI_MemberKind_DataField) + { + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, m->name_string_idx, &name.size); + e_string2num_map_insert(arena, map, name, data_member_num); + data_member_num += 1; + } + } + } + + return map; +} + +//////////////////////////////// +//~ rjf: Cache Creation & Selection + +internal E_Cache * +e_cache_alloc(void) +{ + Arena *arena = arena_alloc(); + E_Cache *cache = push_array(arena, E_Cache, 1); + cache->arena = arena; + cache->arena_eval_start_pos = arena_pos(arena); + return cache; +} + +internal void +e_cache_release(E_Cache *cache) +{ + arena_release(cache->arena); +} + +internal void +e_select_cache(E_Cache *cache) +{ + e_cache = cache; +} + +//////////////////////////////// +//~ rjf: Evaluation Phase Markers + +internal void +e_select_base_ctx(E_BaseCtx *ctx) +{ + //- rjf: select base context + if(ctx->modules == 0) { ctx->modules = &e_module_nil; } + if(ctx->primary_module == 0) { ctx->primary_module = &e_module_nil; } + e_base_ctx = ctx; + + //- rjf: reset the evaluation cache + arena_pop_to(e_cache->arena, e_cache->arena_eval_start_pos); + e_cache->key_id_gen = 0; + e_cache->key_slots_count = 4096; + e_cache->key_slots = push_array(e_cache->arena, E_CacheSlot, e_cache->key_slots_count); + e_cache->string_slots_count = 4096; + e_cache->string_slots = push_array(e_cache->arena, E_CacheSlot, e_cache->string_slots_count); + e_cache->free_parent_node = 0; + e_cache->top_parent_node = 0; + e_cache->cons_id_gen = 0; + e_cache->cons_content_slots_count = 256; + e_cache->cons_key_slots_count = 256; + e_cache->cons_content_slots = push_array(e_cache->arena, E_ConsTypeSlot, e_cache->cons_content_slots_count); + e_cache->cons_key_slots = push_array(e_cache->arena, E_ConsTypeSlot, e_cache->cons_key_slots_count); + e_cache->member_cache_slots_count = 256; + e_cache->member_cache_slots = push_array(e_cache->arena, E_MemberCacheSlot, e_cache->member_cache_slots_count); + e_cache->enum_val_cache_slots_count = 256; + e_cache->enum_val_cache_slots = push_array(e_cache->arena, E_EnumValCacheSlot, e_cache->enum_val_cache_slots_count); + e_cache->type_cache_slots_count = 1024; + e_cache->type_cache_slots = push_array(e_cache->arena, E_TypeCacheSlot, e_cache->type_cache_slots_count); + e_cache->file_type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = str8_lit("file"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(file), + .access = E_TYPE_ACCESS_FUNCTION_NAME(file), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(file), + .range= E_TYPE_EXPAND_RANGE_FUNCTION_NAME(file), + }); + e_cache->folder_type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = str8_lit("folder"), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(folder), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(folder), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(folder), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(folder), + }); + e_cache->thread_ip_procedure = rdi_procedure_from_voff(e_base_ctx->primary_module->rdi, e_base_ctx->thread_ip_voff); + e_cache->used_expr_map = push_array(e_cache->arena, E_UsedExprMap, 1); + e_cache->used_expr_map->slots_count = 64; + e_cache->used_expr_map->slots = push_array(e_cache->arena, E_UsedExprSlot, e_cache->used_expr_map->slots_count); + e_cache->type_auto_hook_cache_map = push_array(e_cache->arena, E_TypeAutoHookCacheMap, 1); + e_cache->type_auto_hook_cache_map->slots_count = 256; + e_cache->type_auto_hook_cache_map->slots = push_array(e_cache->arena, E_TypeAutoHookCacheSlot, e_cache->type_auto_hook_cache_map->slots_count); + e_cache->string_id_gen = 0; + e_cache->string_id_map = push_array(e_cache->arena, E_StringIDMap, 1); + e_cache->string_id_map->id_slots_count = 1024; + e_cache->string_id_map->id_slots = push_array(e_cache->arena, E_StringIDSlot, e_cache->string_id_map->id_slots_count); + e_cache->string_id_map->hash_slots_count = 1024; + e_cache->string_id_map->hash_slots = push_array(e_cache->arena, E_StringIDSlot, e_cache->string_id_map->hash_slots_count); +} + +internal void +e_select_ir_ctx(E_IRCtx *ctx) +{ + if(ctx->regs_map == 0) { ctx->regs_map = &e_string2num_map_nil; } + if(ctx->reg_alias_map == 0) { ctx->reg_alias_map = &e_string2num_map_nil; } + if(ctx->locals_map == 0) { ctx->locals_map = &e_string2num_map_nil; } + if(ctx->member_map == 0) { ctx->member_map = &e_string2num_map_nil; } + if(ctx->macro_map == 0) { ctx->macro_map = push_array(e_cache->arena, E_String2ExprMap, 1); ctx->macro_map[0] = e_string2expr_map_make(e_cache->arena, 512); } + e_ir_ctx = ctx; +} + +//////////////////////////////// +//~ rjf: Cache Accessing Functions + +//- rjf: parent key stack + +internal E_Key +e_parent_key_push(E_Key key) +{ + E_Key top = {0}; + if(e_cache->top_parent_node != 0) + { + top = e_cache->top_parent_node->key; + } + E_CacheParentNode *n = e_cache->free_parent_node; + if(n != 0) + { + SLLStackPop(e_cache->free_parent_node); + } + else + { + n = push_array(e_cache->arena, E_CacheParentNode, 1); + } + SLLStackPush(e_cache->top_parent_node, n); + n->key = key; + return top; +} + +internal E_Key +e_parent_key_pop(void) +{ + E_CacheParentNode *n = e_cache->top_parent_node; + SLLStackPop(e_cache->top_parent_node); + SLLStackPush(e_cache->free_parent_node, n); + E_Key popped = n->key; + return popped; +} + +//- rjf: key construction + +internal E_Key +e_key_from_string(String8 string) +{ + E_Key parent_key = {0}; + if(e_cache->top_parent_node) + { + parent_key = e_cache->top_parent_node->key; + } + U64 hash = e_hash_from_string(parent_key.u64, string); + U64 slot_idx = hash%e_cache->string_slots_count; + E_CacheSlot *slot = &e_cache->string_slots[slot_idx]; + E_CacheNode *node = 0; + for(E_CacheNode *n = slot->first; n != 0; n = n->string_next) + { + if(e_key_match(parent_key, n->bundle.parent_key) && + str8_match(n->bundle.string, string, 0) && + (n->bundle.interpretation.space.kind == E_SpaceKind_Null || + e_space_gen(n->bundle.interpretation.space) == n->bundle.space_gen)) + { + node = n; + break; + } + } + if(node == 0) + { + e_cache->key_id_gen += 1; + E_Key key = {e_cache->key_id_gen}; + U64 key_hash = e_hash_from_string(5381, str8_struct(&key)); + U64 key_slot_idx = key_hash%e_cache->key_slots_count; + E_CacheSlot *key_slot = &e_cache->key_slots[key_slot_idx]; + node = push_array(e_cache->arena, E_CacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, string_next); + SLLQueuePush_N(key_slot->first, key_slot->last, node, key_next); + node->bundle.key = key; + node->bundle.parent_key = parent_key; + node->bundle.string = push_str8_copy(e_cache->arena, string); + } + return node->bundle.key; +} + +internal E_Key +e_key_from_stringf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + E_Key result = e_key_from_string(string); + va_end(args); + scratch_end(scratch); + return result; +} + +internal E_Key +e_key_from_expr(E_Expr *expr) +{ + Temp scratch = scratch_begin(0, 0); + String8 string = e_string_from_expr(scratch.arena, expr, str8_zero()); + E_Key key = e_key_from_string(string); + scratch_end(scratch); + return key; +} + +//- rjf: base key -> node helper + +internal E_CacheBundle * +e_cache_bundle_from_key(E_Key key) +{ + U64 hash = e_hash_from_string(5381, str8_struct(&key)); + U64 slot_idx = hash%e_cache->key_slots_count; + E_CacheSlot *slot = &e_cache->key_slots[slot_idx]; + E_CacheNode *node = 0; + for(E_CacheNode *n = slot->first; n != 0; n = n->key_next) + { + if(e_key_match(n->bundle.key, key)) + { + node = n; + break; + } + } + E_CacheBundle *bundle = &e_cache_bundle_nil; + if(node != 0) + { + bundle = &node->bundle; + } + return bundle; +} + +//- rjf: bundle -> pipeline stage outputs + +internal E_Parse +e_parse_from_bundle(E_CacheBundle *bundle) +{ + if(bundle != &e_cache_bundle_nil && !(bundle->flags & E_CacheBundleFlag_Parse)) + { + bundle->flags |= E_CacheBundleFlag_Parse; + bundle->parse = e_push_parse_from_string(e_cache->arena, bundle->string); + E_MsgList msgs_copy = e_msg_list_copy(e_cache->arena, &bundle->parse.msgs); + e_msg_list_concat_in_place(&bundle->msgs, &msgs_copy); + } + E_Parse parse = bundle->parse; + return parse; +} + +internal E_IRTreeAndType +e_irtree_from_bundle(E_CacheBundle *bundle) +{ + if(bundle != &e_cache_bundle_nil && !(bundle->flags & E_CacheBundleFlag_IRTree)) + { + bundle->flags |= E_CacheBundleFlag_IRTree; + E_IRTreeAndType parent = e_irtree_from_key(bundle->parent_key); + E_Parse parse = e_parse_from_bundle(bundle); + ProfScope("irtree generation for '%.*s'", str8_varg(bundle->string)) + { + bundle->irtree = e_push_irtree_and_type_from_expr(e_cache->arena, &parent, &e_default_identifier_resolution_rule, 0, 0, parse.expr); + } + E_MsgList msgs_copy = e_msg_list_copy(e_cache->arena, &bundle->irtree.msgs); + e_msg_list_concat_in_place(&bundle->msgs, &msgs_copy); + } + E_IRTreeAndType result = bundle->irtree; + return result; +} + +internal String8 +e_bytecode_from_bundle(E_CacheBundle *bundle) +{ + if(bundle != &e_cache_bundle_nil && !(bundle->flags & E_CacheBundleFlag_Bytecode)) + { + bundle->flags |= E_CacheBundleFlag_Bytecode; + Temp scratch = scratch_begin(0, 0); + E_IRTreeAndType irtree = e_irtree_from_bundle(bundle); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree.root); + bundle->bytecode = e_bytecode_from_oplist(e_cache->arena, &oplist); + scratch_end(scratch); + } + String8 result = bundle->bytecode; + return result; +} + +internal E_Interpretation +e_interpretation_from_bundle(E_CacheBundle *bundle) +{ + if(bundle != &e_cache_bundle_nil && !(bundle->flags & E_CacheBundleFlag_Interpret)) + { + bundle->flags |= E_CacheBundleFlag_Interpret; + String8 bytecode = e_bytecode_from_bundle(bundle); + E_Interpretation interpret = e_interpret(bytecode); + if(E_InterpretationCode_Good < interpret.code && interpret.code < E_InterpretationCode_COUNT) + { + e_msg(e_cache->arena, &bundle->msgs, E_MsgKind_InterpretationError, r1u64(0, 0), e_interpretation_code_display_strings[interpret.code]); + } + bundle->interpretation = interpret; + bundle->space_gen = e_space_gen(interpret.space); + } + E_Interpretation interpret = bundle->interpretation; + return interpret; +} + +//- rjf: key -> full expression string + +internal String8 +e_full_expr_string_from_key(Arena *arena, E_Key key) +{ + E_CacheBundle *bundle = e_cache_bundle_from_key(key); + String8 result = push_str8_copy(arena, bundle->string); + if(!e_key_match(bundle->parent_key, e_key_zero())) + { + Temp scratch = scratch_begin(&arena, 1); + + //- NOTE(rjf): any individual eval does not contain all information for + // reconstructing an entire "flattened" expression string. this is because + // one evaluation may be e.g. `$.x`, in the context of `foobar`, and so + // the full thing is evaluated as equivalent to `foobar.x`. In that case, + // `foobar` is referred to via the "parent key" of the evaluation for + // `$.x`. + // + // because parents may themselves have parents, e.g. `$.x` in the context + // of `$` in the context of `foobar`, we need to apply the parent + // expression strings to each parent. + // + // we do this in order, from oldest ancestor to the passed-in evaluation + // key, so we gather the fully-resolved string at the end of the chain. + + //- rjf: gather the entire chain of parents (in order of deepest ancestor -> shallowest) + typedef struct ParentResolveTask ParentResolveTask; + struct ParentResolveTask + { + ParentResolveTask *next; + E_CacheBundle *bundle; + }; + ParentResolveTask start_task = {0, bundle}; + ParentResolveTask *first_task = &start_task; + ParentResolveTask *last_task = first_task; + for(ParentResolveTask *t = first_task, *next = 0; t != 0; (t = next, next = 0)) + { + if(!e_key_match(t->bundle->parent_key, e_key_zero())) + { + ParentResolveTask *task = push_array(scratch.arena, ParentResolveTask, 1); + SLLQueuePushFront(first_task, last_task, task); + task->bundle = e_cache_bundle_from_key(t->bundle->parent_key); + next = task; + } + } + + //- rjf: walk the chain of tasks, from deepest -> shallowest, producing a + // more fully resolved string at each step + String8 parent_string = {0}; + for(ParentResolveTask *t = first_task; t != 0; t = t->next) + { + E_Parse parse = e_parse_from_bundle(t->bundle); + parent_string = e_string_from_expr(scratch.arena, parse.expr, parent_string); + } + + //- rjf: take final string as result + result = push_str8_copy(arena, parent_string); + + scratch_end(scratch); + } + return result; +} + +//- rjf: comprehensive bundle + +internal E_Eval +e_eval_from_bundle(E_CacheBundle *bundle) +{ + E_Eval eval = + { + .key = bundle->key, + .parent_key= bundle->parent_key, + .string = bundle->string, + .expr = e_parse_from_bundle(bundle).expr, + .irtree = e_irtree_from_bundle(bundle), + .bytecode = e_bytecode_from_bundle(bundle), + .msgs = bundle->msgs, + }; + E_Interpretation interpretation = e_interpretation_from_bundle(bundle); + eval.code = interpretation.code; + eval.value = interpretation.value; + eval.space = interpretation.space; + return eval; +} + +internal E_Eval +e_value_eval_from_eval(E_Eval eval) +{ + ProfBeginFunction(); + if(eval.irtree.mode == E_Mode_Offset) + { + E_TypeKey type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind type_kind = e_type_kind_from_key(type_key); + if(type_kind == E_TypeKind_Array) + { + eval.irtree.mode = E_Mode_Value; + } + else + { + U64 type_byte_size = e_type_byte_size_from_key(type_key); + Rng1U64 value_vaddr_range = r1u64(eval.value.u64, eval.value.u64 + type_byte_size); + MemoryZeroStruct(&eval.value); + if(!e_type_key_match(type_key, e_type_key_zero()) && + type_byte_size <= sizeof(E_Value) && + e_space_read(eval.space, &eval.value, value_vaddr_range)) + { + eval.irtree.mode = E_Mode_Value; + + // rjf: mask&shift, for bitfields + if(type_kind == E_TypeKind_Bitfield && type_byte_size <= sizeof(U64)) + { + E_Type *type = e_type_from_key(type_key); + U64 valid_bits_mask = 0; + for(U64 idx = 0; idx < type->count; idx += 1) + { + valid_bits_mask |= (1ull<> type->off; + eval.value.u64 = eval.value.u64 & valid_bits_mask; + eval.irtree.type_key = type->direct_type_key; + } + + // rjf: manually sign-extend + switch(type_kind) + { + default: break; + case E_TypeKind_Char8: + case E_TypeKind_S8: {eval.value.s64 = (S64)*((S8 *)&eval.value.u64);}break; + case E_TypeKind_Char16: + case E_TypeKind_S16: {eval.value.s64 = (S64)*((S16 *)&eval.value.u64);}break; + case E_TypeKind_Char32: + case E_TypeKind_S32: {eval.value.s64 = (S64)*((S32 *)&eval.value.u64);}break; + } + } + } + } + ProfEnd(); + return eval; +} + +//- rjf: type key -> auto hooks + +internal E_ExprList +e_auto_hook_exprs_from_type_key(Arena *arena, E_TypeKey type_key) +{ + ProfBeginFunction(); + E_ExprList exprs = {0}; + if(e_ir_ctx != 0) + { + Temp scratch = scratch_begin(&arena, 1); + E_AutoHookMap *map = e_ir_ctx->auto_hook_map; + String8 type_string = str8_skip_chop_whitespace(e_type_string_from_key(scratch.arena, type_key)); + + //- rjf: gather exact-type-key-matches from the map + if(map != 0 && map->slots_count != 0) + { + U64 hash = e_hash_from_string(5381, type_string); + U64 slot_idx = hash%map->slots_count; + for(E_AutoHookNode *n = map->slots[slot_idx].first; n != 0; n = n->hash_next) + { + if(str8_match(n->type_string, type_string, 0)) + { + E_Expr *expr = e_parse_from_string(n->expr_string).expr; + e_expr_list_push(arena, &exprs, expr); + } + } + } + + //- rjf: gather fuzzy matches from all patterns in the map + if(map != 0 && map->first_pattern != 0) + { + for(E_AutoHookNode *auto_hook_node = map->first_pattern; + auto_hook_node != 0; + auto_hook_node = auto_hook_node->pattern_order_next) + { + B32 fits_this_type_string = 1; + U64 scan_pos = 0; + for(String8Node *n = auto_hook_node->type_pattern_parts.first; n != 0; n = n->next) + { + if(n->string.size == 0) + { + continue; + } + U64 pattern_part_pos = str8_find_needle(type_string, scan_pos, n->string, 0); + if(pattern_part_pos > scan_pos && n == auto_hook_node->type_pattern_parts.first) + { + fits_this_type_string = 0; + break; + } + if(pattern_part_pos >= type_string.size) + { + fits_this_type_string = 0; + break; + } + scan_pos = pattern_part_pos + n->string.size; + } + if(fits_this_type_string) + { + E_Expr *expr = e_parse_from_string(auto_hook_node->expr_string).expr; + e_expr_list_push(arena, &exprs, expr); + } + } + } + + scratch_end(scratch); + } + ProfEnd(); + return exprs; +} + +internal E_ExprList +e_auto_hook_exprs_from_type_key__cached(E_TypeKey type_key) +{ + E_ExprList exprs = {0}; + { + U64 hash = e_hash_from_string(5381, str8_struct(&type_key)); + U64 slot_idx = hash%e_cache->type_auto_hook_cache_map->slots_count; + E_TypeAutoHookCacheNode *node = 0; + for(E_TypeAutoHookCacheNode *n = e_cache->type_auto_hook_cache_map->slots[slot_idx].first; + n != 0; + n = n->next) + { + if(e_type_key_match(n->key, type_key)) + { + node = n; + } + } + if(node == 0) + { + node = push_array(e_cache->arena, E_TypeAutoHookCacheNode, 1); + SLLQueuePush(e_cache->type_auto_hook_cache_map->slots[slot_idx].first, e_cache->type_auto_hook_cache_map->slots[slot_idx].last, node); + node->key = type_key; + node->exprs = e_auto_hook_exprs_from_type_key(e_cache->arena, type_key); + } + exprs = node->exprs; + } + return exprs; +} + +//- rjf: string IDs + +internal U64 +e_id_from_string(String8 string) +{ + U64 hash = e_hash_from_string(5381, string); + U64 hash_slot_idx = hash%e_cache->string_id_map->hash_slots_count; + E_StringIDNode *node = 0; + for(E_StringIDNode *n = e_cache->string_id_map->hash_slots[hash_slot_idx].first; n != 0; n = n->hash_next) + { + if(str8_match(n->string, string, 0)) + { + node = n; + break; + } + } + if(node == 0) + { + e_cache->string_id_gen += 1; + U64 id = e_cache->string_id_gen; + U64 id_slot_idx = id%e_cache->string_id_map->id_slots_count; + node = push_array(e_cache->arena, E_StringIDNode, 1); + SLLQueuePush_N(e_cache->string_id_map->hash_slots[hash_slot_idx].first, e_cache->string_id_map->hash_slots[hash_slot_idx].last, node, hash_next); + SLLQueuePush_N(e_cache->string_id_map->id_slots[id_slot_idx].first, e_cache->string_id_map->hash_slots[id_slot_idx].last, node, id_next); + node->id = id; + node->string = push_str8_copy(e_cache->arena, string); + } + U64 result = node->id; + return result; +} + +internal String8 +e_string_from_id(U64 id) +{ + U64 id_slot_idx = id%e_cache->string_id_map->id_slots_count; + E_StringIDNode *node = 0; + for(E_StringIDNode *n = e_cache->string_id_map->id_slots[id_slot_idx].first; n != 0; n = n->id_next) + { + if(n->id == id) + { + node = n; + break; + } + } + String8 result = {0}; + if(node != 0) + { + result = node->string; + } + return result; +} + +//////////////////////////////// +//~ rjf: Key Extension Functions + +internal E_Key +e_key_wrap(E_Key key, String8 string) +{ + e_parent_key_push(key); + E_Key result = e_key_from_string(string); + e_parent_key_pop(); + return result; +} + +internal E_Key +e_key_wrapf(E_Key key, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + E_Key result = e_key_wrap(key, string); + va_end(args); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Eval Info Extraction + +internal U64 +e_base_offset_from_eval(E_Eval eval) +{ + if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)))) + { + eval = e_value_eval_from_eval(eval); + } + return eval.value.u64; +} + +internal U64 +e_range_size_from_eval(E_Eval eval) +{ + U64 result = KB(16); + { + E_TypeKey type_core = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind type_core_kind = e_type_kind_from_key(type_core); + B32 got_size = 0; + + // rjf: try getting size from expansions + if(!got_size) + { + E_TypeKey maybe_lens_type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_Meta); + E_TypeKind maybe_lens_type_kind = e_type_kind_from_key(maybe_lens_type_key); + if(maybe_lens_type_kind == E_TypeKind_Lens) + { + E_TypeExpandRule *expand_rule = e_expand_rule_from_type_key(maybe_lens_type_key); + if(expand_rule->info != 0) + { + Temp scratch = scratch_begin(0, 0); + U64 element_size = e_type_byte_size_from_key(e_type_key_unwrap(type_core, E_TypeUnwrapFlag_All)); + E_TypeExpandInfo expand_info = expand_rule->info(scratch.arena, eval, str8_zero()); + U64 new_result_maybe = expand_info.expr_count * element_size; + if(new_result_maybe != 0) + { + result = new_result_maybe; + got_size = 1; + } + scratch_end(scratch); + } + } + } + + // rjf: try getting size from intrinsic type (e.g. arrays/etc.) + if(!got_size) + { + if(type_core_kind == E_TypeKind_Array || + type_core_kind == E_TypeKind_Struct || + type_core_kind == E_TypeKind_Union || + type_core_kind == E_TypeKind_Class) + { + result = e_type_byte_size_from_key(type_core); + got_size = 1; + } + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Debug Functions + +internal String8 +e_debug_log_from_expr_string(Arena *arena, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + char *indent_spaces = " "; + String8List strings = {0}; + + //- rjf: begin expression + String8 expr_text = string; + str8_list_pushf(scratch.arena, &strings, "`%S`\n", expr_text); + + //- rjf: parse + E_Parse parse = e_push_parse_from_string(scratch.arena, expr_text); + { + typedef struct Task Task; + struct Task + { + Task *next; + E_Expr *expr; + S32 indent; + }; + E_TokenArray tokens = parse.tokens; + str8_list_pushf(scratch.arena, &strings, " tokens:\n"); + for EachIndex(idx, tokens.count) + { + E_Token token = tokens.v[idx]; + String8 token_string = str8_substr(expr_text, token.range); + str8_list_pushf(scratch.arena, &strings, " %S: `%S`\n", e_token_kind_strings[token.kind], token_string); + } + str8_list_pushf(scratch.arena, &strings, " expr:\n"); + Task start_task = {0, parse.expr, 2}; + Task *first_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) + { + E_Expr *expr = t->expr; + str8_list_pushf(scratch.arena, &strings, "%.*s%S", (int)t->indent*4, indent_spaces, e_expr_kind_strings[expr->kind]); + switch(expr->kind) + { + default:{}break; + case E_ExprKind_LeafU64: + { + str8_list_pushf(scratch.arena, &strings, " (%I64u)", expr->value.u64); + }break; + case E_ExprKind_LeafIdentifier: + { + str8_list_pushf(scratch.arena, &strings, " (`%S`)", expr->string); + }break; + } + str8_list_pushf(scratch.arena, &strings, "\n"); + Task *last_task = t; + for(E_Expr *child = expr->first; child != &e_expr_nil; child = child->next) + { + Task *task = push_array(scratch.arena, Task, 1); + task->next = last_task->next; + last_task->next = task; + task->expr = child; + task->indent = t->indent+1; + last_task = task; + } + } + } + + //- rjf: type + E_IRTreeAndType irtree = e_push_irtree_and_type_from_expr(scratch.arena, 0, &e_default_identifier_resolution_rule, 0, 0, parse.expr); + { + str8_list_pushf(scratch.arena, &strings, " type:\n"); + S32 indent = 2; + for(E_TypeKey type_key = irtree.type_key; + !e_type_key_match(e_type_key_zero(), type_key); + type_key = e_type_key_direct(type_key), + indent += 1) + { + E_Type *type = e_push_type_from_key(scratch.arena, type_key); + str8_list_pushf(scratch.arena, &strings, "%.*s%S\n", (int)indent*4, indent_spaces, e_type_kind_basic_string_table[type->kind]); + } + } + + //- rjf: irtree + { + typedef struct Task Task; + struct Task + { + Task *next; + E_IRNode *irnode; + S32 indent; + }; + str8_list_pushf(scratch.arena, &strings, " ir_tree:\n"); + Task start_task = {0, irtree.root, 2}; + Task *first_task = &start_task; + for(Task *t = first_task; t != 0; t = t->next) + { + E_IRNode *irnode = t->irnode; + str8_list_pushf(scratch.arena, &strings, "%.*s", (int)t->indent*4, indent_spaces); + switch(irnode->op) + { + default:{}break; +#define X(name) case RDI_EvalOp_##name:{str8_list_pushf(scratch.arena, &strings, #name);}break; + RDI_EvalOp_XList +#undef X + } + if(irnode->value.u64 != 0) + { + str8_list_pushf(scratch.arena, &strings, " (%I64u)", irnode->value.u64); + } + str8_list_pushf(scratch.arena, &strings, "\n"); + Task *last_task = t; + for(E_IRNode *child = irnode->first; child != &e_irnode_nil; child = child->next) + { + Task *task = push_array(scratch.arena, Task, 1); + task->next = last_task->next; + last_task->next = task; + task->irnode = child; + task->indent = t->indent+1; + last_task = task; + } + } + } + + str8_list_pushf(scratch.arena, &strings, "\n"); + + String8 result = str8_list_join(arena, &strings, 0); + scratch_end(scratch); + return result; +} diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index 29579d20..b88f742b 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -4,6 +4,15 @@ #ifndef EVAL_CORE_H #define EVAL_CORE_H +//////////////////////////////// +//~ rjf: Evaluation Key Type + +typedef struct E_Key E_Key; +struct E_Key +{ + U64 u64; +}; + //////////////////////////////// //~ rjf: Messages @@ -23,7 +32,7 @@ struct E_Msg { E_Msg *next; E_MsgKind kind; - void *location; + Rng1U64 range; String8 text; }; @@ -42,8 +51,8 @@ struct E_MsgList typedef union E_Value E_Value; union E_Value { - U64 u512[8]; - U64 u256[4]; + U512 u512; + U256 u256; U128 u128; U64 u64; U32 u32; @@ -55,6 +64,34 @@ union E_Value F32 f32; }; +//////////////////////////////// +//~ rjf: Bytecode Operation Types + +enum +{ + E_IRExtKind_Bytecode = RDI_EvalOp_COUNT, + E_IRExtKind_SetSpace, + E_IRExtKind_COUNT +}; + +typedef struct E_Op E_Op; +struct E_Op +{ + E_Op *next; + RDI_EvalOp opcode; + E_Value value; + String8 string; +}; + +typedef struct E_OpList E_OpList; +struct E_OpList +{ + E_Op *first; + E_Op *last; + U64 op_count; + U64 encoded_size; +}; + //////////////////////////////// //~ rjf: Operator Info @@ -74,6 +111,7 @@ struct E_OpInfo String8 pre; String8 sep; String8 post; + String8 chain; }; //////////////////////////////// @@ -93,7 +131,9 @@ typedef U64 E_SpaceKind; enum { E_SpaceKind_Null, + E_SpaceKind_File, E_SpaceKind_FileSystem, + E_SpaceKind_HashStoreKey, E_SpaceKind_FirstUserDefined, }; @@ -112,6 +152,85 @@ struct E_Space }; }; +//////////////////////////////// +//~ rjf: Implicit Type Graph Key Types + +typedef enum E_TypeKeyKind +{ + E_TypeKeyKind_Null, + E_TypeKeyKind_Basic, + E_TypeKeyKind_Ext, + E_TypeKeyKind_Cons, + E_TypeKeyKind_Reg, + E_TypeKeyKind_RegAlias, +} +E_TypeKeyKind; + +typedef struct E_TypeKey E_TypeKey; +struct E_TypeKey +{ + E_TypeKeyKind kind; + U32 u32[3]; + // [0] -> E_TypeKind (Basic, Cons, Ext); Arch (Reg, RegAlias) + // [1] -> Type Index In RDI (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) + // [2] -> RDI Index (Ext) +}; + +typedef struct E_TypeKeyNode E_TypeKeyNode; +struct E_TypeKeyNode +{ + E_TypeKeyNode *next; + E_TypeKey v; +}; + +typedef struct E_TypeKeyList E_TypeKeyList; +struct E_TypeKeyList +{ + E_TypeKeyNode *first; + E_TypeKeyNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/eval.meta.h" + +//////////////////////////////// +//~ rjf: Token Types + +typedef struct E_Token E_Token; +struct E_Token +{ + E_TokenKind kind; + Rng1U64 range; +}; + +typedef struct E_TokenChunkNode E_TokenChunkNode; +struct E_TokenChunkNode +{ + E_TokenChunkNode *next; + E_Token *v; + U64 count; + U64 cap; +}; + +typedef struct E_TokenChunkList E_TokenChunkList; +struct E_TokenChunkList +{ + E_TokenChunkNode *first; + E_TokenChunkNode *last; + U64 node_count; + U64 total_count; +}; + +typedef struct E_TokenArray E_TokenArray; +struct E_TokenArray +{ + E_Token *v; + U64 count; +}; + //////////////////////////////// //~ rjf: Evaluation Modes @@ -123,6 +242,325 @@ typedef enum E_Mode } E_Mode; +//////////////////////////////// +//~ rjf: Expression Tree Types + +typedef struct E_Expr E_Expr; +struct E_Expr +{ + E_Expr *first; + E_Expr *last; + E_Expr *next; + E_Expr *prev; + E_Expr *ref; + Rng1U64 range; + E_ExprKind kind; + E_Mode mode; + E_Space space; + E_TypeKey type_key; + E_Value value; + String8 string; + String8 qualifier; + String8 bytecode; +}; + +typedef struct E_ExprChain E_ExprChain; +struct E_ExprChain +{ + E_Expr *first; + E_Expr *last; +}; + +typedef struct E_ExprNode E_ExprNode; +struct E_ExprNode +{ + E_ExprNode *next; + E_Expr *v; +}; + +typedef struct E_ExprList E_ExprList; +struct E_ExprList +{ + E_ExprNode *first; + E_ExprNode *last; + U64 count; +}; + +typedef struct E_Parse E_Parse; +struct E_Parse +{ + E_TokenArray tokens; + E_Token *last_token; + E_Expr *expr; + E_Expr *last_expr; + E_MsgList msgs; +}; + +//////////////////////////////// +//~ rjf: IR Tree Types + +typedef struct E_IRNode E_IRNode; +struct E_IRNode +{ + E_IRNode *first; + E_IRNode *last; + E_IRNode *next; + RDI_EvalOp op; + E_Space space; + String8 string; + E_Value value; +}; + +typedef struct E_IRTreeAndType E_IRTreeAndType; +struct E_IRTreeAndType +{ + E_IRNode *root; + E_TypeKey type_key; + void *user_data; + E_Mode mode; + B32 auto_hook; + E_MsgList msgs; + E_IRTreeAndType *prev; +}; + +//////////////////////////////// +//~ rjf: Bytecode Interpretation Types + +typedef struct E_Interpretation E_Interpretation; +struct E_Interpretation +{ + E_Value value; + E_Space space; + E_InterpretationCode code; +}; + +//////////////////////////////// +//~ rjf: Evaluation Artifact Bundle + +typedef struct E_Eval E_Eval; +struct E_Eval +{ + E_Key key; + E_Key parent_key; + String8 string; + E_Expr *expr; + E_IRTreeAndType irtree; + String8 bytecode; + E_InterpretationCode code; + E_Value value; + E_Space space; + E_MsgList msgs; +}; + +//////////////////////////////// +//~ rjf: Full Extracted Type Information Types + +typedef enum E_MemberKind +{ + E_MemberKind_Null, + E_MemberKind_DataField, + E_MemberKind_StaticData, + E_MemberKind_Method, + E_MemberKind_StaticMethod, + E_MemberKind_VirtualMethod, + E_MemberKind_VTablePtr, + E_MemberKind_Base, + E_MemberKind_VirtualBase, + E_MemberKind_NestedType, + E_MemberKind_Padding, + E_MemberKind_COUNT +} +E_MemberKind; + +typedef U32 E_TypeFlags; +enum +{ + E_TypeFlag_Const = (1<<0), + E_TypeFlag_Volatile = (1<<1), + E_TypeFlag_IsPlainText = (1<<2), + E_TypeFlag_IsCodeText = (1<<3), + E_TypeFlag_IsPathText = (1<<4), + E_TypeFlag_IsNotText = (1<<5), + E_TypeFlag_EditableChildren = (1<<6), + E_TypeFlag_InheritedByMembers = (1<<7), + E_TypeFlag_InheritedByElements = (1<<8), + E_TypeFlag_ArrayLikeExpansion = (1<<9), + E_TypeFlag_StubSingleLineExpansion = (1<<10), +}; + +typedef struct E_Member E_Member; +struct E_Member +{ + E_MemberKind kind; + E_TypeKey type_key; + String8 name; + U64 off; + E_TypeKeyList inheritance_key_chain; +}; + +typedef struct E_MemberNode E_MemberNode; +struct E_MemberNode +{ + E_MemberNode *next; + E_Member v; +}; + +typedef struct E_MemberList E_MemberList; +struct E_MemberList +{ + E_MemberNode *first; + E_MemberNode *last; + U64 count; +}; + +typedef struct E_MemberArray E_MemberArray; +struct E_MemberArray +{ + E_Member *v; + U64 count; +}; + +typedef struct E_EnumVal E_EnumVal; +struct E_EnumVal +{ + String8 name; + U64 val; +}; + +typedef struct E_EnumValNode E_EnumValNode; +struct E_EnumValNode +{ + E_EnumValNode *next; + E_EnumVal v; +}; + +typedef struct E_EnumValList E_EnumValList; +struct E_EnumValList +{ + E_EnumValNode *first; + E_EnumValNode *last; + U64 count; +}; + +typedef struct E_EnumValArray E_EnumValArray; +struct E_EnumValArray +{ + E_EnumVal *v; + U64 count; +}; + +typedef struct E_IRExt E_IRExt; +struct E_IRExt +{ + void *user_data; +}; + +typedef struct E_TypeExpandInfo E_TypeExpandInfo; +struct E_TypeExpandInfo +{ + void *user_data; + U64 expr_count; +}; + +#define E_TYPE_IREXT_FUNCTION_SIG(name) E_IRExt name(Arena *arena, E_Expr *expr, E_IRTreeAndType *irtree) +#define E_TYPE_IREXT_FUNCTION_NAME(name) e_type_irext__##name +#define E_TYPE_IREXT_FUNCTION_DEF(name) internal E_TYPE_IREXT_FUNCTION_SIG(E_TYPE_IREXT_FUNCTION_NAME(name)) +typedef E_TYPE_IREXT_FUNCTION_SIG(E_TypeIRExtFunctionType); + +#define E_TYPE_ACCESS_FUNCTION_SIG(name) E_IRTreeAndType name(Arena *arena, E_IRTreeAndType *overridden, E_Expr *expr, E_IRTreeAndType *lhs_irtree) +#define E_TYPE_ACCESS_FUNCTION_NAME(name) e_type_access__##name +#define E_TYPE_ACCESS_FUNCTION_DEF(name) internal E_TYPE_ACCESS_FUNCTION_SIG(E_TYPE_ACCESS_FUNCTION_NAME(name)) +typedef E_TYPE_ACCESS_FUNCTION_SIG(E_TypeAccessFunctionType); + +#define E_TYPE_EXPAND_INFO_FUNCTION_SIG(name) E_TypeExpandInfo name(Arena *arena, E_Eval eval, String8 filter) +#define E_TYPE_EXPAND_INFO_FUNCTION_NAME(name) e_type_expand_info__##name +#define E_TYPE_EXPAND_INFO_FUNCTION_DEF(name) internal E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TYPE_EXPAND_INFO_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_INFO_FUNCTION_SIG(E_TypeExpandInfoFunctionType); + +#define E_TYPE_EXPAND_RANGE_FUNCTION_SIG(name) void name(Arena *arena, void *user_data, E_Eval eval, String8 filter, Rng1U64 idx_range, E_Eval *evals_out) +#define E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name) e_type_expand_range__##name +#define E_TYPE_EXPAND_RANGE_FUNCTION_DEF(name) internal E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_RANGE_FUNCTION_SIG(E_TypeExpandRangeFunctionType); + +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(name) U64 name(void *user_data, U64 num) +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name) e_type_expand_id_from_num__##name +#define E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(name) internal E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_SIG(E_TypeExpandIDFromNumFunctionType); + +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(name) U64 name(void *user_data, U64 id) +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name) e_type_expand_num_from_id__##name +#define E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(name) internal E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name)) +typedef E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_SIG(E_TypeExpandNumFromIDFunctionType); + +typedef struct E_TypeExpandRule E_TypeExpandRule; +struct E_TypeExpandRule +{ + E_TypeExpandInfoFunctionType *info; + E_TypeExpandRangeFunctionType *range; + E_TypeExpandIDFromNumFunctionType *id_from_num; + E_TypeExpandNumFromIDFunctionType *num_from_id; +}; + +typedef struct E_Type E_Type; +struct E_Type +{ + E_TypeKind kind; + E_TypeFlags flags; + String8 name; + U64 byte_size; + U64 count; + U64 depth; + U32 off; + Arch arch; + E_TypeKey direct_type_key; + E_TypeKey owner_type_key; + E_TypeKey *param_type_keys; + E_Member *members; + E_EnumVal *enum_vals; + E_Expr **args; + E_TypeIRExtFunctionType *irext; + E_TypeAccessFunctionType *access; + E_TypeExpandRule expand; +}; + +//////////////////////////////// +//~ rjf: Constructed Type Types + +typedef struct E_ConsTypeParams E_ConsTypeParams; +struct E_ConsTypeParams +{ + Arch arch; + E_TypeKind kind; + E_TypeFlags flags; + String8 name; + E_TypeKey direct_key; + U64 count; + U64 depth; + E_Member *members; + E_EnumVal *enum_vals; + E_Expr **args; + E_TypeIRExtFunctionType *irext; + E_TypeAccessFunctionType *access; + E_TypeExpandRule expand; +}; + +typedef struct E_ConsTypeNode E_ConsTypeNode; +struct E_ConsTypeNode +{ + E_ConsTypeNode *key_next; + E_ConsTypeNode *content_next; + E_TypeKey key; + E_ConsTypeParams params; + U64 byte_size; +}; + +typedef struct E_ConsTypeSlot E_ConsTypeSlot; +struct E_ConsTypeSlot +{ + E_ConsTypeNode *first; + E_ConsTypeNode *last; +}; + //////////////////////////////// //~ rjf: Modules @@ -135,27 +573,686 @@ struct E_Module E_Space space; }; +//////////////////////////////// +//~ rjf: String -> Num + +typedef struct E_String2NumMapNode E_String2NumMapNode; +struct E_String2NumMapNode +{ + E_String2NumMapNode *order_next; + E_String2NumMapNode *hash_next; + String8 string; + U64 num; +}; + +typedef struct E_String2NumMapNodeArray E_String2NumMapNodeArray; +struct E_String2NumMapNodeArray +{ + E_String2NumMapNode **v; + U64 count; +}; + +typedef struct E_String2NumMapSlot E_String2NumMapSlot; +struct E_String2NumMapSlot +{ + E_String2NumMapNode *first; + E_String2NumMapNode *last; +}; + +typedef struct E_String2NumMap E_String2NumMap; +struct E_String2NumMap +{ + U64 slots_count; + U64 node_count; + E_String2NumMapSlot *slots; + E_String2NumMapNode *first; + E_String2NumMapNode *last; +}; + +//////////////////////////////// +//~ rjf: String -> Expr + +typedef struct E_String2ExprMapNode E_String2ExprMapNode; +struct E_String2ExprMapNode +{ + E_String2ExprMapNode *hash_next; + String8 string; + E_Expr *expr; + U64 poison_count; +}; + +typedef struct E_String2ExprMapSlot E_String2ExprMapSlot; +struct E_String2ExprMapSlot +{ + E_String2ExprMapNode *first; + E_String2ExprMapNode *last; +}; + +typedef struct E_String2ExprMap E_String2ExprMap; +struct E_String2ExprMap +{ + U64 slots_count; + E_String2ExprMapSlot *slots; +}; + +//////////////////////////////// +//~ rjf: String -> Type Key Map Data Structure + +typedef struct E_String2TypeKeyNode E_String2TypeKeyNode; +struct E_String2TypeKeyNode +{ + E_String2TypeKeyNode *next; + String8 string; + E_TypeKey key; +}; + +typedef struct E_String2TypeKeySlot E_String2TypeKeySlot; +struct E_String2TypeKeySlot +{ + E_String2TypeKeyNode *first; + E_String2TypeKeyNode *last; +}; + +typedef struct E_String2TypeKeyMap E_String2TypeKeyMap; +struct E_String2TypeKeyMap +{ + U64 slots_count; + E_String2TypeKeySlot *slots; +}; + +//////////////////////////////// +//~ rjf: Type Pattern -> Hook Key Data Structure (Type Views) + +typedef struct E_AutoHookNode E_AutoHookNode; +struct E_AutoHookNode +{ + E_AutoHookNode *hash_next; + E_AutoHookNode *pattern_order_next; + String8 type_string; + String8List type_pattern_parts; + String8 expr_string; +}; + +typedef struct E_AutoHookSlot E_AutoHookSlot; +struct E_AutoHookSlot +{ + E_AutoHookNode *first; + E_AutoHookNode *last; +}; + +typedef struct E_AutoHookMap E_AutoHookMap; +struct E_AutoHookMap +{ + U64 slots_count; + E_AutoHookSlot *slots; + E_AutoHookNode *first_pattern; + E_AutoHookNode *last_pattern; +}; + +typedef struct E_AutoHookParams E_AutoHookParams; +struct E_AutoHookParams +{ + E_TypeKey type_key; + String8 type_pattern; + String8 tag_expr_string; +}; + +//////////////////////////////// +//~ rjf: Evaluation Context + +typedef U64 E_SpaceGenFunction(void *user_data, E_Space space); +typedef B32 E_SpaceRWFunction(void *user_data, E_Space space, void *out, Rng1U64 offset_range); + +//- rjf: base context + +typedef struct E_BaseCtx E_BaseCtx; +struct E_BaseCtx +{ + // rjf: instruction pointer info + U64 thread_ip_vaddr; + U64 thread_ip_voff; + E_Space thread_reg_space; + Arch thread_arch; + U64 thread_unwind_count; + + // rjf: modules + E_Module *modules; + U64 modules_count; + E_Module *primary_module; + + // rjf: space hooks + void *space_rw_user_data; + E_SpaceGenFunction *space_gen; + E_SpaceRWFunction *space_read; + E_SpaceRWFunction *space_write; +}; + +//- rjf: ir generation context + +typedef struct E_IRCtx E_IRCtx; +struct E_IRCtx +{ + E_String2NumMap *regs_map; + E_String2NumMap *reg_alias_map; + E_String2NumMap *locals_map; // (within `primary_module`) + E_String2NumMap *member_map; // (within `primary_module`) + E_String2ExprMap *macro_map; + E_AutoHookMap *auto_hook_map; +}; + +//////////////////////////////// +//~ rjf: Core Evaluation Cache Types + +//- rjf: unpacked type cache + +typedef struct E_TypeCacheNode E_TypeCacheNode; +struct E_TypeCacheNode +{ + E_TypeCacheNode *next; + E_TypeKey key; + E_Type *type; +}; + +typedef struct E_TypeCacheSlot E_TypeCacheSlot; +struct E_TypeCacheSlot +{ + E_TypeCacheNode *first; + E_TypeCacheNode *last; +}; + +//- rjf: member lookup cache types + +typedef struct E_MemberHashNode E_MemberHashNode; +struct E_MemberHashNode +{ + E_MemberHashNode *next; + U64 member_idx; +}; + +typedef struct E_MemberHashSlot E_MemberHashSlot; +struct E_MemberHashSlot +{ + E_MemberHashNode *first; + E_MemberHashNode *last; +}; + +typedef struct E_MemberFilterNode E_MemberFilterNode; +struct E_MemberFilterNode +{ + E_MemberFilterNode *next; + String8 filter; + E_MemberArray members_filtered; +}; + +typedef struct E_MemberFilterSlot E_MemberFilterSlot; +struct E_MemberFilterSlot +{ + E_MemberFilterNode *first; + E_MemberFilterNode *last; +}; + +typedef struct E_MemberCacheNode E_MemberCacheNode; +struct E_MemberCacheNode +{ + E_MemberCacheNode *next; + E_TypeKey key; + E_MemberArray members; + U64 member_hash_slots_count; + E_MemberHashSlot *member_hash_slots; + U64 member_filter_slots_count; + E_MemberFilterSlot *member_filter_slots; +}; + +typedef struct E_MemberCacheSlot E_MemberCacheSlot; +struct E_MemberCacheSlot +{ + E_MemberCacheNode *first; + E_MemberCacheNode *last; +}; + +//- rjf: enum val lookup cache types + +typedef struct E_EnumValHashNode E_EnumValHashNode; +struct E_EnumValHashNode +{ + E_EnumValHashNode *next; + U64 val_idx; +}; + +typedef struct E_EnumValHashSlot E_EnumValHashSlot; +struct E_EnumValHashSlot +{ + E_EnumValHashNode *first; + E_EnumValHashNode *last; +}; + +typedef struct E_EnumValFilterNode E_EnumValFilterNode; +struct E_EnumValFilterNode +{ + E_EnumValFilterNode *next; + String8 filter; + E_EnumValArray vals_filtered; +}; + +typedef struct E_EnumValFilterSlot E_EnumValFilterSlot; +struct E_EnumValFilterSlot +{ + E_EnumValFilterNode *first; + E_EnumValFilterNode *last; +}; + +typedef struct E_EnumValCacheNode E_EnumValCacheNode; +struct E_EnumValCacheNode +{ + E_EnumValCacheNode *next; + E_TypeKey key; + U64 val_hash_slots_count; + E_EnumValHashSlot *val_hash_slots; + U64 val_filter_slots_count; + E_EnumValFilterSlot *val_filter_slots; +}; + +typedef struct E_EnumValCacheSlot E_EnumValCacheSlot; +struct E_EnumValCacheSlot +{ + E_EnumValCacheNode *first; + E_EnumValCacheNode *last; +}; + +//- rjf: used expression map + +typedef struct E_UsedExprNode E_UsedExprNode; +struct E_UsedExprNode +{ + E_UsedExprNode *next; + E_UsedExprNode *prev; + E_Expr *expr; +}; + +typedef struct E_UsedExprSlot E_UsedExprSlot; +struct E_UsedExprSlot +{ + E_UsedExprNode *first; + E_UsedExprNode *last; +}; + +typedef struct E_UsedExprMap E_UsedExprMap; +struct E_UsedExprMap +{ + U64 slots_count; + E_UsedExprSlot *slots; +}; + +//- rjf: type key -> auto hook expression list cache + +typedef struct E_TypeAutoHookCacheNode E_TypeAutoHookCacheNode; +struct E_TypeAutoHookCacheNode +{ + E_TypeAutoHookCacheNode *next; + E_TypeKey key; + E_ExprList exprs; +}; + +typedef struct E_TypeAutoHookCacheSlot E_TypeAutoHookCacheSlot; +struct E_TypeAutoHookCacheSlot +{ + E_TypeAutoHookCacheNode *first; + E_TypeAutoHookCacheNode *last; +}; + +typedef struct E_TypeAutoHookCacheMap E_TypeAutoHookCacheMap; +struct E_TypeAutoHookCacheMap +{ + U64 slots_count; + E_TypeAutoHookCacheSlot *slots; +}; + +//- rjf: string ID cache + +typedef struct E_StringIDNode E_StringIDNode; +struct E_StringIDNode +{ + E_StringIDNode *hash_next; + E_StringIDNode *id_next; + U64 id; + String8 string; +}; + +typedef struct E_StringIDSlot E_StringIDSlot; +struct E_StringIDSlot +{ + E_StringIDNode *first; + E_StringIDNode *last; +}; + +typedef struct E_StringIDMap E_StringIDMap; +struct E_StringIDMap +{ + U64 id_slots_count; + E_StringIDSlot *id_slots; + U64 hash_slots_count; + E_StringIDSlot *hash_slots; +}; + +//- rjf: cache evaluation bundles + +typedef U32 E_CacheBundleFlags; +enum +{ + E_CacheBundleFlag_Parse = (1<<0), + E_CacheBundleFlag_IRTree = (1<<1), + E_CacheBundleFlag_Bytecode = (1<<2), + E_CacheBundleFlag_Interpret = (1<<3), +}; + +typedef struct E_CacheBundle E_CacheBundle; +struct E_CacheBundle +{ + E_CacheBundleFlags flags; + E_Key key; + E_Key parent_key; + String8 string; + E_Parse parse; + E_IRTreeAndType irtree; + String8 bytecode; + E_Interpretation interpretation; + U64 space_gen; + E_MsgList msgs; +}; + +typedef struct E_CacheNode E_CacheNode; +struct E_CacheNode +{ + E_CacheNode *string_next; + E_CacheNode *key_next; + E_CacheBundle bundle; +}; + +typedef struct E_CacheLookup E_CacheLookup; +struct E_CacheLookup +{ + E_CacheNode *node; + U64 hash; +}; + +typedef struct E_CacheSlot E_CacheSlot; +struct E_CacheSlot +{ + E_CacheNode *first; + E_CacheNode *last; +}; + +//- rjf: parent stack + +typedef struct E_CacheParentNode E_CacheParentNode; +struct E_CacheParentNode +{ + E_CacheParentNode *next; + E_Key key; +}; + +//- rjf: main cache state type + +typedef struct E_Cache E_Cache; +struct E_Cache +{ + //- rjf: root arena + Arena *arena; + U64 arena_eval_start_pos; + + //- rjf: key ID generation counter + U64 key_id_gen; + + //- rjf: key -> bundle, string -> bundle tables + U64 key_slots_count; + E_CacheSlot *key_slots; + U64 string_slots_count; + E_CacheSlot *string_slots; + + //- rjf: parent stack + E_CacheParentNode *top_parent_node; + E_CacheParentNode *free_parent_node; + + //- rjf: unpacked context + RDI_Procedure *thread_ip_procedure; + + //- rjf: [types] JIT-constructed types tables + U64 cons_id_gen; + U64 cons_content_slots_count; + U64 cons_key_slots_count; + E_ConsTypeSlot *cons_content_slots; + E_ConsTypeSlot *cons_key_slots; + + //- rjf: [types] build-in constructed type keys + E_TypeKey file_type_key; + E_TypeKey folder_type_key; + + //- rjf: [types] member cache table + U64 member_cache_slots_count; + E_MemberCacheSlot *member_cache_slots; + + //- rjf: [types] enum val cache table + U64 enum_val_cache_slots_count; + E_EnumValCacheSlot *enum_val_cache_slots; + + //- rjf: [types] unpacked type cache + U64 type_cache_slots_count; + E_TypeCacheSlot *type_cache_slots; + + //- rjf: [ir] ir gen options + B32 disallow_autohooks; + B32 disallow_chained_fastpaths; + + //- rjf: [ir] ir caches + E_UsedExprMap *used_expr_map; + E_TypeAutoHookCacheMap *type_auto_hook_cache_map; + + //- rjf: [ir] string ID cache + U64 string_id_gen; + E_StringIDMap *string_id_map; +}; + //////////////////////////////// //~ rjf: Generated Code #include "eval/generated/eval.meta.h" //////////////////////////////// -//~ rjf: Basic Helper Functions +//~ rjf: Globals + +read_only global E_String2NumMap e_string2num_map_nil = {0}; +read_only global E_String2ExprMap e_string2expr_map_nil = {0}; +read_only global E_Expr e_expr_nil = {&e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil}; +read_only global E_IRNode e_irnode_nil = {&e_irnode_nil, &e_irnode_nil, &e_irnode_nil}; +read_only global E_Eval e_eval_nil = {{0}, {0}, {0}, &e_expr_nil, {&e_irnode_nil}}; +read_only global E_Module e_module_nil = {&rdi_parsed_nil}; +read_only global E_CacheBundle e_cache_bundle_nil = {0, {0}, {0}, {0}, {{0}, 0, &e_expr_nil, &e_expr_nil}, {&e_irnode_nil}}; +thread_static E_BaseCtx *e_base_ctx = 0; +thread_static E_IRCtx *e_ir_ctx = 0; +thread_static E_Cache *e_cache = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers internal U64 e_hash_from_string(U64 seed, String8 string); #define e_value_u64(v) (E_Value){.u64 = (v)} +//////////////////////////////// +//~ rjf: Expr Kind Enum Functions + +internal RDI_EvalOp e_opcode_from_expr_kind(E_ExprKind kind); +internal B32 e_expr_kind_is_comparison(E_ExprKind kind); + +//////////////////////////////// +//~ rjf: Key Type Functions + +internal B32 e_key_match(E_Key a, E_Key b); +internal E_Key e_key_zero(void); + +//////////////////////////////// +//~ rjf: Type Key Type Functions + +internal void e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key); +internal void e_type_key_list_push_front(Arena *arena, E_TypeKeyList *list, E_TypeKey key); +internal E_TypeKeyList e_type_key_list_copy(Arena *arena, E_TypeKeyList *src); + //////////////////////////////// //~ rjf: Message Functions -internal void e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, String8 text); -internal void e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, void *location, char *fmt, ...); +internal void e_msg(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, String8 text); +internal void e_msgf(Arena *arena, E_MsgList *msgs, E_MsgKind kind, Rng1U64 range, char *fmt, ...); internal void e_msg_list_concat_in_place(E_MsgList *dst, E_MsgList *to_push); +internal E_MsgList e_msg_list_copy(Arena *arena, E_MsgList *src); //////////////////////////////// //~ rjf: Space Functions internal E_Space e_space_make(E_SpaceKind kind); +//////////////////////////////// +//~ rjf: Map Functions + +//- rjf: string -> num +internal E_String2NumMap e_string2num_map_make(Arena *arena, U64 slot_count); +internal void e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num); +internal U64 e_num_from_string(E_String2NumMap *map, String8 string); +internal E_String2NumMapNodeArray e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map); +internal int e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b); +internal void e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array); + +//- rjf: string -> expr +internal E_String2ExprMap e_string2expr_map_make(Arena *arena, U64 slot_count); +internal void e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr); +internal void e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string); +internal void e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string); +internal E_Expr *e_string2expr_map_lookup(E_String2ExprMap *map, String8 string); + +//- rjf: string -> type-key +internal E_String2TypeKeyMap e_string2typekey_map_make(Arena *arena, U64 slots_count); +internal void e_string2typekey_map_insert(Arena *arena, E_String2TypeKeyMap *map, String8 string, E_TypeKey key); +internal E_TypeKey e_string2typekey_map_lookup(E_String2TypeKeyMap *map, String8 string); + +//- rjf: auto hooks +internal E_AutoHookMap e_auto_hook_map_make(Arena *arena, U64 slots_count); +internal void e_auto_hook_map_insert_new_(Arena *arena, E_AutoHookMap *map, E_AutoHookParams *params); +#define e_auto_hook_map_insert_new(arena, map, ...) e_auto_hook_map_insert_new_((arena), (map), &(E_AutoHookParams){.type_key = zero_struct, __VA_ARGS__}) + +//////////////////////////////// +//~ rjf: Debug-Info-Driven Map Building Functions + +internal E_String2NumMap *e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); +internal E_String2NumMap *e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); + +//////////////////////////////// +//~ rjf: Cache Creation & Selection + +internal E_Cache *e_cache_alloc(void); +internal void e_cache_release(E_Cache *cache); +internal void e_select_cache(E_Cache *cache); + +//////////////////////////////// +//~ rjf: Evaluation Phase Markers + +internal void e_select_base_ctx(E_BaseCtx *ctx); +internal void e_select_ir_ctx(E_IRCtx *ctx); + +//////////////////////////////// +//~ rjf: Base Cache Accessing Functions +// +// The cache uses a unique keying mechanism to refer to some evaluation at +// many layers of analysis. +// +// key +// ________________________________________________ +// / / | \ +// text -> expression -> ir tree and type -> interpretation result +// +// Each one of these calls refers to one stage in this pipeline. The cache will +// only compute what is needed on-demand. If you ask for the full evaluation, +// which is a bundle of artifacts at all layers of analysis, then all stages +// will be computed. +// +// One wrinkle here is that the IR tree generation stage is implicitly +// parameterized by the "overridden" IR tree - this is to enable "parent +// expressions", e.g. `$.x`, or simply `x` assuming `foo` has such a member, +// in the context of some struct `foo` evaluates to the same thing as `foo.x`. +// So even though the primary API shape is based around singular keys, the +// "parent key stack" also implicitly parameterizes all of these (partly +// because it is not relevant in 99% of cases). + +//- rjf: parent key stack +internal E_Key e_parent_key_push(E_Key key); +internal E_Key e_parent_key_pop(void); +#define E_ParentKey(key) DeferLoop(e_parent_key_push(key), e_parent_key_pop()) + +//- rjf: key construction +internal E_Key e_key_from_string(String8 string); +internal E_Key e_key_from_stringf(char *fmt, ...); +internal E_Key e_key_from_expr(E_Expr *expr); + +//- rjf: base key -> bundle helper +internal E_CacheBundle *e_cache_bundle_from_key(E_Key key); + +//- rjf: bundle -> pipeline stage outputs +internal E_Parse e_parse_from_bundle(E_CacheBundle *bundle); +internal E_IRTreeAndType e_irtree_from_bundle(E_CacheBundle *bundle); +internal String8 e_bytecode_from_bundle(E_CacheBundle *bundle); +internal E_Interpretation e_interpretation_from_bundle(E_CacheBundle *bundle); +#define e_parse_from_key(key) e_parse_from_bundle(e_cache_bundle_from_key(key)) +#define e_irtree_from_key(key) e_irtree_from_bundle(e_cache_bundle_from_key(key)) +#define e_bytecode_from_key(key) e_bytecode_from_bundle(e_cache_bundle_from_key(key)) +#define e_interpretation_from_key(key) e_interpretation_from_bundle(e_cache_bundle_from_key(key)) + +//- rjf: key -> full expression string +internal String8 e_full_expr_string_from_key(Arena *arena, E_Key key); + +//- rjf: comprehensive bundle +internal E_Eval e_eval_from_bundle(E_CacheBundle *bundle); +internal E_Eval e_value_eval_from_eval(E_Eval eval); +#define e_eval_from_key(key) e_eval_from_bundle(e_cache_bundle_from_key(key)) +#define e_value_from_key(key) (e_value_eval_from_eval(e_eval_from_key(key)).value) + +//- rjf: string-based helpers +#define e_parse_from_string(string) e_parse_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) +#define e_irtree_from_string(string) e_irtree_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) +#define e_bytecode_from_string(string) e_bytecode_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) +#define e_interpretation_from_string(string) e_interpretation_from_bundle(e_cache_bundle_from_key(e_key_from_string(string))) +#define e_eval_from_string(string) e_eval_from_key(e_key_from_string(string)) +#define e_eval_from_stringf(...) e_eval_from_key(e_key_from_stringf(__VA_ARGS__)) +#define e_value_from_string(string) e_value_eval_from_eval(e_eval_from_string(string)).value +#define e_value_from_stringf(...) e_value_eval_from_eval(e_eval_from_stringf(__VA_ARGS__)).value + +//- rjf: expr-based helpers +#define e_eval_from_expr(expr) e_eval_from_key(e_key_from_expr(expr)) +#define e_value_from_expr(expr) e_value_eval_from_eval(e_eval_from_expr(expr)).value + +//- rjf: type key -> auto hooks +internal E_ExprList e_auto_hook_exprs_from_type_key(Arena *arena, E_TypeKey type_key); +internal E_ExprList e_auto_hook_exprs_from_type_key__cached(E_TypeKey type_key); + +//- rjf: string IDs +internal U64 e_id_from_string(String8 string); +internal String8 e_string_from_id(U64 id); + +//////////////////////////////// +//~ rjf: Key Extension Functions + +internal E_Key e_key_wrap(E_Key key, String8 string); +internal E_Key e_key_wrapf(E_Key key, char *fmt, ...); + +//- rjf: eval-based helpers +#define e_eval_wrap(eval, string) e_eval_from_key(e_key_wrap((eval).key, (string))) +#define e_eval_wrapf(eval, ...) e_eval_from_key(e_key_wrapf((eval).key, __VA_ARGS__)) + +//////////////////////////////// +//~ rjf: Eval Info Extraction + +internal U64 e_base_offset_from_eval(E_Eval eval); +internal U64 e_range_size_from_eval(E_Eval eval); + +//////////////////////////////// +//~ rjf: Debug Functions + +internal String8 e_debug_log_from_expr_string(Arena *arena, String8 string); + #endif // EVAL_CORE_H diff --git a/src/eval/eval_inc.c b/src/eval/eval_inc.c index c4d2222c..cdfed3bd 100644 --- a/src/eval/eval_inc.c +++ b/src/eval/eval_inc.c @@ -6,4 +6,3 @@ #include "eval/eval_parse.c" #include "eval/eval_ir.c" #include "eval/eval_interpret.c" -#include "eval/eval_bundles.c" diff --git a/src/eval/eval_inc.h b/src/eval/eval_inc.h index 2c46335b..bb03829f 100644 --- a/src/eval/eval_inc.h +++ b/src/eval/eval_inc.h @@ -9,6 +9,5 @@ #include "eval/eval_parse.h" #include "eval/eval_ir.h" #include "eval/eval_interpret.h" -#include "eval/eval_bundles.h" #endif // EVAL_INC_H diff --git a/src/eval/eval_interpret.c b/src/eval/eval_interpret.c index c7c824a4..5af37288 100644 --- a/src/eval/eval_interpret.c +++ b/src/eval/eval_interpret.c @@ -4,21 +4,68 @@ //////////////////////////////// //~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) -internal E_InterpretCtx * -e_selected_interpret_ctx(void) -{ - return e_interpret_ctx; -} - internal void -e_select_interpret_ctx(E_InterpretCtx *ctx) +e_select_interpret_ctx(E_InterpretCtx *ctx, RDI_Parsed *primary_rdi, U64 ip_voff) { e_interpret_ctx = ctx; + + // compute and apply frame base + if(primary_rdi != 0) + { + E_Interpretation frame_base = { .code = ~0 }; + + RDI_Procedure *proc = rdi_procedure_from_voff(primary_rdi, ip_voff); + for(U64 loc_block_idx = proc->frame_base_location_first; loc_block_idx < proc->frame_base_location_opl; loc_block_idx += 1) + { + RDI_LocationBlock *block = rdi_element_from_name_idx(primary_rdi, LocationBlocks, loc_block_idx); + if (block->scope_off_first <= ip_voff && ip_voff < block->scope_off_opl) { + U64 all_location_data_size = 0; + U8 *all_location_data = rdi_table_from_name(primary_rdi, LocationData, &all_location_data_size); + if(block->location_data_off + sizeof(RDI_LocationKind) <= all_location_data_size) + { + RDI_LocationKind loc_kind = *(RDI_LocationKind *)(all_location_data + block->location_data_off); + if(loc_kind == RDI_LocationKind_ValBytecodeStream || loc_kind == RDI_LocationKind_AddrBytecodeStream) + { + U8 *bytecode_ptr = all_location_data + block->location_data_off + sizeof(RDI_LocationKind); + U8 *bytecode_opl = all_location_data + all_location_data_size; + U64 bytecode_size = rdi_size_from_bytecode_stream(bytecode_ptr, bytecode_opl); + String8 bytecode = str8(bytecode_ptr, bytecode_size); + frame_base = e_interpret(bytecode); + } + else if(loc_kind != RDI_LocationKind_NULL) + { + NotImplemented; + } + } + break; + } + } + + if(frame_base.code == E_InterpretationCode_Good) + { + *ctx->frame_base = frame_base.value.u64; + } + else + { + ctx->frame_base = 0; + } + } } //////////////////////////////// //~ rjf: Space Reading Helpers +internal U64 +e_space_gen(E_Space space) +{ + U64 result = 0; + if(e_base_ctx->space_gen != 0) + { + result = e_base_ctx->space_gen(e_base_ctx->space_rw_user_data, space); + } + return result; +} + internal B32 e_space_read(E_Space space, void *out, Rng1U64 range) { @@ -58,7 +105,11 @@ e_interpret(String8 bytecode) U64 stack_cap = 128; // TODO(rjf): scan bytecode; determine maximum stack depth E_Value *stack = push_array_no_zero(scratch.arena, E_Value, stack_cap); U64 stack_count = 0; - E_Space selected_space = e_interpret_ctx->primary_space; + E_Space selected_space = {0}; + if(bytecode.size != 0) + { + selected_space = e_interpret_ctx->primary_space; + } //- rjf: iterate bytecode & perform ops U8 *ptr = bytecode.str; @@ -74,7 +125,7 @@ e_interpret(String8 bytecode) } else switch(op) { - case E_IRExtKind_SetSpace:{ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break; + case E_IRExtKind_SetSpace: {ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break; default: { result.code = E_InterpretationCode_BadOp; @@ -526,13 +577,13 @@ e_interpret(String8 bytecode) case RDI_EvalOp_EqEq: { - B32 result = MemoryMatchArray(svals[0].u512, svals[1].u512); + B32 result = MemoryMatchArray(svals[0].u512.u64, svals[1].u512.u64); nval.u64 = !!result; }break; case RDI_EvalOp_NtEq: { - B32 result = MemoryMatchArray(svals[0].u512, svals[1].u512); + B32 result = MemoryMatchArray(svals[0].u512.u64, svals[1].u512.u64); nval.u64 = !result; }break; @@ -767,7 +818,7 @@ e_interpret(String8 bytecode) if(offset + bytes_to_read <= sizeof(E_Value)) { E_Value src_val = svals[1]; - MemoryCopy(&nval.u512[0], (U8 *)(&src_val.u512[0]) + offset, bytes_to_read); + MemoryCopy(&nval.u512.u64[0], (U8 *)(&src_val.u512.u64[0]) + offset, bytes_to_read); } }break; @@ -812,6 +863,7 @@ e_interpret(String8 bytecode) { result.value = stack[0]; } + result.space = selected_space; scratch_end(scratch); return result; } diff --git a/src/eval/eval_interpret.h b/src/eval/eval_interpret.h index 3a9d0b51..61ac98f0 100644 --- a/src/eval/eval_interpret.h +++ b/src/eval/eval_interpret.h @@ -4,21 +4,9 @@ #ifndef EVAL_INTERPRET_H #define EVAL_INTERPRET_H -//////////////////////////////// -//~ rjf: Bytecode Interpretation Types - -typedef struct E_Interpretation E_Interpretation; -struct E_Interpretation -{ - E_Value value; - E_InterpretationCode code; -}; - //////////////////////////////// //~ rjf: Interpretation Context -typedef B32 E_SpaceRWFunction(void *user_data, E_Space space, void *out, Rng1U64 offset_range); - typedef struct E_InterpretCtx E_InterpretCtx; struct E_InterpretCtx { @@ -42,12 +30,12 @@ thread_static E_InterpretCtx *e_interpret_ctx = 0; //////////////////////////////// //~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) -internal E_InterpretCtx *e_selected_interpret_ctx(void); -internal void e_select_interpret_ctx(E_InterpretCtx *ctx); +internal void e_select_interpret_ctx(E_InterpretCtx *ctx, RDI_Parsed *primary_rdi, U64 ip_voff); //////////////////////////////// //~ rjf: Space Reading Helpers +internal U64 e_space_gen(E_Space space); internal B32 e_space_read(E_Space space, void *out, Rng1U64 range); internal B32 e_space_write(E_Space space, void *in, Rng1U64 range); diff --git a/src/eval/eval_ir.c b/src/eval/eval_ir.c index 9c08b133..643946c9 100644 --- a/src/eval/eval_ir.c +++ b/src/eval/eval_ir.c @@ -1,75 +1,6 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -//////////////////////////////// -//~ rjf: Expr Kind Enum Functions - -internal RDI_EvalOp -e_opcode_from_expr_kind(E_ExprKind kind) -{ - RDI_EvalOp result = RDI_EvalOp_Stop; - switch(kind) - { - case E_ExprKind_Neg: result = RDI_EvalOp_Neg; break; - case E_ExprKind_LogNot: result = RDI_EvalOp_LogNot; break; - case E_ExprKind_BitNot: result = RDI_EvalOp_BitNot; break; - case E_ExprKind_Mul: result = RDI_EvalOp_Mul; break; - case E_ExprKind_Div: result = RDI_EvalOp_Div; break; - case E_ExprKind_Mod: result = RDI_EvalOp_Mod; break; - case E_ExprKind_Add: result = RDI_EvalOp_Add; break; - case E_ExprKind_Sub: result = RDI_EvalOp_Sub; break; - case E_ExprKind_LShift: result = RDI_EvalOp_LShift; break; - case E_ExprKind_RShift: result = RDI_EvalOp_RShift; break; - case E_ExprKind_Less: result = RDI_EvalOp_Less; break; - case E_ExprKind_LsEq: result = RDI_EvalOp_LsEq; break; - case E_ExprKind_Grtr: result = RDI_EvalOp_Grtr; break; - case E_ExprKind_GrEq: result = RDI_EvalOp_GrEq; break; - case E_ExprKind_EqEq: result = RDI_EvalOp_EqEq; break; - case E_ExprKind_NtEq: result = RDI_EvalOp_NtEq; break; - case E_ExprKind_BitAnd: result = RDI_EvalOp_BitAnd; break; - case E_ExprKind_BitXor: result = RDI_EvalOp_BitXor; break; - case E_ExprKind_BitOr: result = RDI_EvalOp_BitOr; break; - case E_ExprKind_LogAnd: result = RDI_EvalOp_LogAnd; break; - case E_ExprKind_LogOr: result = RDI_EvalOp_LogOr; break; - } - return result; -} - -internal B32 -e_expr_kind_is_comparison(E_ExprKind kind) -{ - B32 result = 0; - switch(kind) - { - default:{}break; - case E_ExprKind_EqEq: - case E_ExprKind_NtEq: - case E_ExprKind_Less: - case E_ExprKind_Grtr: - case E_ExprKind_LsEq: - case E_ExprKind_GrEq: - { - result = 1; - }break; - } - return result; -} - -//////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) - -internal E_IRCtx * -e_selected_ir_ctx(void) -{ - return e_ir_ctx; -} - -internal void -e_select_ir_ctx(E_IRCtx *ctx) -{ - e_ir_ctx = ctx; -} - //////////////////////////////// //~ rjf: IR-ization Functions @@ -191,7 +122,10 @@ e_push_irnode(Arena *arena, RDI_EvalOp op) internal void e_irnode_push_child(E_IRNode *parent, E_IRNode *child) { - SLLQueuePush_NZ(&e_irnode_nil, parent->first, parent->last, child, next); + if(parent != &e_irnode_nil && child != &e_irnode_nil) + { + SLLQueuePush_NZ(&e_irnode_nil, parent->first, parent->last, child, next); + } } //- rjf: ir subtree building helpers @@ -211,6 +145,14 @@ e_irtree_const_u(Arena *arena, U64 v) return n; } +internal E_IRNode * +e_irtree_leaf_u128(Arena *arena, U128 u128) +{ + E_IRNode *n = e_push_irnode(arena, RDI_EvalOp_ConstU128); + n->value.u128 = u128; + return n; +} + internal E_IRNode * e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *c) { @@ -274,7 +216,7 @@ e_irtree_set_space(Arena *arena, E_Space space, E_IRNode *c) } internal E_IRNode * -e_irtree_mem_read_type(Arena *arena, E_Space space, E_IRNode *c, E_TypeKey type_key) +e_irtree_mem_read_type(Arena *arena, E_IRNode *c, E_TypeKey type_key) { E_IRNode *result = &e_irnode_nil; U64 byte_size = e_type_byte_size_from_key(type_key); @@ -296,11 +238,8 @@ e_irtree_mem_read_type(Arena *arena, E_Space space, E_IRNode *c, E_TypeKey type_ e_irnode_push_child(with_trunc, read_node); } - // rjf: set space for this mem read - E_IRNode *set_space_node = e_irtree_set_space(arena, space, with_trunc); - // rjf: fill - result = set_space_node; + result = with_trunc; return result; } @@ -358,147 +297,92 @@ e_irtree_convert_hi(Arena *arena, E_IRNode *c, E_TypeKey out, E_TypeKey in) } internal E_IRNode * -e_irtree_resolve_to_value(Arena *arena, E_Space from_space, E_Mode from_mode, E_IRNode *tree, E_TypeKey type_key) +e_irtree_resolve_to_value(Arena *arena, E_Mode from_mode, E_IRNode *tree, E_TypeKey type_key) { E_IRNode *result = tree; if(from_mode == E_Mode_Offset) { - result = e_irtree_mem_read_type(arena, from_space, tree, type_key); + result = e_irtree_mem_read_type(arena, tree, type_key); + } + if(e_type_kind_from_key(type_key) == E_TypeKind_Bitfield) + { + E_Type *type = e_type_from_key(type_key); + if(type->byte_size <= sizeof(U64)) + { + U64 valid_bits_mask = 0; + for(U64 idx = 0; idx < type->count; idx += 1) + { + valid_bits_mask |= (1ull<off)); + result = e_irtree_binary_op_u(arena, RDI_EvalOp_BitAnd, result, e_irtree_const_u(arena, valid_bits_mask)); + } } return result; } +//- rjf: rule tag poison checking + +internal B32 +e_expr_is_poisoned(E_Expr *expr) +{ + B32 tag_is_poisoned = 0; + U64 hash = e_hash_from_string(5381, str8_struct(&expr)); + U64 slot_idx = hash%e_cache->used_expr_map->slots_count; + for(E_UsedExprNode *n = e_cache->used_expr_map->slots[slot_idx].first; n != 0; n = n->next) + { + if(n->expr == expr) + { + tag_is_poisoned = 1; + break; + } + } + return tag_is_poisoned; +} + +internal void +e_expr_poison(E_Expr *expr) +{ + U64 hash = e_hash_from_string(5381, str8_struct(&expr)); + U64 slot_idx = hash%e_cache->used_expr_map->slots_count; + E_UsedExprNode *n = push_array(e_cache->arena, E_UsedExprNode, 1); + n->expr = expr; + DLLPushBack(e_cache->used_expr_map->slots[slot_idx].first, e_cache->used_expr_map->slots[slot_idx].last, n); +} + +internal void +e_expr_unpoison(E_Expr *expr) +{ + U64 hash = e_hash_from_string(5381, str8_struct(&expr)); + U64 slot_idx = hash%e_cache->used_expr_map->slots_count; + for(E_UsedExprNode *n = e_cache->used_expr_map->slots[slot_idx].first; n != 0; n = n->next) + { + if(n->expr == expr) + { + DLLRemove(e_cache->used_expr_map->slots[slot_idx].first, e_cache->used_expr_map->slots[slot_idx].last, n); + break; + } + } +} + //- rjf: top-level irtree/type extraction -internal E_IRTreeAndType -e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) +E_TYPE_ACCESS_FUNCTION_DEF(default) { + Temp scratch = scratch_begin(&arena, 1); E_IRTreeAndType result = {&e_irnode_nil}; - E_ExprKind kind = expr->kind; - switch(kind) + switch(expr->kind) { default:{}break; - //- rjf: references -> just descend to sub-expr - case E_ExprKind_Ref: - { - result = e_irtree_and_type_from_expr(arena, expr->ref); - }break; - - //- rjf: array indices - case E_ExprKind_ArrayIndex: - { - // rjf: unpack left/right expressions - E_Expr *exprl = expr->first; - E_Expr *exprr = exprl->next; - E_IRTreeAndType l = e_irtree_and_type_from_expr(arena, exprl); - E_IRTreeAndType r = e_irtree_and_type_from_expr(arena, exprr); - E_TypeKey l_restype = e_type_unwrap(l.type_key); - E_TypeKey r_restype = e_type_unwrap(r.type_key); - E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); - E_TypeKind r_restype_kind = e_type_kind_from_key(r_restype); - if(e_type_kind_is_basic_or_enum(r_restype_kind)) - { - r_restype = e_type_unwrap_enum(r_restype); - r_restype_kind = e_type_kind_from_key(r_restype); - } - E_TypeKey direct_type = e_type_unwrap(l_restype); - direct_type = e_type_direct_from_key(direct_type); - direct_type = e_type_unwrap(direct_type); - U64 direct_type_size = e_type_byte_size_from_key(direct_type); - e_msg_list_concat_in_place(&result.msgs, &l.msgs); - e_msg_list_concat_in_place(&result.msgs, &r.msgs); - - // rjf: bad conditions? -> error if applicable, exit - if(r.root->op == 0) - { - break; - } - else if(l_restype_kind != E_TypeKind_Ptr && l_restype_kind != E_TypeKind_Array) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot index into this type."); - break; - } - else if(!e_type_kind_is_integer(r_restype_kind)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index with this type."); - break; - } - else if(l_restype_kind == E_TypeKind_Ptr && direct_type_size == 0) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types."); - break; - } - else if(l_restype_kind == E_TypeKind_Array && direct_type_size == 0) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Cannot index into arrays of zero-sized types."); - break; - } - - // rjf: generate - E_IRNode *new_tree = &e_irnode_nil; - { - switch(l.mode) - { - // rjf: offsets -> read from base offset - default: - case E_Mode_Null: - case E_Mode_Offset: - { - // rjf: ops to compute the offset - E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.space, r.mode, r.root, r_restype); - if(direct_type_size > 1) - { - E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); - } - - // rjf: ops to compute the base offset (resolve to value if addr-of-pointer) - E_IRNode *base_tree = l.root; - if(l_restype_kind == E_TypeKind_Ptr && l.mode != E_Mode_Value) - { - base_tree = e_irtree_resolve_to_value(arena, l.space, l.mode, base_tree, l_restype); - } - - // rjf: ops to compute the final address - new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, offset_tree, base_tree); - }break; - - // rjf: values -> read from stack value - case E_Mode_Value: - { - // rjf: ops to compute the offset - E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.space, r.mode, r.root, r_restype); - if(direct_type_size > 1) - { - E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); - } - - // rjf: ops to push stack value, push offset, + read from stack value - new_tree = e_push_irnode(arena, RDI_EvalOp_ValueRead); - new_tree->value.u64 = direct_type_size; - e_irnode_push_child(new_tree, offset_tree); - e_irnode_push_child(new_tree, l.root); - }break; - } - } - - // rjf: fill - result.root = new_tree; - result.type_key = direct_type; - result.mode = l.mode; - result.space = l.space; - }break; - - //- rjf: member accesses + //- rjf: member accessing (. operator) case E_ExprKind_MemberAccess: { // rjf: unpack left/right expressions E_Expr *exprl = expr->first; E_Expr *exprr = exprl->next; - E_IRTreeAndType l = e_irtree_and_type_from_expr(arena, exprl); - E_TypeKey l_restype = e_type_unwrap(l.type_key); + E_IRTreeAndType l = *lhs_irtree; + E_TypeKey l_restype = e_type_key_unwrap(l.type_key, E_TypeUnwrapFlag_AllDecorative & ~E_TypeUnwrapFlag_Enums); E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); E_TypeKey check_type_key = l_restype; E_TypeKind check_type_kind = l_restype_kind; @@ -506,19 +390,22 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) l_restype_kind == E_TypeKind_LRef || l_restype_kind == E_TypeKind_RRef) { - check_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_restype))); + check_type_key = e_type_key_unwrap(l.type_key, E_TypeUnwrapFlag_All); check_type_kind = e_type_kind_from_key(check_type_key); } e_msg_list_concat_in_place(&result.msgs, &l.msgs); // rjf: look up member + E_Member member = zero_struct; B32 r_found = 0; E_TypeKey r_type = zero_struct; U64 r_value = 0; + String8 r_query_name = {0}; B32 r_is_constant_value = 0; { Temp scratch = scratch_begin(&arena, 1); E_Member match = e_type_member_from_key_name__cached(check_type_key, exprr->string); + member = match; if(match.kind != E_MemberKind_Null) { r_found = 1; @@ -527,48 +414,39 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) } if(match.kind == E_MemberKind_Null) { - E_Type *type = e_type_from_key(scratch.arena, check_type_key); - if(type->enum_vals != 0) + E_Type *type = e_type_from_key(check_type_key); + String8 lookup_string = exprr->string; + String8 lookup_string_append_1 = push_str8f(scratch.arena, "%S_%S", type->name, lookup_string); + String8 lookup_string_append_2 = push_str8f(scratch.arena, "%S%S", type->name, lookup_string); + E_EnumVal enum_val = {0}; + if(enum_val.name.size == 0) { enum_val = e_type_enum_val_from_key_name__cached(check_type_key, lookup_string); } + if(enum_val.name.size == 0) { enum_val = e_type_enum_val_from_key_name__cached(check_type_key, lookup_string_append_1); } + if(enum_val.name.size == 0) { enum_val = e_type_enum_val_from_key_name__cached(check_type_key, lookup_string_append_2); } + if(enum_val.name.size != 0) { - String8 lookup_string = exprr->string; - String8 lookup_string_append_1 = push_str8f(scratch.arena, "%S_%S", type->name, lookup_string); - String8 lookup_string_append_2 = push_str8f(scratch.arena, "%S%S", type->name, lookup_string); - E_EnumVal *enum_val_match = 0; - for EachIndex(idx, type->count) - { - if(str8_match(type->enum_vals[idx].name, lookup_string, 0) || - str8_match(type->enum_vals[idx].name, lookup_string_append_1, 0) || - str8_match(type->enum_vals[idx].name, lookup_string_append_2, 0)) - { - enum_val_match = &type->enum_vals[idx]; - break; - } - } - if(enum_val_match != 0) - { - r_found = 1; - r_type = check_type_key; - r_value = enum_val_match->val; - r_is_constant_value = 1; - } + r_found = 1; + r_type = check_type_key; + r_value = enum_val.val; + r_is_constant_value = 1; } } scratch_end(scratch); } // rjf: bad conditions? -> error if applicable, exit - if(e_type_key_match(e_type_key_zero(), check_type_key)) + if(exprr->kind != E_ExprKind_LeafIdentifier) { - break; - } - else if(exprr->kind != E_ExprKind_LeafMember) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Expected member name."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->range, "Expected member name."); break; } else if(!r_found) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->location, "Could not find a member named `%S`.", exprr->string); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->range, "Could not find a member named `%S`.", exprr->string); + break; + } + else if(l.root == &e_irnode_nil || + e_type_key_match(e_type_key_zero(), check_type_key)) + { break; } else if(check_type_kind != E_TypeKind_Struct && @@ -576,7 +454,7 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) check_type_kind != E_TypeKind_Union && check_type_kind != E_TypeKind_Enum) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->location, "Cannot perform member access on this type."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->range, "Cannot perform member access on this type."); break; } @@ -584,13 +462,15 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) { // rjf: build tree E_IRNode *new_tree = l.root; + E_TypeKey new_tree_type = r_type; E_Mode mode = l.mode; - if(l_restype_kind == E_TypeKind_Ptr || - l_restype_kind == E_TypeKind_LRef || - l_restype_kind == E_TypeKind_RRef) + if(e_type_kind_is_pointer_or_ref(l_restype_kind)) { - new_tree = e_irtree_resolve_to_value(arena, l.space, l.mode, new_tree, l_restype); - mode = E_Mode_Offset; + new_tree = e_irtree_resolve_to_value(arena, l.mode, new_tree, l_restype); + if(l.mode != E_Mode_Null) + { + mode = E_Mode_Offset; + } } if(r_value != 0 && !r_is_constant_value) { @@ -607,759 +487,1962 @@ e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr) result.root = new_tree; result.type_key = r_type; result.mode = mode; - result.space = l.space; } }break; - //- rjf: dereference - case E_ExprKind_Deref: + //- rjf: indexing ([] operator) + case E_ExprKind_ArrayIndex: { - // rjf: unpack operand - E_Expr *r_expr = expr->first; - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - E_TypeKey r_type = e_type_unwrap(r_tree.type_key); - E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - E_TypeKey r_type_direct = e_type_direct_from_key(r_type); - U64 r_type_direct_size = e_type_byte_size_from_key(r_type_direct); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + // rjf: unpack left/right expressions + E_Expr *exprl = expr->first; + E_Expr *exprr = exprl->next; + E_IRTreeAndType l = *lhs_irtree; + E_IRTreeAndType r = e_push_irtree_and_type_from_expr(arena, overridden, &e_default_identifier_resolution_rule, 0, 1, exprr); + e_msg_list_concat_in_place(&result.msgs, &r.msgs); + E_TypeKey l_restype = e_type_key_unwrap(l.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey r_restype = e_type_key_unwrap(r.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind l_restype_kind = e_type_kind_from_key(l_restype); + E_TypeKind r_restype_kind = e_type_kind_from_key(r_restype); + E_TypeKey direct_type = e_type_key_unwrap(l_restype, E_TypeUnwrapFlag_All); + U64 direct_type_size = e_type_byte_size_from_key(direct_type); // rjf: bad conditions? -> error if applicable, exit - if(r_tree.root->op == 0) + if(r.root->op == 0) { break; } - else if(r_type_direct_size == 0 && - (r_type_kind == E_TypeKind_Ptr || - r_type_kind == E_TypeKind_LRef || - r_type_kind == E_TypeKind_RRef)) + else if(l_restype_kind != E_TypeKind_Ptr && l_restype_kind != E_TypeKind_Array) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference pointers of zero-sized types."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprl->range, "Cannot index into this type."); break; } - else if(r_type_direct_size == 0 && r_type_kind == E_TypeKind_Array) + else if(!e_type_kind_is_integer(r_restype_kind)) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference arrays of zero-sized types."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->range, "Cannot index with this type."); break; } - else if(r_type_kind != E_TypeKind_Array && - r_type_kind != E_TypeKind_Ptr && - r_type_kind != E_TypeKind_LRef && - r_type_kind != E_TypeKind_RRef) + else if(l_restype_kind == E_TypeKind_Ptr && direct_type_size == 0) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->location, "Cannot dereference this type."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->range, "Cannot index into pointers of zero-sized types."); + break; + } + else if(l_restype_kind == E_TypeKind_Array && direct_type_size == 0) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, exprr->range, "Cannot index into arrays of zero-sized types."); break; } // rjf: generate + E_IRNode *new_tree = &e_irnode_nil; + E_Mode mode = l.mode; { - E_IRNode *new_tree = r_tree.root; - if(r_tree.mode != E_Mode_Value && - (r_type_kind == E_TypeKind_Ptr || - r_type_kind == E_TypeKind_LRef || - r_type_kind == E_TypeKind_RRef)) + // rjf: reading from an array value -> read from stack value + if(l.mode == E_Mode_Value && l_restype_kind == E_TypeKind_Array) { - new_tree = e_irtree_resolve_to_value(arena, r_tree.space, r_tree.mode, r_tree.root, r_type); + // rjf: ops to compute the offset + E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.mode, r.root, r_restype); + if(direct_type_size > 1) + { + E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + } + + // rjf: ops to push stack value, push offset, + read from stack value + new_tree = e_push_irnode(arena, RDI_EvalOp_ValueRead); + new_tree->value.u64 = direct_type_size; + e_irnode_push_child(new_tree, offset_tree); + e_irnode_push_child(new_tree, l.root); + } + + // rjf: all other cases -> read from base offset + else + { + // rjf: ops to compute the offset + E_IRNode *offset_tree = e_irtree_resolve_to_value(arena, r.mode, r.root, r_restype); + if(direct_type_size > 1) + { + E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); + offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree); + } + + // rjf: ops to compute the base offset (resolve to value if addr-of-pointer) + E_IRNode *base_tree = l.root; + if(l_restype_kind == E_TypeKind_Ptr && l.mode != E_Mode_Value) + { + base_tree = e_irtree_resolve_to_value(arena, l.mode, base_tree, l_restype); + } + + // rjf: ops to compute the final address + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, offset_tree, base_tree); + if(mode != E_Mode_Null) + { + mode = E_Mode_Offset; + } } - result.root = new_tree; - result.type_key = r_type_direct; - result.mode = E_Mode_Offset; - result.space = r_tree.space; } + + // rjf: fill + result.root = new_tree; + result.type_key = direct_type; + result.mode = mode; }break; + } + scratch_end(scratch); + return result; +} + +internal E_IRTreeAndType +e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_IdentifierResolutionRule *identifier_resolution_rule, B32 disallow_autohooks, B32 disallow_chained_fastpaths, E_Expr *root_expr) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + E_TypeKeyList inherited_lenses = {0}; + E_IRTreeAndType result = {&e_irnode_nil}; + + ////////////////////////////// + //- rjf: apply all ir-generation steps + // + typedef struct Task Task; + struct Task + { + Task *next; + E_Expr *expr; + E_IRTreeAndType *overridden; + }; + Task start_task = {0, root_expr, 0}; + Task *first_task = &start_task; + Task *last_task = first_task; + for(Task *t = first_task; t != 0; t = t->next) + { + E_Expr *expr = t->expr; + E_IRTreeAndType *parent = t->overridden ? t->overridden : root_parent; - //- rjf: address-of - case E_ExprKind_Address: - { - // rjf: unpack operand - E_Expr *r_expr = expr->first; - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - E_TypeKey r_type = r_tree.type_key; - E_TypeKey r_type_unwrapped = e_type_unwrap(r_type); - E_TypeKind r_type_unwrapped_kind = e_type_kind_from_key(r_type_unwrapped); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - - // rjf: bad conditions? -> error if applicable, exit - if(r_tree.root->op == 0) - { - break; - } - else if(e_type_key_match(e_type_key_zero(), r_type_unwrapped)) - { - break; - } - - // rjf: generate - result.root = r_tree.root; - result.type_key = e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, r_type_unwrapped, 0); - result.mode = E_Mode_Value; - result.space = r_tree.space; - }break; + //- rjf: poison the expression we are about to use, so we don't recursively use it + e_expr_poison(expr); - //- rjf: cast - case E_ExprKind_Cast: + //- rjf: do expr -> irtree generation for this expression + if(expr->kind == E_ExprKind_Ref) { - // rjf: unpack operands - E_Expr *cast_type_expr = expr->first; - E_Expr *casted_expr = cast_type_expr->next; - E_TypeKey cast_type = e_type_from_expr(cast_type_expr); - E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type); - U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type); - E_IRTreeAndType casted_tree = e_irtree_and_type_from_expr(arena, casted_expr); - e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs); - E_TypeKey casted_type = e_type_unwrap(casted_tree.type_key); - E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type); - U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type); - U8 in_group = e_type_group_from_kind(casted_type_kind); - U8 out_group = e_type_group_from_kind(cast_type_kind); - RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group); + expr = expr->ref; + } + E_ExprKind kind = expr->kind; + switch(kind) + { + default:{}break; - // rjf: bad conditions? -> error if applicable, exit - if(casted_tree.root->op == 0) + //- rjf: member accesses & array indexing expressions + case E_ExprKind_MemberAccess: + case E_ExprKind_ArrayIndex: { - break; - } - else if(cast_type_kind == E_TypeKind_Null) - { - break; - } - else if(conversion_rule != RDI_EvalConversionKind_Noop && - conversion_rule != RDI_EvalConversionKind_Legal) - { - String8 text = str8_lit("Unknown cast conversion rule."); - if(conversion_rule < RDI_EvalConversionKind_COUNT) + // rjf: unpack left-hand-side + E_Expr *lhs = expr->first; + E_IRTreeAndType lhs_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, 0, 1, lhs); + e_msg_list_concat_in_place(&result.msgs, &lhs_irtree.msgs); + + // rjf: try all IR trees in chain + for(E_IRTreeAndType *lhs_irtree_try = &lhs_irtree; lhs_irtree_try != 0; lhs_irtree_try = lhs_irtree_try->prev) { - text.str = rdi_explanation_string_from_eval_conversion_kind(conversion_rule, &text.size); + // rjf: gather inherited lenses from the left-hand-side + { + E_TypeKey k = lhs_irtree_try->type_key; + E_TypeKind kind = e_type_kind_from_key(k); + for(;kind == E_TypeKind_Lens;) + { + E_Type *lens_type = e_type_from_key(k); + if((lens_type->flags & E_TypeFlag_InheritedByMembers && expr->kind == E_ExprKind_MemberAccess) || + (lens_type->flags & E_TypeFlag_InheritedByElements && expr->kind == E_ExprKind_ArrayIndex)) + { + e_type_key_list_push_front(scratch.arena, &inherited_lenses, k); + } + k = e_type_key_direct(k); + kind = e_type_kind_from_key(k); + } + } + + // rjf: pick access hook based on type + E_Type *lhs_type = e_type_from_key(lhs_irtree_try->type_key); + E_TypeAccessFunctionType *lhs_access = lhs_type->access; + for(E_Type *lens_type = lhs_type; + lens_type->kind == E_TypeKind_Lens || lens_type->kind == E_TypeKind_Set; + lens_type = e_type_from_key(lens_type->direct_type_key)) + { + if(lens_type->access != 0) + { + lhs_access = lens_type->access; + break; + } + } + if(lhs_access == 0) + { + lhs_access = E_TYPE_ACCESS_FUNCTION_NAME(default); + } + + // rjf: call into hook to do access + result = lhs_access(arena, parent, expr, lhs_irtree_try); + + // rjf: end chain if we found a result + if(result.root != &e_irnode_nil) + { + break; + } } - e_msg(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, text); - break; - } + + // rjf: invalid generation, chain of member accesses all stemming from + // a single leaf identifier -> try to join as single string & resolve it + // that way + if(result.root == &e_irnode_nil) + { + B32 is_ident_chain = 1; + for(E_Expr *l = lhs; l != &e_expr_nil; l = l->first) + { + if(l->kind != E_ExprKind_MemberAccess && l->kind != E_ExprKind_LeafIdentifier) + { + is_ident_chain = 0; + break; + } + } + if(is_ident_chain) + { + String8List parts = {0}; + str8_list_push_front(scratch.arena, &parts, lhs->next->string); + for(E_Expr *l = lhs; l != &e_expr_nil; l = l->first) + { + if(l->kind == E_ExprKind_LeafIdentifier) + { + str8_list_push_front(scratch.arena, &parts, l->string); + } + else if(l->kind == E_ExprKind_MemberAccess) + { + str8_list_push_front(scratch.arena, &parts, l->first->next->string); + } + } + String8 full_qualified_name = str8_list_join(scratch.arena, &parts, &(StringJoin){.sep = str8_lit(".")}); + E_Expr *leaf_expr_name = e_push_expr(scratch.arena, E_ExprKind_LeafIdentifier, r1u64(0, 0)); + leaf_expr_name->string = full_qualified_name; + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, disallow_autohooks, leaf_expr_name); + } + } + }break; - // rjf: generate + //- rjf: dereference + case E_ExprKind_Deref: { - E_IRNode *in_tree = e_irtree_resolve_to_value(arena, casted_tree.space, casted_tree.mode, casted_tree.root, casted_type); - E_IRNode *new_tree = in_tree; - if(conversion_rule == RDI_EvalConversionKind_Legal) + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + E_TypeKey r_type_direct = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_All); + U64 r_type_direct_size = e_type_byte_size_from_key(r_type_direct); + + // rjf: bad conditions? -> error if applicable, exit + if(r_tree.root->op == 0) { - new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group); + break; } - if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind)) + else if(r_type_direct_size == 0 && + (r_type_kind == E_TypeKind_Ptr || + r_type_kind == E_TypeKind_LRef || + r_type_kind == E_TypeKind_RRef)) { - new_tree = e_irtree_trunc(arena, in_tree, cast_type); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->range, "Cannot dereference pointers of zero-sized types."); + break; } - result.root = new_tree; - result.type_key = cast_type; + else if(r_type_direct_size == 0 && r_type_kind == E_TypeKind_Array) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->range, "Cannot dereference arrays of zero-sized types."); + break; + } + else if(r_type_kind != E_TypeKind_Array && + r_type_kind != E_TypeKind_Ptr && + r_type_kind != E_TypeKind_LRef && + r_type_kind != E_TypeKind_RRef) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, r_expr->range, "Cannot dereference this type."); + break; + } + + // rjf: generate + { + E_IRNode *new_tree = r_tree.root; + if(r_tree.mode != E_Mode_Value && + (r_type_kind == E_TypeKind_Ptr || + r_type_kind == E_TypeKind_LRef || + r_type_kind == E_TypeKind_RRef)) + { + new_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + } + result.root = new_tree; + result.type_key = r_type_direct; + result.mode = E_Mode_Null; + if(r_tree.mode != E_Mode_Null) + { + result.mode = E_Mode_Offset; + } + } + }break; + + //- rjf: address-of + case E_ExprKind_Address: + { + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey r_type = r_tree.type_key; + E_TypeKey r_type_unwrapped = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind r_type_unwrapped_kind = e_type_kind_from_key(r_type_unwrapped); + + // rjf: bad conditions? -> error if applicable, exit + if(r_tree.root->op == 0) + { + break; + } + else if(e_type_key_match(e_type_key_zero(), r_type_unwrapped)) + { + break; + } + + // rjf: generate + result.root = r_tree.root; + result.type_key = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, r_type_unwrapped, 1, 0); result.mode = E_Mode_Value; - result.space = casted_tree.space; - } - }break; - - //- rjf: sizeof - case E_ExprKind_Sizeof: - { - // rjf: unpack operand - E_Expr *r_expr = expr->first; - E_TypeKey r_type = zero_struct; - E_Space space = r_expr->space; - switch(r_expr->kind) + }break; + + //- rjf: cast + case E_ExprKind_Cast: { - case E_ExprKind_TypeIdent: - case E_ExprKind_Ptr: - case E_ExprKind_Array: - case E_ExprKind_Func: + // rjf: unpack operands + E_Expr *cast_type_expr = expr->first; + E_Expr *casted_expr = cast_type_expr->next; + E_IRTreeAndType cast_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, cast_type_expr); + e_msg_list_concat_in_place(&result.msgs, &cast_irtree.msgs); + E_TypeKey cast_type = cast_irtree.type_key; + E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type); + U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type); + E_IRTreeAndType casted_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, casted_expr); + e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs); + E_TypeKey casted_type = e_type_key_unwrap(casted_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type); + U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type); + U8 in_group = e_type_group_from_kind(casted_type_kind); + U8 out_group = e_type_group_from_kind(cast_type_kind); + RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group); + + // rjf: bad conditions? -> error if applicable, exit + if(casted_tree.root->op == 0) { - r_type = e_type_from_expr(r_expr); - }break; - default: + break; + } + else if(cast_type_kind == E_TypeKind_Null) { - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - r_type = r_tree.type_key; - space = r_tree.space; - }break; - } + break; + } + else if(conversion_rule != RDI_EvalConversionKind_Noop && + conversion_rule != RDI_EvalConversionKind_Legal) + { + String8 text = str8_lit("Unknown cast conversion rule."); + if(conversion_rule < RDI_EvalConversionKind_COUNT) + { + text.str = rdi_explanation_string_from_eval_conversion_kind(conversion_rule, &text.size); + } + e_msg(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, text); + break; + } + + // rjf: generate + { + E_IRNode *in_tree = e_irtree_resolve_to_value(arena, casted_tree.mode, casted_tree.root, casted_type); + E_IRNode *new_tree = in_tree; + if(conversion_rule == RDI_EvalConversionKind_Legal) + { + new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group); + } + if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind)) + { + new_tree = e_irtree_trunc(arena, in_tree, cast_type); + } + result.root = new_tree; + result.type_key = cast_type; + result.mode = E_Mode_Value; + } + }break; - // rjf: bad conditions? -> error if applicable, exit - if(e_type_key_match(r_type, e_type_key_zero())) + //- rjf: sizeof + case E_ExprKind_Sizeof: { - break; - } - else if(e_type_kind_from_key(r_type) == E_TypeKind_Null) - { - break; - } + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_TypeKey r_type = zero_struct; + E_Space space = r_expr->space; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, 1, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + r_type = r_tree.type_key; + + // rjf: bad conditions? -> error if applicable, exit + if(e_type_key_match(r_type, e_type_key_zero())) + { + break; + } + else if(e_type_kind_from_key(r_type) == E_TypeKind_Null) + { + break; + } + + // rjf: generate + { + U64 r_type_byte_size = e_type_byte_size_from_key(r_type); + result.root = e_irtree_const_u(arena, r_type_byte_size); + result.type_key = e_type_key_basic(E_TypeKind_U64); + result.mode = E_Mode_Value; + } + }break; - // rjf: generate + //- rjf: typeof + case E_ExprKind_Typeof: { - U64 r_type_byte_size = e_type_byte_size_from_key(r_type); - result.root = e_irtree_const_u(arena, r_type_byte_size); - result.type_key = e_type_key_basic(E_TypeKind_U64); - result.mode = E_Mode_Value; - result.space = space; - } - }break; - - //- rjf: typeof - case E_ExprKind_Typeof: - { - // rjf: evaluate operand tree - E_Expr *r_expr = expr->first; - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + // rjf: evaluate operand tree + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, 1, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + + // rjf: find the first non-autohook result + E_TypeKey type_key = r_tree.type_key; + for(E_IRTreeAndType *t = &r_tree; t != 0; t = t->prev) + { + type_key = t->type_key; + if(t->auto_hook == 0) + { + break; + } + } + + // rjf: fill output + result.root = e_irtree_const_u(arena, 0); + result.type_key = type_key; + result.mode = E_Mode_Null; + }break; - // rjf: fill output - result.root = e_irtree_const_u(arena, 0); - result.type_key = r_tree.type_key; - result.mode = E_Mode_Null; - result.space = r_tree.space; - }break; - - //- rjf: byteswap - case E_ExprKind_ByteSwap: - { - // rjf: unpack operand - E_Expr *r_expr = expr->first; - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - E_TypeKey r_type = e_type_unwrap(r_tree.type_key); - E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - U64 r_type_size = e_type_byte_size_from_key(r_type); - E_Space space = r_tree.space; + //- rjf: byteswap + case E_ExprKind_ByteSwap: + { + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + U64 r_type_size = e_type_byte_size_from_key(r_type); + + // rjf: bad conditions? -> error if applicable, exit + if(!e_type_kind_is_integer(r_type_kind) || (r_type_size != 8 && r_type_size != 4 && r_type_size != 2)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Byteswapping this type is not supported."); + break; + } + + // rjf: generate + { + E_IRNode *node = e_push_irnode(arena, RDI_EvalOp_ByteSwap); + E_IRNode *rhs = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + e_irnode_push_child(node, rhs); + node->value.u64 = r_type_size; + result.root = node; + result.mode = E_Mode_Value; + result.type_key = r_type; + } + }break; - // rjf: bad conditions? -> error if applicable, exit - if(!e_type_kind_is_integer(r_type_kind) || (r_type_size != 8 && r_type_size != 4 && r_type_size != 2)) + //- rjf: unary operations + case E_ExprKind_Pos: { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Byteswapping this type is not supported."); - break; - } + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first); + }break; + case E_ExprKind_Neg: + case E_ExprKind_BitNot: + { + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); + E_TypeKey r_type_promoted = e_type_key_promote(r_type); + RDI_EvalOp op = e_opcode_from_expr_kind(kind); + + // rjf: bad conditions? -> error if applicable, exit + if(r_tree.root->op == 0) + { + break; + } + else if(!rdi_eval_op_typegroup_are_compatible(op, r_type_group)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Cannot use this operator on this type."); + break; + } + + // rjf: generate + { + E_IRNode *in_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + in_tree = e_irtree_convert_hi(arena, in_tree, r_type_promoted, r_type); + E_IRNode *new_tree = e_irtree_unary_op(arena, op, r_type_group, in_tree); + result.root = new_tree; + result.type_key = r_type_promoted; + result.mode = E_Mode_Value; + } + }break; + case E_ExprKind_LogNot: + { + // rjf: unpack operand + E_Expr *r_expr = expr->first; + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); + E_TypeKey r_type_promoted = e_type_key_basic(E_TypeKind_Bool); + RDI_EvalOp op = e_opcode_from_expr_kind(kind); + + // rjf: bad conditions? -> error if applicable, exit + if(r_tree.root->op == 0) + { + break; + } + else if(!rdi_eval_op_typegroup_are_compatible(op, r_type_group)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Cannot use this operator on this type."); + break; + } + + // rjf: generate + { + E_IRNode *in_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + in_tree = e_irtree_convert_hi(arena, in_tree, r_type_promoted, r_type); + E_IRNode *new_tree = e_irtree_unary_op(arena, op, r_type_group, in_tree); + result.root = new_tree; + result.type_key = r_type_promoted; + result.mode = E_Mode_Value; + } + }break; - // rjf: generate + //- rjf: binary operations + case E_ExprKind_Mul: + case E_ExprKind_Div: + case E_ExprKind_Mod: + case E_ExprKind_Add: + case E_ExprKind_Sub: + case E_ExprKind_LShift: + case E_ExprKind_RShift: + case E_ExprKind_Less: + case E_ExprKind_LsEq: + case E_ExprKind_Grtr: + case E_ExprKind_GrEq: + case E_ExprKind_EqEq: + case E_ExprKind_NtEq: + case E_ExprKind_BitAnd: + case E_ExprKind_BitXor: + case E_ExprKind_BitOr: + case E_ExprKind_LogAnd: + case E_ExprKind_LogOr: { - E_IRNode *node = e_push_irnode(arena, RDI_EvalOp_ByteSwap); - E_IRNode *rhs = e_irtree_resolve_to_value(arena, space, r_tree.mode, r_tree.root, r_type); - e_irnode_push_child(node, rhs); - node->value.u64 = r_type_size; - result.root = node; - result.mode = E_Mode_Value; - result.space = space; - result.type_key = r_type; - } - }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: - { - // rjf: unpack operand - E_Expr *r_expr = expr->first; - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - E_TypeKey r_type = e_type_unwrap(r_tree.type_key); - E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); - E_TypeKey r_type_promoted = e_type_promote(r_type); - RDI_EvalOp op = e_opcode_from_expr_kind(kind); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - - // rjf: bad conditions? -> error if applicable, exit - if(r_tree.root->op == 0) - { - break; - } - else if(!rdi_eval_op_typegroup_are_compatible(op, r_type_group)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Cannot use this operator on this type."); - break; - } - - // rjf: generate - { - E_IRNode *in_tree = e_irtree_resolve_to_value(arena, r_tree.space, r_tree.mode, r_tree.root, r_type); - in_tree = e_irtree_convert_hi(arena, in_tree, r_type_promoted, r_type); - E_IRNode *new_tree = e_irtree_unary_op(arena, op, r_type_group, in_tree); - result.root = new_tree; - result.type_key = r_type_promoted; - result.mode = E_Mode_Value; - result.space = r_tree.space; - } - }break; - - //- rjf: binary operations - case E_ExprKind_Mul: - case E_ExprKind_Div: - case E_ExprKind_Mod: - case E_ExprKind_Add: - case E_ExprKind_Sub: - case E_ExprKind_LShift: - case E_ExprKind_RShift: - case E_ExprKind_Less: - case E_ExprKind_LsEq: - case E_ExprKind_Grtr: - case E_ExprKind_GrEq: - case E_ExprKind_EqEq: - case E_ExprKind_NtEq: - case E_ExprKind_BitAnd: - case E_ExprKind_BitXor: - case E_ExprKind_BitOr: - case E_ExprKind_LogAnd: - case E_ExprKind_LogOr: - { - // rjf: unpack operands - RDI_EvalOp op = e_opcode_from_expr_kind(kind); - B32 is_comparison = e_expr_kind_is_comparison(kind); - E_Expr *l_expr = expr->first; - E_Expr *r_expr = l_expr->next; - E_IRTreeAndType l_tree = e_irtree_and_type_from_expr(arena, l_expr); - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - E_TypeKey l_type = e_type_unwrap_enum(e_type_unwrap(l_tree.type_key)); - E_TypeKey r_type = e_type_unwrap_enum(e_type_unwrap(r_tree.type_key)); - E_TypeKind l_type_kind = e_type_kind_from_key(l_type); - E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - if(l_type.kind == E_TypeKeyKind_Reg) - { - l_type_kind = E_TypeKind_U64; - l_type = e_type_key_basic(l_type_kind); - } - if(r_type.kind == E_TypeKeyKind_Reg) - { - r_type_kind = E_TypeKind_U64; - r_type = e_type_key_basic(r_type_kind); - } - B32 l_is_pointer = (l_type_kind == E_TypeKind_Ptr); - B32 l_is_decay = (l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Offset); - B32 l_is_pointer_like = (l_is_pointer || l_is_decay); - B32 r_is_pointer = (r_type_kind == E_TypeKind_Ptr); - B32 r_is_decay = (r_type_kind == E_TypeKind_Array && r_tree.mode == E_Mode_Offset); - B32 r_is_pointer_like = (r_is_pointer || r_is_decay); - RDI_EvalTypeGroup l_type_group = e_type_group_from_kind(l_type_kind); - RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); - - // rjf: bad conditions? -> error if applicable, exit - if(l_tree.root->op == 0 || r_tree.root->op == 0) - { - break; - } - - // rjf: determine arithmetic path + // rjf: unpack operands + RDI_EvalOp op = e_opcode_from_expr_kind(kind); + B32 is_comparison = e_expr_kind_is_comparison(kind); + E_Expr *l_expr = expr->first; + E_Expr *r_expr = l_expr->next; + E_IRTreeAndType l_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, l_expr); + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey l_type = e_type_key_unwrap(l_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind l_type_kind = e_type_kind_from_key(l_type); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + + // rjf: resolve complex types to simple arithmetic tyeps + if(l_type_kind == E_TypeKind_Bitfield) + { + l_tree.root = e_irtree_resolve_to_value(arena, l_tree.mode, l_tree.root, l_tree.type_key); + l_type = e_type_key_unwrap(e_type_key_direct(l_tree.type_key), E_TypeUnwrapFlag_AllDecorative); + l_type_kind = e_type_kind_from_key(r_type); + l_tree.mode = E_Mode_Value; + } + if(r_type_kind == E_TypeKind_Bitfield) + { + r_tree.root = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_tree.type_key); + r_type = e_type_key_unwrap(e_type_key_direct(r_tree.type_key), E_TypeUnwrapFlag_AllDecorative); + r_type_kind = e_type_kind_from_key(r_type); + r_tree.mode = E_Mode_Value; + } + if(l_type.kind == E_TypeKeyKind_Reg) + { + l_type_kind = E_TypeKind_U64; + l_type = e_type_key_basic(l_type_kind); + } + if(r_type.kind == E_TypeKeyKind_Reg) + { + r_type_kind = E_TypeKind_U64; + r_type = e_type_key_basic(r_type_kind); + } + + // rjf: unpack info about resolved types + B32 l_is_pointer = (l_type_kind == E_TypeKind_Ptr); + B32 l_is_decay = (l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Offset); + B32 l_is_pointer_like = (l_is_pointer || l_is_decay); + B32 r_is_pointer = (r_type_kind == E_TypeKind_Ptr); + B32 r_is_decay = (r_type_kind == E_TypeKind_Array && r_tree.mode == E_Mode_Offset); + B32 r_is_pointer_like = (r_is_pointer || r_is_decay); + RDI_EvalTypeGroup l_type_group = e_type_group_from_kind(l_type_kind); + RDI_EvalTypeGroup r_type_group = e_type_group_from_kind(r_type_kind); + + // rjf: bad conditions? -> error if applicable, exit + if(l_tree.root->op == 0 || r_tree.root->op == 0) + { + break; + } + + // rjf: determine arithmetic path #define E_ArithPath_Normal 0 #define E_ArithPath_PtrAdd 1 #define E_ArithPath_PtrSub 2 #define E_ArithPath_PtrArrayCompare 3 - B32 ptr_arithmetic_mul_rptr = 0; - U32 arith_path = E_ArithPath_Normal; - if(kind == E_ExprKind_Add) - { - if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) + B32 ptr_arithmetic_mul_rptr = 0; + U32 arith_path = E_ArithPath_Normal; + if(kind == E_ExprKind_Add) { - arith_path = E_ArithPath_PtrAdd; - } - if(l_is_pointer_like && e_type_kind_is_integer(l_type_kind)) - { - arith_path = E_ArithPath_PtrAdd; - ptr_arithmetic_mul_rptr = 1; - } - } - else if(kind == E_ExprKind_Sub) - { - if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) - { - arith_path = E_ArithPath_PtrAdd; - } - if(l_is_pointer_like && r_is_pointer_like) - { - E_TypeKey l_type_direct = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_type))); - E_TypeKey r_type_direct = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(r_type))); - U64 l_type_direct_byte_size = e_type_byte_size_from_key(l_type_direct); - U64 r_type_direct_byte_size = e_type_byte_size_from_key(r_type_direct); - if(l_type_direct_byte_size == r_type_direct_byte_size) + if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) { - arith_path = E_ArithPath_PtrSub; + arith_path = E_ArithPath_PtrAdd; + } + if(l_is_pointer_like && e_type_kind_is_integer(l_type_kind)) + { + arith_path = E_ArithPath_PtrAdd; + ptr_arithmetic_mul_rptr = 1; } } - } - else if(kind == E_ExprKind_EqEq) - { - if(l_type_kind == E_TypeKind_Array && (r_type_kind == E_TypeKind_Ptr || r_is_decay)) + else if(kind == E_ExprKind_Sub) { - arith_path = E_ArithPath_PtrArrayCompare; - } - if(r_type_kind == E_TypeKind_Array && (l_type_kind == E_TypeKind_Ptr || l_is_decay)) - { - arith_path = E_ArithPath_PtrArrayCompare; - } - } - - // rjf: generate according to arithmetic path - switch(arith_path) - { - //- rjf: normal arithmetic - case E_ArithPath_Normal: - { - // rjf: bad conditions? -> error if applicable, exit - if(!rdi_eval_op_typegroup_are_compatible(op, l_type_group) || - !rdi_eval_op_typegroup_are_compatible(op, r_type_group)) + if(l_is_pointer_like && e_type_kind_is_integer(r_type_kind)) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Cannot use this operator on this type."); + arith_path = E_ArithPath_PtrAdd; + } + if(l_is_pointer_like && r_is_pointer_like) + { + E_TypeKey l_type_direct = e_type_key_unwrap(l_type, E_TypeUnwrapFlag_All); + E_TypeKey r_type_direct = e_type_key_unwrap(r_type, E_TypeUnwrapFlag_All); + U64 l_type_direct_byte_size = e_type_byte_size_from_key(l_type_direct); + U64 r_type_direct_byte_size = e_type_byte_size_from_key(r_type_direct); + if(l_type_direct_byte_size == r_type_direct_byte_size) + { + arith_path = E_ArithPath_PtrSub; + } + } + } + else if(kind == E_ExprKind_EqEq) + { + if(l_type_kind == E_TypeKind_Array && (r_type_kind == E_TypeKind_Ptr || r_is_decay)) + { + arith_path = E_ArithPath_PtrArrayCompare; + } + if(r_type_kind == E_TypeKind_Array && (l_type_kind == E_TypeKind_Ptr || l_is_decay)) + { + arith_path = E_ArithPath_PtrArrayCompare; + } + } + + // rjf: generate according to arithmetic path + switch(arith_path) + { + //- rjf: normal arithmetic + case E_ArithPath_Normal: + { + // rjf: bad conditions? -> error if applicable, exit + if(!rdi_eval_op_typegroup_are_compatible(op, l_type_group) || + !rdi_eval_op_typegroup_are_compatible(op, r_type_group)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Cannot use this operator on this type."); + break; + } + + // rjf: generate + { + E_TypeKey final_type_key = is_comparison ? e_type_key_basic(E_TypeKind_Bool) : l_type; + E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.mode, l_tree.root, l_type); + E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + l_value_tree = e_irtree_convert_hi(arena, l_value_tree, l_type, l_type); + r_value_tree = e_irtree_convert_hi(arena, r_value_tree, l_type, r_type); + E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, l_value_tree, r_value_tree); + result.root = new_tree; + result.type_key = final_type_key; + result.mode = E_Mode_Value; + } + }break; + + //- rjf: pointer addition + case E_ArithPath_PtrAdd: + { + // rjf: map l/r to ptr/int + E_IRTreeAndType *ptr_tree = &l_tree; + E_IRTreeAndType *int_tree = &r_tree; + B32 ptr_is_decay = l_is_decay; + if(ptr_arithmetic_mul_rptr) + { + ptr_tree = &r_tree; + int_tree = &l_tree; + ptr_is_decay = r_is_decay; + } + + // rjf: unpack type + E_TypeKey direct_type = e_type_key_unwrap(ptr_tree->type_key, E_TypeUnwrapFlag_All); + U64 direct_type_size = e_type_byte_size_from_key(direct_type); + + // rjf: generate + { + E_IRNode *ptr_root = ptr_tree->root; + if(!ptr_is_decay) + { + ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->mode, ptr_root, ptr_tree->type_key); + } + E_IRNode *int_root = int_tree->root; + int_root = e_irtree_resolve_to_value(arena, int_tree->mode, int_root, int_tree->type_key); + if(direct_type_size > 1) + { + E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size); + int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, int_root, const_root); + } + E_TypeKey ptr_type = ptr_tree->type_key; + if(ptr_is_decay) + { + ptr_type = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, direct_type, 1, 0); + } + E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root); + result.root = new_root; + result.type_key = ptr_type; + result.mode = E_Mode_Value; + } + }break; + + //- rjf: pointer subtraction + case E_ArithPath_PtrSub: + { + // rjf: unpack type + E_TypeKey direct_type = e_type_key_unwrap(l_type, E_TypeUnwrapFlag_All); + U64 direct_type_size = e_type_byte_size_from_key(direct_type); + + // rjf: generate + E_IRNode *l_root = l_tree.root; + E_IRNode *r_root = r_tree.root; + if(!l_is_decay) + { + l_root = e_irtree_resolve_to_value(arena, l_tree.mode, l_root, l_type); + } + if(!r_is_decay) + { + r_root = e_irtree_resolve_to_value(arena, r_tree.mode, r_root, r_type); + } + E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_root, r_root); + E_IRNode *new_tree = op_tree; + if(direct_type_size > 1) + { + E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); + new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, new_tree, const_tree); + } + result.root = new_tree; + result.type_key = e_type_key_basic(E_TypeKind_U64); + result.mode = E_Mode_Value; + }break; + + //- rjf: pointer array comparison + case E_ArithPath_PtrArrayCompare: + { + // rjf: map l/r to pointer/array + B32 ptr_is_decay = l_is_decay; + E_IRTreeAndType *ptr_tree = &l_tree; + E_IRTreeAndType *arr_tree = &r_tree; + if(l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Value) + { + ptr_is_decay = r_is_decay; + ptr_tree = &r_tree; + arr_tree = &l_tree; + } + + // rjf: resolve pointer to value, sized same as array + E_IRNode *ptr_root = ptr_tree->root; + E_IRNode *arr_root = arr_tree->root; + if(!ptr_is_decay) + { + ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->mode, ptr_tree->root, ptr_tree->type_key); + } + + // rjf: read from pointer into value, to compare with array + E_IRNode *mem_root = e_irtree_mem_read_type(arena, ptr_root, arr_tree->type_key); + + // rjf: generate + result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, mem_root, arr_root); + result.type_key = e_type_key_basic(E_TypeKind_Bool); + result.mode = E_Mode_Value; + }break; + } + }break; + + //- rjf: ternary operators + case E_ExprKind_Ternary: + { + // rjf: unpack operands + E_Expr *c_expr = expr->first; + E_Expr *l_expr = c_expr->next; + E_Expr *r_expr = l_expr->next; + E_IRTreeAndType c_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, c_expr); + E_IRTreeAndType l_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, l_expr); + E_IRTreeAndType r_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, r_expr); + e_msg_list_concat_in_place(&result.msgs, &c_tree.msgs); + e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); + e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); + E_TypeKey c_type = e_type_key_unwrap(c_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey l_type = e_type_key_unwrap(l_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind c_type_kind = e_type_kind_from_key(c_type); + E_TypeKind l_type_kind = e_type_kind_from_key(l_type); + E_TypeKind r_type_kind = e_type_kind_from_key(r_type); + + // rjf: bad conditions? -> error if applicable, exit + if(c_tree.root->op == 0 || l_tree.root->op == 0 || r_tree.root->op == 0) + { + break; + } + else if(!e_type_kind_is_integer(c_type_kind) && c_type_kind != E_TypeKind_Bool) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Conditional term must be an integer or boolean type."); + } + + // rjf: determine the resultant type - if the left/right types match, then we + // can just pick the left type, and defer 100% of our interpretation. however, + // if the types do *not* match, then we need to pre-emptively evaluate the + // condition, and pick the result based on that. + B32 ternary_is_dynamic = 0; + E_TypeKey result_type = l_type; + if(!e_type_match(l_type, r_type)) + { + ternary_is_dynamic = 1; + } + + // rjf: generate dynamic ternary + if(ternary_is_dynamic) + { + E_IRNode *c_value_tree = e_irtree_resolve_to_value(arena, c_tree.mode, c_tree.root, c_type); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, c_value_tree); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpretation = e_interpret(bytecode); + if(interpretation.value.u64 != 0) + { + result = l_tree; + } + else + { + result = r_tree; + } + } + + // rjf: generate static ternary + else + { + E_IRNode *c_value_tree = e_irtree_resolve_to_value(arena, c_tree.mode, c_tree.root, c_type); + E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.mode, l_tree.root, l_type); + E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type); + l_value_tree = e_irtree_convert_hi(arena, l_value_tree, result_type, l_type); + r_value_tree = e_irtree_convert_hi(arena, r_value_tree, result_type, r_type); + E_IRNode *new_tree = e_irtree_conditional(arena, c_value_tree, l_value_tree, r_value_tree); + result.root = new_tree; + result.type_key = result_type; + result.mode = E_Mode_Value; + } + }break; + + //- rjf: call + case E_ExprKind_Call: + { + B32 strip_lenses = 0; + E_Expr *lhs = expr->first; + E_IRTreeAndType lhs_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_callable_identifier_resolution_rule, disallow_autohooks, 1, lhs); + e_msg_list_concat_in_place(&result.msgs, &lhs_irtree.msgs); + E_TypeKey lhs_type_key = lhs_irtree.type_key; + E_Type *lhs_type = e_type_from_key(lhs_type_key); + + // rjf: calling a type? -> treat as a cast of that type + if(lhs_irtree.mode == E_Mode_Null && lhs_type != &e_type_nil && lhs_type->kind != E_TypeKind_Lens && lhs_type->kind != E_TypeKind_LensSpec) + { + E_IRTreeAndType casted_tree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first->next); + e_msg_list_concat_in_place(&result.msgs, &casted_tree.msgs); + E_TypeKey cast_type = lhs_irtree.type_key; + E_TypeKind cast_type_kind = e_type_kind_from_key(cast_type); + U64 cast_type_byte_size = e_type_byte_size_from_key(cast_type); + E_TypeKey casted_type = casted_tree.type_key; + E_TypeKind casted_type_kind = e_type_kind_from_key(casted_type); + U64 casted_type_byte_size = e_type_byte_size_from_key(casted_type); + U8 in_group = e_type_group_from_kind(casted_type_kind); + U8 out_group = e_type_group_from_kind(cast_type_kind); + RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_kind_from_typegroups(in_group, out_group); + + // rjf: bad conditions? -> error if applicable, exit + if(casted_tree.root->op == 0) + { + break; + } + else if(cast_type_kind == E_TypeKind_Null) + { + break; + } + else if(conversion_rule != RDI_EvalConversionKind_Noop && + conversion_rule != RDI_EvalConversionKind_Legal) + { + String8 text = str8_lit("Unknown cast conversion rule."); + if(conversion_rule < RDI_EvalConversionKind_COUNT) + { + text.str = rdi_explanation_string_from_eval_conversion_kind(conversion_rule, &text.size); + } + e_msg(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, text); break; } - // rjf: generate + // rjf: generate casted result { - E_TypeKey final_type_key = is_comparison ? e_type_key_basic(E_TypeKind_Bool) : l_type; - E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.space, l_tree.mode, l_tree.root, l_type); - E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.space, r_tree.mode, r_tree.root, r_type); - l_value_tree = e_irtree_convert_hi(arena, l_value_tree, l_type, l_type); - r_value_tree = e_irtree_convert_hi(arena, r_value_tree, l_type, r_type); - E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, l_value_tree, r_value_tree); + E_IRNode *in_tree = e_irtree_resolve_to_value(arena, casted_tree.mode, casted_tree.root, casted_type); + E_IRNode *new_tree = in_tree; + if(conversion_rule == RDI_EvalConversionKind_Legal) + { + new_tree = e_irtree_convert_lo(arena, in_tree, out_group, in_group); + } + if(cast_type_byte_size < casted_type_byte_size && e_type_kind_is_integer(cast_type_kind)) + { + new_tree = e_irtree_trunc(arena, in_tree, cast_type); + } result.root = new_tree; - result.type_key = final_type_key; + result.type_key = cast_type; result.mode = E_Mode_Value; - result.space = l_tree.space; - E_Space zero_space = {0}; - if(MemoryMatchStruct(&result.space, &zero_space)) - { - result.space = r_tree.space; - } } - }break; + } - //- rjf: pointer addition - case E_ArithPath_PtrAdd: + // rjf: calling an unresolved leaf-identifier member access, and we can determine + // that that identifer maps to a type? -> generate a call expression with the + // left-hand-side of the dot operator as the first argument. this is a fast path + // which prevents paren nesting in simple cases, to easily chain multiple + // calls - for example, bin(2).digits(4) + else if(lhs->kind == E_ExprKind_MemberAccess && lhs->first->next != &e_expr_nil) { - // rjf: map l/r to ptr/int - E_IRTreeAndType *ptr_tree = &l_tree; - E_IRTreeAndType *int_tree = &r_tree; - B32 ptr_is_decay = l_is_decay; - if(ptr_arithmetic_mul_rptr) + E_Expr *callee = e_expr_ref(arena, lhs->first->next); + E_Expr *first_arg = e_expr_ref(arena, lhs->first); + E_Expr *call = e_push_expr(arena, E_ExprKind_Call, r1u64(0, 0)); + e_expr_push_child(call, callee); + e_expr_push_child(call, first_arg); + for(E_Expr *arg = lhs->next; arg != &e_expr_nil; arg = arg->next) { - ptr_tree = &r_tree; - int_tree = &l_tree; - ptr_is_decay = r_is_decay; + e_expr_push_child(call, e_expr_copy(arena, arg)); } - - // rjf: unpack type - E_TypeKey direct_type = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(ptr_tree->type_key))); - U64 direct_type_size = e_type_byte_size_from_key(direct_type); - - // rjf: generate + if(str8_match(callee->ref->string, str8_lit("raw"), 0)) { - E_IRNode *ptr_root = ptr_tree->root; - if(!ptr_is_decay) - { - ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->space, ptr_tree->mode, ptr_root, ptr_tree->type_key); - } - E_IRNode *int_root = int_tree->root; - int_root = e_irtree_resolve_to_value(arena, int_tree->space, int_tree->mode, int_root, int_tree->type_key); - if(direct_type_size > 1) - { - E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size); - int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, int_root, const_root); - } - E_TypeKey ptr_type = ptr_tree->type_key; - if(ptr_is_decay) - { - ptr_type = e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, direct_type, 0); - } - E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root); - result.root = new_root; - result.type_key = ptr_type; - result.mode = E_Mode_Value; - result.space = l_tree.space; - E_Space zero_space = {0}; - if(MemoryMatchStruct(&result.space, &zero_space)) - { - result.space = r_tree.space; - } + strip_lenses = 1; + disallow_autohooks = 1; } - }break; + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, call); + // NOTE(rjf): we do not want to accumulate messages from the original left-hand-side evaluation in this case, because + // this path only occurs if the member access fails specifically. + } - //- rjf: pointer subtraction - case E_ArithPath_PtrSub: + // rjf: calling a lens? -> generate IR for the first argument; if enabled, wrap + // the type in a lens type, which preserves the name & arguments of the lens call + // expression + else if(lhs_type->kind == E_TypeKind_LensSpec) { - // rjf: unpack type - E_TypeKey direct_type = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(l_type))); - U64 direct_type_size = e_type_byte_size_from_key(direct_type); + // rjf: is "raw"? -> disable hooks + if(str8_match(lhs_type->name, str8_lit("raw"), 0)) + { + strip_lenses = 1; + disallow_autohooks = 1; + } - // rjf: generate - E_IRNode *l_root = l_tree.root; - E_IRNode *r_root = r_tree.root; - if(!l_is_decay) + // rjf: generate result via first argument to lens + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, lhs->next); + + // rjf: if not raw, wrap resultant type with lens type + if(!strip_lenses) { - l_root = e_irtree_resolve_to_value(arena, l_tree.space, l_tree.mode, l_root, l_type); + Temp scratch = scratch_begin(&arena, 1); + + // rjf: count extra arguments + U64 arg_count = 0; + for(E_Expr *arg = lhs->next->next; arg != &e_expr_nil; arg = arg->next) + { + arg_count += 1; + } + + // rjf: flatten extra arguments + E_Expr **args = push_array(scratch.arena, E_Expr *, arg_count); + { + U64 idx = 0; + for(E_Expr *arg = lhs->next->next; arg != &e_expr_nil; arg = arg->next, idx += 1) + { + args[idx] = arg; + } + } + + // rjf: patch resultant type with a lens w/ args, pointing to the original type + { + result.type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .flags = lhs_type->flags, + .count = arg_count, + .args = args, + .direct_key = result.type_key, + .name = lhs_type->name, + .irext = lhs_type->irext, + .access = lhs_type->access, + .expand = lhs_type->expand); + } + scratch_end(scratch); } - if(!r_is_decay) - { - r_root = e_irtree_resolve_to_value(arena, r_tree.space, r_tree.mode, r_root, r_type); - } - E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_root, r_root); - E_IRNode *new_tree = op_tree; - if(direct_type_size > 1) - { - E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size); - new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, new_tree, const_tree); - } - result.root = new_tree; - result.type_key = e_type_key_basic(E_TypeKind_U64); - result.mode = E_Mode_Value; - result.space = l_tree.space; - E_Space zero_space = {0}; - if(MemoryMatchStruct(&result.space, &zero_space)) - { - result.space = r_tree.space; - } - }break; + } - //- rjf: pointer array comparison - case E_ArithPath_PtrArrayCompare: + // rjf: calling any other type? -> not valid + else { - // rjf: map l/r to pointer/array - B32 ptr_is_decay = l_is_decay; - E_IRTreeAndType *ptr_tree = &l_tree; - E_IRTreeAndType *arr_tree = &r_tree; - if(l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Value) + e_msgf(arena, &result.msgs, E_MsgKind_InterpretationError, expr->range, "Calling this type is not supported."); + } + + // rjf: strip overrides and lenses if needed + if(strip_lenses) + { + if(t->overridden) { - ptr_is_decay = r_is_decay; - ptr_tree = &r_tree; - arr_tree = &l_tree; + E_MsgList existing_msgs = result.msgs; + for(E_IRTreeAndType *prev = t->overridden; prev != 0; prev = prev->prev) + { + result = *prev; + } + E_MsgList overridden_msgs = e_msg_list_copy(arena, &result.msgs); + result.msgs = existing_msgs; + e_msg_list_concat_in_place(&result.msgs, &overridden_msgs); } - - // rjf: resolve pointer to value, sized same as array - E_IRNode *ptr_root = ptr_tree->root; - E_IRNode *arr_root = arr_tree->root; - if(!ptr_is_decay) - { - ptr_root = e_irtree_resolve_to_value(arena, ptr_tree->space, ptr_tree->mode, ptr_tree->root, ptr_tree->type_key); - } - - // rjf: read from pointer into value, to compare with array - E_IRNode *mem_root = e_irtree_mem_read_type(arena, ptr_tree->space, ptr_root, arr_tree->type_key); - - // rjf: generate - result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, mem_root, arr_root); - result.type_key = e_type_key_basic(E_TypeKind_Bool); - result.mode = E_Mode_Value; - result.space = ptr_tree->space; - E_Space zero_space = {0}; - if(MemoryMatchStruct(&result.space, &zero_space)) - { - result.space = arr_tree->space; - } - }break; - } - }break; - - //- rjf: ternary operators - case E_ExprKind_Ternary: - { - // rjf: unpack operands - E_Expr *c_expr = expr->first; - E_Expr *l_expr = c_expr->next; - E_Expr *r_expr = l_expr->next; - E_IRTreeAndType c_tree = e_irtree_and_type_from_expr(arena, c_expr); - E_IRTreeAndType l_tree = e_irtree_and_type_from_expr(arena, l_expr); - E_IRTreeAndType r_tree = e_irtree_and_type_from_expr(arena, r_expr); - e_msg_list_concat_in_place(&result.msgs, &c_tree.msgs); - e_msg_list_concat_in_place(&result.msgs, &l_tree.msgs); - e_msg_list_concat_in_place(&result.msgs, &r_tree.msgs); - E_TypeKey c_type = e_type_unwrap(c_tree.type_key); - E_TypeKey l_type = e_type_unwrap(l_tree.type_key); - E_TypeKey r_type = e_type_unwrap(r_tree.type_key); - E_TypeKind c_type_kind = e_type_kind_from_key(c_type); - E_TypeKind l_type_kind = e_type_kind_from_key(l_type); - E_TypeKind r_type_kind = e_type_kind_from_key(r_type); - E_TypeKey result_type = l_type; + result.type_key = e_type_key_unwrap(result.type_key, E_TypeUnwrapFlag_Lenses|E_TypeUnwrapFlag_Meta); + } + }break; - // rjf: bad conditions? -> error if applicable, exit - if(c_tree.root->op == 0 || l_tree.root->op == 0 || r_tree.root->op == 0) + //- rjf: leaf bytecode + case E_ExprKind_LeafBytecode: { - break; - } - else if(!e_type_kind_is_integer(c_type_kind) && c_type_kind != E_TypeKind_Bool) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Conditional term must be an integer or boolean type."); - } - else if(!e_type_match(l_type, r_type)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Left and right terms must have matching types."); - } - - // rjf: generate - { - E_IRNode *c_value_tree = e_irtree_resolve_to_value(arena, c_tree.space, c_tree.mode, c_tree.root, c_type); - E_IRNode *l_value_tree = e_irtree_resolve_to_value(arena, l_tree.space, l_tree.mode, l_tree.root, l_type); - E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.space, r_tree.mode, r_tree.root, r_type); - l_value_tree = e_irtree_convert_hi(arena, l_value_tree, result_type, l_type); - r_value_tree = e_irtree_convert_hi(arena, r_value_tree, result_type, r_type); - E_IRNode *new_tree = e_irtree_conditional(arena, c_value_tree, l_value_tree, r_value_tree); + E_IRNode *new_tree = e_irtree_bytecode_no_copy(arena, expr->bytecode); + new_tree->space = expr->space; + E_TypeKey final_type_key = expr->type_key; result.root = new_tree; - result.type_key = result_type; + result.type_key = final_type_key; + result.mode = expr->mode; + }break; + + //- rjf: leaf string literal + case E_ExprKind_LeafStringLiteral: + { + String8 string = expr->string; + E_TypeKey type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_UChar8), string.size, 0); + E_IRNode *new_tree = e_irtree_string_literal(arena, string); + result.root = new_tree; + result.type_key = type_key; result.mode = E_Mode_Value; - result.space = l_expr->space; - E_Space zero_space = {0}; - if(MemoryMatchStruct(&result.space, &zero_space)) + }break; + + //- rjf: leaf U64s + case E_ExprKind_LeafU64: + { + U64 val = expr->value.u64; + E_IRNode *new_tree = e_irtree_const_u(arena, val); + E_TypeKey type_key = zero_struct; + if(0){} + else if(val <= max_S32){type_key = e_type_key_basic(E_TypeKind_S32);} + else if(val <= max_S64){type_key = e_type_key_basic(E_TypeKind_S64);} + else {type_key = e_type_key_basic(E_TypeKind_U64);} + result.root = new_tree; + result.type_key = type_key; + result.mode = E_Mode_Value; + }break; + + //- rjf: leaf F64s + case E_ExprKind_LeafF64: + { + U64 val = expr->value.u64; + E_IRNode *new_tree = e_irtree_const_u(arena, val); + result.root = new_tree; + result.type_key = e_type_key_basic(E_TypeKind_F64); + result.mode = E_Mode_Value; + }break; + + //- rjf: leaf F32s + case E_ExprKind_LeafF32: + { + U32 val = expr->value.u32; + E_IRNode *new_tree = e_irtree_const_u(arena, val); + result.root = new_tree; + result.type_key = e_type_key_basic(E_TypeKind_F32); + result.mode = E_Mode_Value; + }break; + + //- rjf: leaf identifiers + case E_ExprKind_LeafIdentifier: + { + Temp scratch = scratch_begin(&arena, 1); + B32 is_auto_hook = 0; + String8 qualifier = expr->qualifier; + String8 string = expr->string; + String8 string__redirected = string; + String8List namespaceified_strings = {0}; + B32 string_mapped = 0; + B32 string_is_implicit_member_name = 0; + E_TypeKey mapped_type_key = zero_struct; + E_Module *mapped_location_block_module = &e_module_nil; + RDI_LocationBlock *mapped_location_block = 0; + E_Mode mapped_bytecode_mode = E_Mode_Offset; + E_Space mapped_bytecode_space = zero_struct; + String8 mapped_bytecode = {0}; + void *mapped_user_data = 0; + B32 generated = 0; + + //- rjf: iterate identifier resolution rule paths, try to resolve + // identifier in that order. + for(U64 path_idx = 0; !generated && path_idx < identifier_resolution_rule->count; path_idx += 1) { - result.space = r_expr->space; + //- rjf: try to map identifier via this path + E_IdentifierResolutionPath path = identifier_resolution_rule->paths[path_idx]; + switch(path) + { + default:{}break; + + //- rjf: try to map name as parent expression signifier ('$') + case E_IdentifierResolutionPath_ParentExpr: + if(qualifier.size == 0 && !string_mapped && str8_match(string, str8_lit("$"), 0) && parent != 0 && (parent->root != &e_irnode_nil || parent->msgs.first != 0)) + { + E_IRTreeAndType *parent_irtree = parent; + { + for(E_IRTreeAndType *prev = parent_irtree; prev != 0; prev = prev->prev) + { + parent_irtree = prev; + if(prev->root != &e_irnode_nil) + { + break; + } + } + } + E_OpList oplist = e_oplist_from_irtree(arena, parent_irtree->root); + string_mapped = 1; + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = parent_irtree->mode; + mapped_type_key = parent_irtree->type_key; + mapped_user_data = parent_irtree->user_data; + is_auto_hook = parent_irtree->auto_hook; + disallow_autohooks = 1; + E_MsgList msgs = e_msg_list_copy(arena, &parent_irtree->msgs); + e_msg_list_concat_in_place(&result.msgs, &msgs); + } + break; + + //- rjf: try to map name as implicit access of overridden expression ('$.member_name', where the $. prefix is omitted) + case E_IdentifierResolutionPath_ParentExprMember: + if(qualifier.size == 0 && !string_mapped && parent != 0 && parent->root != &e_irnode_nil) + { + for(E_IRTreeAndType *prev = parent; prev != 0; prev = prev->prev) + { + E_Expr *access = e_expr_irext_member_access(scratch.arena, &e_expr_nil, prev, string); + E_IRTreeAndType access_irtree = e_push_irtree_and_type_from_expr(scratch.arena, root_parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, access); + if(access_irtree.root != &e_irnode_nil) + { + string_mapped = 1; + E_OpList oplist = e_oplist_from_irtree(scratch.arena, access_irtree.root); + mapped_type_key = access_irtree.type_key; + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = access_irtree.mode; + e_msg_list_concat_in_place(&result.msgs, &access_irtree.msgs); + break; + } + } + }break; + + //- rjf: try to map name as member of `this` - if found, string__redirected := "this", and turn + // on later implicit-member-lookup generation + case E_IdentifierResolutionPath_ImplicitThisMember: + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("member"), 0))) + { + E_Module *module = e_base_ctx->primary_module; + U32 module_idx = (U32)(module - e_base_ctx->modules); + RDI_Parsed *rdi = module->rdi; + RDI_Procedure *procedure = e_cache->thread_ip_procedure; + RDI_UDT *udt = rdi_container_udt_from_procedure(rdi, procedure); + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + E_TypeKey container_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), udt->self_type_idx, module_idx); + E_Member member = e_type_member_from_key_name__cached(container_type_key, string); + if(member.kind != E_MemberKind_Null) + { + string_is_implicit_member_name = 1; + string__redirected = str8_lit("this"); + } + }break; + + //- rjf: try locals + case E_IdentifierResolutionPath_Local: + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("local"), 0))) + { + E_Module *module = e_base_ctx->primary_module; + U32 module_idx = (U32)(module - e_base_ctx->modules); + RDI_Parsed *rdi = module->rdi; + U64 local_num = e_num_from_string(e_ir_ctx->locals_map, string__redirected); + if(local_num != 0) + { + RDI_Local *local = rdi_element_from_name_idx(rdi, Locals, local_num-1); + + // rjf: extract local's type key + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local->type_idx); + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local->type_idx, module_idx); + + // rjf: extract local's location block + U64 ip_voff = e_base_ctx->thread_ip_voff; + for(U32 loc_block_idx = local->location_first; + loc_block_idx < local->location_opl; + loc_block_idx += 1) + { + RDI_LocationBlock *block = rdi_element_from_name_idx(rdi, LocationBlocks, loc_block_idx); + if(block->scope_off_first <= ip_voff && ip_voff < block->scope_off_opl) + { + mapped_location_block_module = module; + mapped_location_block = block; + } + } + } + }break; + + //- rjf: globals / procedures / types + case E_IdentifierResolutionPath_Globals: + case E_IdentifierResolutionPath_Procedures: + case E_IdentifierResolutionPath_ThreadLocals: + { + //- rjf: form namespaceified fallback versions of this lookup string + if(!string_mapped) + { + E_Module *module = e_base_ctx->primary_module; + RDI_Parsed *rdi = module->rdi; + RDI_Procedure *procedure = e_cache->thread_ip_procedure; + U64 name_size = 0; + U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); + String8 containing_procedure_name = str8(name_ptr, name_size); + U64 last_past_scope_resolution_pos = 0; + for(;;) + { + U64 past_next_dbl_colon_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("::"), 0)+2; + U64 past_next_dot_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("."), 0)+1; + U64 past_next_scope_resolution_pos = Min(past_next_dbl_colon_pos, past_next_dot_pos); + if(past_next_scope_resolution_pos >= containing_procedure_name.size) + { + break; + } + String8 new_namespace_prefix_possibility = str8_prefix(containing_procedure_name, past_next_scope_resolution_pos); + String8 namespaceified_string = push_str8f(scratch.arena, "%S%S", new_namespace_prefix_possibility, string); + str8_list_push_front(scratch.arena, &namespaceified_strings, namespaceified_string); + last_past_scope_resolution_pos = past_next_scope_resolution_pos; + } + } + + //- rjf: try globals + if(path == E_IdentifierResolutionPath_Globals && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("global"), 0))) + { + for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1) + { + E_Module *module = &e_base_ctx->modules[module_idx]; + RDI_Parsed *rdi = module->rdi; + RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size); + U32 matches_count = 0; + U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); + for(String8Node *n = namespaceified_strings.first; + n != 0 && matches_count == 0; + n = n->next) + { + node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); + matches_count = 0; + matches = rdi_matches_from_map_node(rdi, node, &matches_count); + } + if(matches_count != 0) + { + U32 match_idx = matches[matches_count-1]; + RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, match_idx); + U32 type_idx = global_var->type_idx; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); + E_OpList oplist = {0}; + e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff)); + string_mapped = 1; + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = module->space; + break; + } + } + } + + //- rjf: try thread-locals + if(path == E_IdentifierResolutionPath_ThreadLocals && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("thread_local"), 0))) + { + for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1) + { + E_Module *module = &e_base_ctx->modules[module_idx]; + RDI_Parsed *rdi = module->rdi; + RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_ThreadVariables); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size); + U32 matches_count = 0; + U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); + for(String8Node *n = namespaceified_strings.first; + n != 0 && matches_count == 0; + n = n->next) + { + node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); + matches_count = 0; + matches = rdi_matches_from_map_node(rdi, node, &matches_count); + } + if(matches_count != 0) + { + U32 match_idx = matches[matches_count-1]; + RDI_ThreadVariable *thread_var = rdi_element_from_name_idx(rdi, ThreadVariables, match_idx); + U32 type_idx = thread_var->type_idx; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); + E_OpList oplist = {0}; + e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off)); + string_mapped = 1; + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = module->space; + break; + } + } + } + + //- rjf: try procedures + if(path == E_IdentifierResolutionPath_Procedures && !string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("procedure"), 0))) + { + for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1) + { + E_Module *module = &e_base_ctx->modules[module_idx]; + RDI_Parsed *rdi = module->rdi; + RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, string.str, string.size); + U32 matches_count = 0; + U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); + for(String8Node *n = namespaceified_strings.first; + n != 0 && matches_count == 0; + n = n->next) + { + node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); + matches_count = 0; + matches = rdi_matches_from_map_node(rdi, node, &matches_count); + } + if(matches_count != 0) + { + U32 match_idx = matches[matches_count-1]; + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match_idx); + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); + U64 voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first); + U32 type_idx = procedure->type_idx; + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); + E_OpList oplist = {0}; + e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); + string_mapped = 1; + mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Value; + mapped_bytecode_space = module->space; + break; + } + } + } + }break; + + //- rjf: try types + case E_IdentifierResolutionPath_Types: + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("type"), 0))) + { + mapped_type_key = e_leaf_type_from_name(string); + if(!e_type_key_match(e_type_key_zero(), mapped_type_key)) + { + string_mapped = 1; + } + }break; + + + //- rjf: try registers + case E_IdentifierResolutionPath_Registers: + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("reg"), 0))) + { + U64 reg_num = e_num_from_string(e_ir_ctx->regs_map, string); + if(reg_num != 0) + { + string_mapped = 1; + REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(e_base_ctx->primary_module->arch)[reg_num]; + E_OpList oplist = {0}; + e_oplist_push_uconst(arena, &oplist, reg_rng.byte_off); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = e_base_ctx->thread_reg_space; + mapped_type_key = e_type_key_reg(e_base_ctx->primary_module->arch, reg_num); + } + }break; + + //- rjf: try register aliases + case E_IdentifierResolutionPath_RegisterAliases: + if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("reg"), 0))) + { + U64 alias_num = e_num_from_string(e_ir_ctx->reg_alias_map, string); + if(alias_num != 0) + { + string_mapped = 1; + REGS_Slice alias_slice = regs_alias_code_slice_table_from_arch(e_base_ctx->primary_module->arch)[alias_num]; + REGS_Rng alias_reg_rng = regs_reg_code_rng_table_from_arch(e_base_ctx->primary_module->arch)[alias_slice.code]; + E_OpList oplist = {0}; + e_oplist_push_uconst(arena, &oplist, alias_reg_rng.byte_off + alias_slice.byte_off); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = e_base_ctx->thread_reg_space; + mapped_type_key = e_type_key_reg_alias(e_base_ctx->primary_module->arch, alias_num); + } + }break; + + //- rjf: try basic constants + case E_IdentifierResolutionPath_Constants: + if(!string_mapped && str8_match(string, str8_lit("true"), 0)) + { + string_mapped = 1; + E_OpList oplist = {0}; + e_oplist_push_uconst(arena, &oplist, 1); + mapped_type_key = e_type_key_basic(E_TypeKind_Bool); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Value; + } + if(!string_mapped && str8_match(string, str8_lit("false"), 0)) + { + string_mapped = 1; + E_OpList oplist = {0}; + e_oplist_push_uconst(arena, &oplist, 0); + mapped_type_key = e_type_key_basic(E_TypeKind_Bool); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Value; + }break; + + //- rjf: try macros + case E_IdentifierResolutionPath_Macros: + { + if(!generated) + { + E_Expr *macro_expr = e_string2expr_map_lookup(e_ir_ctx->macro_map, string); + if(macro_expr != &e_expr_nil) + { + generated = 1; + e_string2expr_map_inc_poison(e_ir_ctx->macro_map, string); + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, macro_expr); + e_string2expr_map_dec_poison(e_ir_ctx->macro_map, string); + } + } + }break; + } + + //- rjf: mapped to location block -> extract or produce bytecode for this mapping + if(!generated && mapped_location_block != 0) + { + E_Module *module = mapped_location_block_module; + E_Space space = module->space; + Arch arch = module->arch; + RDI_Parsed *rdi = module->rdi; + RDI_LocationBlock *block = mapped_location_block; + U64 all_location_data_size = 0; + U8 *all_location_data = rdi_table_from_name(rdi, LocationData, &all_location_data_size); + if(block->location_data_off + sizeof(RDI_LocationKind) <= all_location_data_size) + { + RDI_LocationKind loc_kind = *((RDI_LocationKind *)(all_location_data + block->location_data_off)); + switch(loc_kind) + { + default:{}break; + case RDI_LocationKind_ValBytecodeStream: {mapped_bytecode_mode = E_Mode_Value;}goto bytecode_stream; + case RDI_LocationKind_AddrBytecodeStream:{mapped_bytecode_mode = E_Mode_Offset;}goto bytecode_stream; + bytecode_stream:; + { + string_mapped = 1; + U64 bytecode_size = 0; + U64 off_first = block->location_data_off + sizeof(RDI_LocationKind); + U64 off_opl = all_location_data_size; + for(U64 off = off_first, next_off = off_opl; + off < all_location_data_size; + off = next_off) + { + next_off = off_opl; + U8 op = all_location_data[off]; + if(op == 0) + { + break; + } + U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; + U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + bytecode_size += (1 + p_size); + next_off = (off + 1 + p_size); + } + mapped_bytecode = str8(all_location_data + off_first, bytecode_size); + }break; + case RDI_LocationKind_AddrRegPlusU16: + if(block->location_data_off + sizeof(RDI_LocationRegPlusU16) <= all_location_data_size) + { + string_mapped = 1; + RDI_LocationRegPlusU16 loc = *(RDI_LocationRegPlusU16 *)(all_location_data + block->location_data_off); + E_OpList oplist = {0}; + U64 byte_size = bit_size_from_arch(arch)/8; + U64 regread_param = RDI_EncodeRegReadParam(loc.reg_code, byte_size, 0); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, e_value_u64(loc.offset)); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, e_value_u64(0)); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = space; + }break; + case RDI_LocationKind_AddrAddrRegPlusU16: + { + string_mapped = 1; + RDI_LocationRegPlusU16 loc = *(RDI_LocationRegPlusU16 *)(all_location_data + block->location_data_off); + E_OpList oplist = {0}; + U64 byte_size = bit_size_from_arch(arch)/8; + U64 regread_param = RDI_EncodeRegReadParam(loc.reg_code, byte_size, 0); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, e_value_u64(loc.offset)); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, e_value_u64(0)); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_MemRead, e_value_u64(bit_size_from_arch(arch)/8)); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Offset; + mapped_bytecode_space = space; + }break; + case RDI_LocationKind_ValReg: + if(block->location_data_off + sizeof(RDI_LocationReg) <= all_location_data_size) + { + string_mapped = 1; + RDI_LocationReg loc = *(RDI_LocationReg *)(all_location_data + block->location_data_off); + + REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(arch, loc.reg_code); + REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(arch)[regs_reg_code]; + E_OpList oplist = {0}; + U64 byte_size = (U64)reg_rng.byte_size; + U64 byte_pos = 0; + U64 regread_param = RDI_EncodeRegReadParam(loc.reg_code, byte_size, byte_pos); + e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); + mapped_bytecode = e_bytecode_from_oplist(arena, &oplist); + mapped_bytecode_mode = E_Mode_Value; + mapped_bytecode_space = space; + }break; + } + } + } + + //- rjf: generate IR trees for bytecode + if(!generated && mapped_bytecode.size != 0) + { + generated = 1; + E_IRNode *root = e_irtree_bytecode_no_copy(arena, mapped_bytecode); + root->space = mapped_bytecode_space; + result.root = root; + result.type_key = mapped_type_key; + result.mode = mapped_bytecode_mode; + } + + //- rjf: generate nil-IR trees w/ type for types + if(!generated && !e_type_key_match(e_type_key_zero(), mapped_type_key)) + { + generated = 1; + result.root = e_irtree_const_u(arena, 0); + result.type_key = mapped_type_key; + result.mode = E_Mode_Null; + } + } + + //- rjf: extend generated result, if result was generated by an implicit member access + if(generated && string_is_implicit_member_name) + { + E_Expr *access = e_expr_irext_member_access(arena, &e_expr_nil, &result, string); + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, access); + } + + //- rjf: mark if auto hook, equip user data + result.auto_hook = is_auto_hook; + result.user_data = mapped_user_data; + + //- rjf: error on failure-to-generate + if(!generated && !str8_match(string, str8_lit("$"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_ResolutionFailure, expr->range, "`%S` could not be found.", string); + } + + scratch_end(scratch); + }break; + + //- rjf: leaf offsets + case E_ExprKind_LeafOffset: + { + E_IRNode *new_tree = e_push_irnode(arena, RDI_EvalOp_ConstU64); + new_tree->value = expr->value; + new_tree->space = expr->space; + result.root = new_tree; + result.type_key = expr->type_key; + result.mode = E_Mode_Offset; + }break; + + //- rjf: leaf values + case E_ExprKind_LeafValue: + { + E_IRNode *new_tree = e_push_irnode(arena, RDI_EvalOp_ConstU128); + new_tree->value = expr->value; + new_tree->space = expr->space; + result.root = new_tree; + result.type_key = expr->type_key; + result.mode = E_Mode_Value; + }break; + + //- rjf: leaf file paths + case E_ExprKind_LeafFilePath: + { + Temp scratch = scratch_begin(&arena, 1); + String8 file_path = expr->string; + FileProperties props = os_properties_from_file_path(file_path); + if(!str8_match(expr->qualifier, str8_lit("folder"), 0) && !(props.flags & FilePropertyFlag_IsFolder) && file_path.size != 0) + { + E_Space space = e_space_make(E_SpaceKind_FileSystem); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, e_id_from_string(file_path))); + result.type_key = e_cache->file_type_key; + result.mode = E_Mode_Value; + } + else + { + String8 folder_path = str8_chop_last_slash(file_path); + props = os_properties_from_file_path(folder_path); + if(props.flags & FilePropertyFlag_IsFolder || folder_path.size == 0 || str8_match(folder_path, str8_lit("/"), StringMatchFlag_SlashInsensitive)) + { + E_Space space = e_space_make(E_SpaceKind_FileSystem); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, e_id_from_string(folder_path))); + result.type_key = e_cache->folder_type_key; + result.mode = E_Mode_Value; + } + } + scratch_end(scratch); + }break; + + //- rjf: types + case E_ExprKind_TypeIdent: + { + result.root = e_irtree_const_u(arena, 0); + result.root->space = expr->space; + result.type_key = expr->type_key; + result.mode = E_Mode_Null; + }break; + case E_ExprKind_Unsigned: + { + E_IRTreeAndType direct_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first); + result = direct_irtree; + E_TypeKey direct_type_key = result.type_key; + E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); + if(e_type_kind_is_signed(direct_type_kind)) + { + E_TypeKind new_kind = direct_type_kind; + switch(direct_type_kind) + { + default:{}break; + case E_TypeKind_Char8: {new_kind = E_TypeKind_UChar8;}break; + case E_TypeKind_Char16:{new_kind = E_TypeKind_UChar16;}break; + case E_TypeKind_Char32:{new_kind = E_TypeKind_UChar32;}break; + case E_TypeKind_S8:{new_kind = E_TypeKind_U8;}break; + case E_TypeKind_S16:{new_kind = E_TypeKind_U16;}break; + case E_TypeKind_S32:{new_kind = E_TypeKind_U32;}break; + case E_TypeKind_S64:{new_kind = E_TypeKind_U64;}break; + case E_TypeKind_S128:{new_kind = E_TypeKind_U128;}break; + case E_TypeKind_S256:{new_kind = E_TypeKind_U256;}break; + case E_TypeKind_S512:{new_kind = E_TypeKind_U512;}break; + } + result.type_key = e_type_key_basic(new_kind); + } + else + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->first->range, "Cannot apply an `unsigned` modifier to this type."); + } + }break; + case E_ExprKind_Ptr: + { + E_IRTreeAndType ptee_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first); + result = ptee_irtree; + result.type_key = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, result.type_key, 1, 0); + }break; + case E_ExprKind_Array: + { + E_IRTreeAndType element_irtree = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, expr->first); + result = element_irtree; + result.type_key = e_type_key_cons_array(result.type_key, expr->value.u64, 0); + }break; + case E_ExprKind_Func: + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Function type expressions are currently not supported."); + }break; + + //- rjf: definitions + case E_ExprKind_Define: + { + E_Expr *lhs = expr->first; + E_Expr *rhs = lhs->next; + result = e_push_irtree_and_type_from_expr(arena, parent, &e_default_identifier_resolution_rule, disallow_autohooks, 1, rhs); + if(lhs->kind != E_ExprKind_LeafIdentifier) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->range, "Left side of assignment must be an unused identifier."); + } + }break; + } + + //- rjf: check chained expressions for simple wrappers + if(!disallow_chained_fastpaths) + { + local_persist struct + { + String8 shorthand; + String8 full_name; + } + shorthand_lens_pair_table[] = + { + {str8_lit_comp("x"), str8_lit_comp("hex")}, + {str8_lit_comp("b"), str8_lit_comp("bin")}, + {str8_lit_comp("o"), str8_lit_comp("oct")}, + {str8_lit_comp("d"), str8_lit_comp("dec")}, + }; + E_Expr *first_chained = expr->next; + for(E_Expr *chained_expr = first_chained; + chained_expr != &e_expr_nil; + chained_expr = chained_expr->next) + { + B32 matches_shorthand = 0; + if(chained_expr->kind == E_ExprKind_LeafIdentifier) + { + for EachElement(shorthand_idx, shorthand_lens_pair_table) + { + if(str8_match(chained_expr->string, shorthand_lens_pair_table[shorthand_idx].shorthand, 0)) + { + String8 full_name = shorthand_lens_pair_table[shorthand_idx].full_name; + result.type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .direct_key = result.type_key, + .name = full_name); + matches_shorthand = 1; + break; + } + } + } + if(!matches_shorthand) + { + E_TypeKind type_kind = e_type_kind_from_key(e_type_key_unwrap(result.type_key, E_TypeUnwrapFlag_AllDecorative)); + if(e_type_kind_is_pointer_or_ref(type_kind) || + type_kind == E_TypeKind_Array) + { + E_Expr *lens_spec_expr = e_string2expr_map_lookup(e_ir_ctx->macro_map, str8_lit("array")); + E_TypeKey lens_spec_type_key = lens_spec_expr->type_key; + E_Type *lens_spec_type = e_type_from_key(lens_spec_type_key); + result.type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .flags = lens_spec_type->flags, + .count = 1, + .args = &chained_expr, + .direct_key = result.type_key, + .name = lens_spec_type->name, + .irext = lens_spec_type->irext, + .access = lens_spec_type->access, + .expand = lens_spec_type->expand); + } } } - }break; + } - //- rjf: leaf bytecode - case E_ExprKind_LeafBytecode: + //- rjf: if the evaluated type has a hook for an extra layer of ir extension, + // call into it + E_Type *type = e_type_from_key(result.type_key); { - E_IRNode *new_tree = e_irtree_bytecode_no_copy(arena, expr->bytecode); - E_TypeKey final_type_key = expr->type_key; - result.root = new_tree; - result.type_key = final_type_key; - result.mode = expr->mode; - result.space = expr->space; - }break; - - //- rjf: (unexpected) leaf member - case E_ExprKind_LeafMember: - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "(internal) Leaf member not expected here."); - }break; - - //- rjf: leaf string literal - case E_ExprKind_LeafStringLiteral: - { - String8 string = expr->string; - E_TypeKey type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_UChar8), string.size); - E_IRNode *new_tree = e_irtree_string_literal(arena, string); - result.root = new_tree; - result.type_key = type_key; - result.mode = E_Mode_Value; - }break; - - //- rjf: leaf bools - case E_ExprKind_LeafBool: - { - result.root = e_irtree_const_u(arena, expr->value.u64); - result.type_key = expr->type_key; - result.mode = E_Mode_Value; - }break; - - //- rjf: leaf U64s - case E_ExprKind_LeafU64: - { - U64 val = expr->value.u64; - E_IRNode *new_tree = e_irtree_const_u(arena, val); - E_TypeKey type_key = zero_struct; - if(0){} - else if(val <= max_S32){type_key = e_type_key_basic(E_TypeKind_S32);} - else if(val <= max_S64){type_key = e_type_key_basic(E_TypeKind_S64);} - else {type_key = e_type_key_basic(E_TypeKind_U64);} - result.root = new_tree; - result.type_key = type_key; - result.mode = E_Mode_Value; - }break; - - //- rjf: leaf F64s - case E_ExprKind_LeafF64: - { - U64 val = expr->value.u64; - E_IRNode *new_tree = e_irtree_const_u(arena, val); - result.root = new_tree; - result.type_key = e_type_key_basic(E_TypeKind_F64); - result.mode = E_Mode_Value; - }break; - - //- rjf: leaf F32s - case E_ExprKind_LeafF32: - { - U32 val = expr->value.u32; - E_IRNode *new_tree = e_irtree_const_u(arena, val); - result.root = new_tree; - result.type_key = e_type_key_basic(E_TypeKind_F32); - result.mode = E_Mode_Value; - }break; - - //- rjf: leaf identifiers - case E_ExprKind_LeafIdent: - { - E_Expr *macro_expr = e_string2expr_lookup(e_ir_ctx->macro_map, expr->string); - if(macro_expr == &e_expr_nil) + E_TypeIRExtFunctionType *irext = type->irext; + for(E_Type *t = type; t->kind == E_TypeKind_Lens || t->kind == E_TypeKind_Set; t = e_type_from_key(t->direct_type_key)) { - e_msgf(arena, &result.msgs, E_MsgKind_ResolutionFailure, expr->location, "`%S` could not be found.", expr->string); + if(t->irext != 0) + { + irext = t->irext; + break; + } } - else + if(irext != 0 && result.user_data == 0) { - e_string2expr_map_inc_poison(e_ir_ctx->macro_map, expr->string); - result = e_irtree_and_type_from_expr(arena, macro_expr); - e_string2expr_map_dec_poison(e_ir_ctx->macro_map, expr->string); + E_IRTreeAndType irtree_stripped = result; + if(type->kind == E_TypeKind_Lens) + { + irtree_stripped.type_key = e_type_key_direct(irtree_stripped.type_key); + } + E_IRExt ext = irext(arena, expr, &irtree_stripped); + result.user_data = ext.user_data; } - }break; + } - //- rjf: leaf offsets - case E_ExprKind_LeafOffset: + //- rjf: if the evaluated type has a virtual table pointer, then we must + // pre-emptively evaluate this ir tree, and determine a more resolved type. + if(!disallow_autohooks && result.mode != E_Mode_Null) { - E_IRNode *new_tree = e_push_irnode(arena, RDI_EvalOp_ConstU64); - new_tree->value.u64 = expr->value.u64; - result.root = new_tree; - result.type_key = expr->type_key; - result.mode = E_Mode_Offset; - result.space = expr->space; - }break; - - //- rjf: leaf file paths - case E_ExprKind_LeafFilePath: - { - U128 key = fs_key_from_path_range(expr->string, r1u64(0, max_U64)); - E_Space space = {E_SpaceKind_FileSystem, .u128 = key}; - U64 size = fs_size_from_path(expr->string); - E_IRNode *base_offset = e_irtree_const_u(arena, 0); - E_IRNode *set_space = e_irtree_set_space(arena, space, base_offset); - result.root = set_space; - result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), size); - result.mode = E_Mode_Offset; - result.space = space; - }break; - - //- rjf: types - case E_ExprKind_TypeIdent: - { - result.root = e_irtree_const_u(arena, 0); - result.type_key = expr->type_key; - result.mode = E_Mode_Null; - result.space = expr->space; - }break; - - //- rjf: (unexpected) type expressions - case E_ExprKind_Ptr: - case E_ExprKind_Array: - case E_ExprKind_Func: - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Type expression not expected."); - }break; - - //- rjf: definitions - case E_ExprKind_Define: - { - E_Expr *lhs = expr->first; - E_Expr *rhs = lhs->next; - result = e_irtree_and_type_from_expr(arena, rhs); - if(lhs->kind != E_ExprKind_LeafIdent) + E_TypeKey type_key = e_type_key_unwrap(result.type_key, E_TypeUnwrapFlag_Modifiers); + if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(type_key))) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, expr->location, "Left side of assignment must be an unused identifier."); + E_TypeKey ptee_key = e_type_key_unwrap(result.type_key, E_TypeUnwrapFlag_All); + E_TypeKind ptee_kind = e_type_kind_from_key(ptee_key); + if(ptee_kind == E_TypeKind_Struct || + ptee_kind == E_TypeKind_Class) + { + E_Type *ptee_type = e_type_from_key(ptee_key); + B32 has_vtable = 0; + for(U64 idx = 0; idx < ptee_type->count; idx += 1) + { + if(ptee_type->members[idx].kind == E_MemberKind_VirtualMethod) + { + has_vtable = 1; + break; + } + } + if(has_vtable) + { + E_IRNode *class_base_value_tree = e_irtree_resolve_to_value(scratch.arena, result.mode, result.root, result.type_key); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, class_base_value_tree); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + U64 class_base_vaddr = interpret.value.u64; + U64 vtable_vaddr = 0; + U64 addr_size = e_type_byte_size_from_key(type_key); + if(e_space_read(interpret.space, &vtable_vaddr, r1u64(class_base_vaddr, class_base_vaddr+addr_size))) + { + Arch arch = e_base_ctx->primary_module->arch; + U32 rdi_idx = 0; + RDI_Parsed *rdi = 0; + U64 module_base = 0; + for(U64 idx = 0; idx < e_base_ctx->modules_count; idx += 1) + { + if(contains_1u64(e_base_ctx->modules[idx].vaddr_range, vtable_vaddr)) + { + arch = e_base_ctx->modules[idx].arch; + rdi_idx = (U32)idx; + rdi = e_base_ctx->modules[idx].rdi; + module_base = e_base_ctx->modules[idx].vaddr_range.min; + break; + } + } + if(rdi != 0) + { + U64 vtable_voff = vtable_vaddr - module_base; + U64 global_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, vtable_voff); + RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, global_idx); + if(global_var->link_flags & RDI_LinkFlag_TypeScoped) + { + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, global_var->container_idx); + RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); + E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, rdi_idx); + E_TypeKey ptr_to_derived_type_key = e_type_key_cons_ptr(arch, derived_type_key, 1, 0); + result.type_key = ptr_to_derived_type_key; + } + } + } + } + } } - }break; + } + //- rjf: equip previous task's irtree + if(parent != 0) + { + result.prev = push_array(arena, E_IRTreeAndType, 1); + result.prev[0] = *parent; + } + + //- rjf: mark this result as an auto-hook, if we have an override + if(t->overridden) + { + result.auto_hook = 1; + } + + //- rjf: find any auto hooks according to this generation's type + if(!disallow_autohooks && result.mode != E_Mode_Null) + { + E_ExprList exprs = e_auto_hook_exprs_from_type_key__cached(result.type_key); + for(E_ExprNode *n = exprs.first; n != 0; n = n->next) + { + for(E_Expr *e = n->v; e != &e_expr_nil; e = e->next) + { + B32 e_is_poisoned = e_expr_is_poisoned(e); + if(!e_is_poisoned) + { + Task *task = push_array(scratch.arena, Task, 1); + SLLQueuePush(first_task, last_task, task); + task->expr = e; + task->overridden = push_array(scratch.arena, E_IRTreeAndType, 1); + task->overridden[0] = result; + goto end_autohook_find; + } + } + } + end_autohook_find:; + } } + ////////////////////////////// + //- rjf: unpoison the tags we used + // + for(Task *t = first_task; t != 0; t = t->next) + { + e_expr_unpoison(t->expr); + } + + ////////////////////////////// + //- rjf: apply inherited lenses to the resultant type + // + if(inherited_lenses.count != 0) + { + E_Type *result_type = e_type_from_key(result.type_key); + for(E_TypeKeyNode *n = inherited_lenses.first; n != 0; n = n->next) + { + E_Type *src_type = e_type_from_key(n->v); + E_TypeKey dst_type_key = e_type_key_cons(.kind = src_type->kind, + .flags = src_type->flags, + .name = src_type->name, + .count = src_type->count, + .args = src_type->args, + .irext = src_type->irext, + .access = src_type->access, + .expand = src_type->expand, + .direct_key = result.type_key); + result.type_key = dst_type_key; + } + } + + scratch_end(scratch); + ProfEnd(); return result; } //- rjf: irtree -> linear ops/bytecode internal void -e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_OpList *out) +e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_Space *current_space, E_OpList *out) { U32 op = root->op; + { + E_Space zero_space = zero_struct; + if(!MemoryMatchStruct(&root->space, &zero_space) && + !MemoryMatchStruct(&root->space, current_space)) + { + *current_space = root->space; + e_oplist_push_set_space(arena, out, root->space); + } + } switch(op) { case RDI_EvalOp_Stop: @@ -1382,9 +2465,8 @@ e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_OpList *out) child != &e_irnode_nil; child = child->next) { - e_append_oplist_from_irtree(arena, child, out); + e_append_oplist_from_irtree(arena, child, current_space, out); } - }break; case RDI_EvalOp_Cond: @@ -1434,7 +2516,7 @@ e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_OpList *out) child != &e_irnode_nil && idx < child_count; child = child->next, idx += 1) { - e_append_oplist_from_irtree(arena, child, out); + e_append_oplist_from_irtree(arena, child, current_space, out); } // rjf: emit op to compute this node @@ -1448,7 +2530,8 @@ internal E_OpList e_oplist_from_irtree(Arena *arena, E_IRNode *root) { E_OpList ops = {0}; - e_append_oplist_from_irtree(arena, root, &ops); + E_Space space = e_interpret_ctx->primary_space; + e_append_oplist_from_irtree(arena, root, &space, &ops); return ops; } @@ -1537,3 +2620,24 @@ e_bytecode_from_oplist(Arena *arena, E_OpList *oplist) result.str = str; return result; } + +//- rjf: leaf-bytecode expression extensions + +internal E_Expr * +e_expr_irext_member_access(Arena *arena, E_Expr *lhs, E_IRTreeAndType *lhs_irtree, String8 member_name) +{ + E_Expr *root = e_push_expr(arena, E_ExprKind_MemberAccess, r1u64(0, 0)); + E_Expr *lhs_bytecode = e_push_expr(arena, E_ExprKind_LeafBytecode, lhs->range); + E_OpList lhs_oplist = e_oplist_from_irtree(arena, lhs_irtree->root); + lhs_bytecode->string = e_string_from_expr(arena, lhs, str8_zero()); + lhs_bytecode->qualifier = lhs->qualifier; + lhs_bytecode->space = lhs->space; + lhs_bytecode->mode = lhs_irtree->mode; + lhs_bytecode->type_key = lhs_irtree->type_key; + lhs_bytecode->bytecode = e_bytecode_from_oplist(arena, &lhs_oplist); + E_Expr *rhs = e_push_expr(arena, E_ExprKind_LeafIdentifier, r1u64(0, 0)); + rhs->string = push_str8_copy(arena, member_name); + e_expr_push_child(root, lhs_bytecode); + e_expr_push_child(root, rhs); + return root; +} diff --git a/src/eval/eval_ir.h b/src/eval/eval_ir.h index d5485c1f..c7b9e338 100644 --- a/src/eval/eval_ir.h +++ b/src/eval/eval_ir.h @@ -5,83 +5,121 @@ #define EVAL_IR_H //////////////////////////////// -//~ rjf: Bytecode Operation Types +//~ rjf: Identifier Resolution Rule Types -enum +typedef enum E_IdentifierResolutionPath { - E_IRExtKind_Bytecode = RDI_EvalOp_COUNT, - E_IRExtKind_SetSpace, - E_IRExtKind_COUNT -}; + E_IdentifierResolutionPath_ParentExpr, + E_IdentifierResolutionPath_ParentExprMember, + E_IdentifierResolutionPath_ImplicitThisMember, + E_IdentifierResolutionPath_Local, + E_IdentifierResolutionPath_Globals, + E_IdentifierResolutionPath_ThreadLocals, + E_IdentifierResolutionPath_Procedures, + E_IdentifierResolutionPath_Types, + E_IdentifierResolutionPath_Registers, + E_IdentifierResolutionPath_RegisterAliases, + E_IdentifierResolutionPath_Constants, + E_IdentifierResolutionPath_Macros, +} +E_IdentifierResolutionPath; -typedef struct E_Op E_Op; -struct E_Op +typedef struct E_IdentifierResolutionRule E_IdentifierResolutionRule; +struct E_IdentifierResolutionRule { - E_Op *next; - RDI_EvalOp opcode; - E_Value value; - String8 string; -}; - -typedef struct E_OpList E_OpList; -struct E_OpList -{ - E_Op *first; - E_Op *last; - U64 op_count; - U64 encoded_size; + E_IdentifierResolutionPath *paths; + U64 count; }; //////////////////////////////// -//~ rjf: IR Tree Types +//~ rjf: IR State -typedef struct E_IRNode E_IRNode; -struct E_IRNode +typedef struct E_IRCacheNode E_IRCacheNode; +struct E_IRCacheNode { - E_IRNode *first; - E_IRNode *last; - E_IRNode *next; - RDI_EvalOp op; - String8 string; - E_Value value; + E_IRCacheNode *next; + E_Expr *expr; + E_IRNode *overridden_node; + E_IRTreeAndType irtree; }; -typedef struct E_IRTreeAndType E_IRTreeAndType; -struct E_IRTreeAndType +typedef struct E_IRCacheSlot E_IRCacheSlot; +struct E_IRCacheSlot { - E_IRNode *root; - E_TypeKey type_key; - E_Mode mode; - E_Space space; - E_MsgList msgs; + E_IRCacheNode *first; + E_IRCacheNode *last; }; -//////////////////////////////// -//~ rjf: Parse Context - -typedef struct E_IRCtx E_IRCtx; -struct E_IRCtx +typedef struct E_IRState E_IRState; +struct E_IRState { - E_String2ExprMap *macro_map; + Arena *arena; + U64 arena_eval_start_pos; + + // rjf: ir context + E_IRCtx *ctx; + + // rjf: unpacked ctx + RDI_Procedure *thread_ip_procedure; + + // rjf: overridden irtree + E_IRTreeAndType *overridden_irtree; + B32 disallow_autohooks; + B32 disallow_chained_fastpaths; + + // rjf: caches + E_UsedExprMap *used_expr_map; + E_TypeAutoHookCacheMap *type_auto_hook_cache_map; + U64 string_id_gen; + E_StringIDMap *string_id_map; + U64 ir_cache_slots_count; + E_IRCacheSlot *ir_cache_slots; }; //////////////////////////////// //~ rjf: Globals -global read_only E_IRNode e_irnode_nil = {&e_irnode_nil, &e_irnode_nil, &e_irnode_nil}; -thread_static E_IRCtx *e_ir_ctx = 0; +E_IdentifierResolutionPath e_default_identifier_resolution_paths[] = +{ + E_IdentifierResolutionPath_ParentExpr, + E_IdentifierResolutionPath_ParentExprMember, + E_IdentifierResolutionPath_ImplicitThisMember, + E_IdentifierResolutionPath_Local, + E_IdentifierResolutionPath_Globals, + E_IdentifierResolutionPath_ThreadLocals, + E_IdentifierResolutionPath_Procedures, + E_IdentifierResolutionPath_Types, + E_IdentifierResolutionPath_Registers, + E_IdentifierResolutionPath_RegisterAliases, + E_IdentifierResolutionPath_Constants, + E_IdentifierResolutionPath_Macros, +}; +E_IdentifierResolutionRule e_default_identifier_resolution_rule = +{ + e_default_identifier_resolution_paths, + ArrayCount(e_default_identifier_resolution_paths), +}; -//////////////////////////////// -//~ rjf: Expr Kind Enum Functions - -internal RDI_EvalOp e_opcode_from_expr_kind(E_ExprKind kind); -internal B32 e_expr_kind_is_comparison(E_ExprKind kind); - -//////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) - -internal E_IRCtx *e_selected_ir_ctx(void); -internal void e_select_ir_ctx(E_IRCtx *ctx); +E_IdentifierResolutionPath e_callable_identifier_resolution_paths[] = +{ + E_IdentifierResolutionPath_Macros, + E_IdentifierResolutionPath_ParentExpr, + E_IdentifierResolutionPath_ParentExprMember, + E_IdentifierResolutionPath_ImplicitThisMember, + E_IdentifierResolutionPath_Local, + E_IdentifierResolutionPath_Globals, + E_IdentifierResolutionPath_ThreadLocals, + E_IdentifierResolutionPath_Procedures, + E_IdentifierResolutionPath_Types, + E_IdentifierResolutionPath_Registers, + E_IdentifierResolutionPath_RegisterAliases, + E_IdentifierResolutionPath_Constants, +}; +E_IdentifierResolutionRule e_callable_identifier_resolution_rule = +{ + e_callable_identifier_resolution_paths, + ArrayCount(e_callable_identifier_resolution_paths), +}; //////////////////////////////// //~ rjf: IR-ization Functions @@ -101,6 +139,7 @@ internal void e_irnode_push_child(E_IRNode *parent, E_IRNode *child); //- rjf: ir subtree building helpers internal E_IRNode *e_irtree_const_u(Arena *arena, U64 v); +internal E_IRNode *e_irtree_leaf_u128(Arena *arena, U128 u128); internal E_IRNode *e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *c); internal E_IRNode *e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r); internal E_IRNode *e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r); @@ -108,18 +147,27 @@ internal E_IRNode *e_irtree_conditional(Arena *arena, E_IRNode *c, E_IRNode *l, internal E_IRNode *e_irtree_bytecode_no_copy(Arena *arena, String8 bytecode); internal E_IRNode *e_irtree_string_literal(Arena *arena, String8 string); internal E_IRNode *e_irtree_set_space(Arena *arena, E_Space space, E_IRNode *c); -internal E_IRNode *e_irtree_mem_read_type(Arena *arena, E_Space space, E_IRNode *c, E_TypeKey type_key); +internal E_IRNode *e_irtree_mem_read_type(Arena *arena, E_IRNode *c, E_TypeKey type_key); internal E_IRNode *e_irtree_convert_lo(Arena *arena, E_IRNode *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in); internal E_IRNode *e_irtree_trunc(Arena *arena, E_IRNode *c, E_TypeKey type_key); internal E_IRNode *e_irtree_convert_hi(Arena *arena, E_IRNode *c, E_TypeKey out, E_TypeKey in); -internal E_IRNode *e_irtree_resolve_to_value(Arena *arena, E_Space from_space, E_Mode from_mode, E_IRNode *tree, E_TypeKey type_key); +internal E_IRNode *e_irtree_resolve_to_value(Arena *arena, E_Mode from_mode, E_IRNode *tree, E_TypeKey type_key); + +//- rjf: expression poison checking +internal B32 e_expr_is_poisoned(E_Expr *expr); +internal void e_expr_poison(E_Expr *expr); +internal void e_expr_unpoison(E_Expr *expr); //- rjf: top-level irtree/type extraction -internal E_IRTreeAndType e_irtree_and_type_from_expr(Arena *arena, E_Expr *expr); +E_TYPE_ACCESS_FUNCTION_DEF(default); +internal E_IRTreeAndType e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_IdentifierResolutionRule *identifier_resolution_rule, B32 disallow_autohooks, B32 disallow_chained_fastpaths, E_Expr *root_expr); //- rjf: irtree -> linear ops/bytecode -internal void e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_OpList *out); +internal void e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_Space *current_space, E_OpList *out); internal E_OpList e_oplist_from_irtree(Arena *arena, E_IRNode *root); internal String8 e_bytecode_from_oplist(Arena *arena, E_OpList *oplist); +//- rjf: leaf-bytecode expression extensions +internal E_Expr *e_expr_irext_member_access(Arena *arena, E_Expr *lhs, E_IRTreeAndType *lhs_irtree, String8 member_name); + #endif // EVAL_IR_H diff --git a/src/eval/eval_parse.c b/src/eval/eval_parse.c index 60f31be4..a82b01db 100644 --- a/src/eval/eval_parse.c +++ b/src/eval/eval_parse.c @@ -15,328 +15,11 @@ global read_only String8 e_multichar_symbol_strings[] = str8_lit_comp("!="), str8_lit_comp("&&"), str8_lit_comp("||"), + str8_lit_comp("=>"), }; global read_only S64 e_max_precedence = 15; -//////////////////////////////// -//~ rjf: Basic Map Functions - -//- rjf: string -> num - -internal E_String2NumMap -e_string2num_map_make(Arena *arena, U64 slot_count) -{ - E_String2NumMap map = {0}; - map.slots_count = slot_count; - map.slots = push_array(arena, E_String2NumMapSlot, map.slots_count); - return map; -} - -internal void -e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num) -{ - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - E_String2NumMapNode *existing_node = 0; - for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) - { - if(str8_match(node->string, string, 0) && node->num == num) - { - existing_node = node; - break; - } - } - if(existing_node == 0) - { - E_String2NumMapNode *node = push_array(arena, E_String2NumMapNode, 1); - SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); - SLLQueuePush_N(map->first, map->last, node, order_next); - node->string = push_str8_copy(arena, string); - node->num = num; - map->node_count += 1; - } -} - -internal U64 -e_num_from_string(E_String2NumMap *map, String8 string) -{ - U64 num = 0; - if(map->slots_count != 0) - { - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - E_String2NumMapNode *existing_node = 0; - for(E_String2NumMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) - { - if(str8_match(node->string, string, 0)) - { - existing_node = node; - break; - } - } - if(existing_node != 0) - { - num = existing_node->num; - } - } - return num; -} - -internal E_String2NumMapNodeArray -e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map) -{ - E_String2NumMapNodeArray result = {0}; - result.count = map->node_count; - result.v = push_array(arena, E_String2NumMapNode *, result.count); - U64 idx = 0; - for(E_String2NumMapNode *n = map->first; n != 0; n = n->order_next, idx += 1) - { - result.v[idx] = n; - } - return result; -} - -internal int -e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b) -{ - int result = 0; - if(a[0]->num < b[0]->num) - { - result = -1; - } - else if(a[0]->num > b[0]->num) - { - result = +1; - } - return result; -} - -internal void -e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array) -{ - quick_sort(array->v, array->count, sizeof(array->v[0]), e_string2num_map_node_qsort_compare__num_ascending); -} - -//- rjf: string -> expr - -internal E_String2ExprMap -e_string2expr_map_make(Arena *arena, U64 slot_count) -{ - E_String2ExprMap map = {0}; - map.slots_count = slot_count; - map.slots = push_array(arena, E_String2ExprMapSlot, map.slots_count); - return map; -} - -internal void -e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr) -{ - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - E_String2ExprMapNode *existing_node = 0; - for(E_String2ExprMapNode *node = map->slots[slot_idx].first; - node != 0; - node = node->hash_next) - { - if(str8_match(node->string, string, 0)) - { - existing_node = node; - break; - } - } - if(existing_node == 0) - { - E_String2ExprMapNode *node = push_array(arena, E_String2ExprMapNode, 1); - SLLQueuePush_N(map->slots[slot_idx].first, map->slots[slot_idx].last, node, hash_next); - node->string = push_str8_copy(arena, string); - existing_node = node; - } - existing_node->expr = expr; -} - -internal void -e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string) -{ - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - for(E_String2ExprMapNode *node = map->slots[slot_idx].first; - node != 0; - node = node->hash_next) - { - if(str8_match(node->string, string, 0)) - { - node->poison_count += 1; - break; - } - } -} - -internal void -e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string) -{ - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - for(E_String2ExprMapNode *node = map->slots[slot_idx].first; - node != 0; - node = node->hash_next) - { - if(str8_match(node->string, string, 0) && node->poison_count > 0) - { - node->poison_count -= 1; - break; - } - } -} - -internal E_Expr * -e_string2expr_lookup(E_String2ExprMap *map, String8 string) -{ - E_Expr *expr = &e_expr_nil; - if(map->slots_count != 0) - { - U64 hash = e_hash_from_string(5381, string); - U64 slot_idx = hash%map->slots_count; - E_String2ExprMapNode *existing_node = 0; - for(E_String2ExprMapNode *node = map->slots[slot_idx].first; node != 0; node = node->hash_next) - { - if(str8_match(node->string, string, 0) && node->poison_count == 0) - { - existing_node = node; - break; - } - } - if(existing_node != 0) - { - expr = existing_node->expr; - } - } - return expr; -} - -//////////////////////////////// -//~ rjf: Debug-Info-Driven Map Building Functions - -internal E_String2NumMap * -e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) -{ - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: gather scopes to walk - typedef struct Task Task; - struct Task - { - Task *next; - RDI_Scope *scope; - }; - Task *first_task = 0; - Task *last_task = 0; - - //- rjf: voff -> tightest scope - RDI_Scope *tightest_scope = 0; - { - U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - Task *task = push_array(scratch.arena, Task, 1); - task->scope = scope; - SLLQueuePush(first_task, last_task, task); - tightest_scope = scope; - } - - //- rjf: voff-1 -> scope - if(voff > 0) - { - U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff-1); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - if(scope != tightest_scope) - { - Task *task = push_array(scratch.arena, Task, 1); - task->scope = scope; - SLLQueuePush(first_task, last_task, task); - } - } - - //- rjf: tightest scope -> walk up the tree & build tasks for each parent scope - if(tightest_scope != 0) - { - RDI_Scope *nil_scope = rdi_element_from_name_idx(rdi, Scopes, 0); - for(RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, tightest_scope->parent_scope_idx); - scope != 0 && scope != nil_scope; - scope = rdi_element_from_name_idx(rdi, Scopes, scope->parent_scope_idx)) - { - Task *task = push_array(scratch.arena, Task, 1); - task->scope = scope; - SLLQueuePush(first_task, last_task, task); - } - } - - //- rjf: build blank map - E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); - *map = e_string2num_map_make(arena, 1024); - - //- rjf: accumulate locals for all tasks - for(Task *task = first_task; task != 0; task = task->next) - { - RDI_Scope *scope = task->scope; - if(scope != 0) - { - U32 local_opl_idx = scope->local_first + scope->local_count; - for(U32 local_idx = scope->local_first; local_idx < local_opl_idx; local_idx += 1) - { - RDI_Local *local_var = rdi_element_from_name_idx(rdi, Locals, local_idx); - U64 local_name_size = 0; - U8 *local_name_str = rdi_string_from_idx(rdi, local_var->name_string_idx, &local_name_size); - String8 name = push_str8_copy(arena, str8(local_name_str, local_name_size)); - e_string2num_map_insert(arena, map, name, (U64)local_idx+1); - } - } - } - - scratch_end(scratch); - return map; -} - -internal E_String2NumMap * -e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) -{ - //- rjf: voff -> tightest scope - U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); - RDI_Scope *tightest_scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - - //- rjf: tightest scope -> procedure - U32 proc_idx = tightest_scope->proc_idx; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); - - //- rjf: procedure -> udt - U32 udt_idx = procedure->container_idx; - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, udt_idx); - - //- rjf: build blank map - E_String2NumMap *map = push_array(arena, E_String2NumMap, 1); - *map = e_string2num_map_make(arena, 64); - - //- rjf: udt -> fill member map - if(!(udt->flags & RDI_UDTFlag_EnumMembers)) - { - U64 data_member_num = 1; - for(U32 member_idx = udt->member_first; - member_idx < udt->member_first+udt->member_count; - member_idx += 1) - { - RDI_Member *m = rdi_element_from_name_idx(rdi, Members, member_idx); - if(m->kind == RDI_MemberKind_DataField) - { - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, m->name_string_idx, &name.size); - e_string2num_map_insert(arena, map, name, data_member_num); - data_member_num += 1; - } - } - } - - return map; -} - //////////////////////////////// //~ rjf: Tokenization Functions @@ -612,45 +295,15 @@ e_token_array_make_first_opl(E_Token *first, E_Token *opl) return array; } -//////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) - -internal E_ParseCtx * -e_selected_parse_ctx(void) -{ - return e_parse_ctx; -} - -internal void -e_select_parse_ctx(E_ParseCtx *ctx) -{ - e_parse_ctx = ctx; -} - -internal U32 -e_parse_ctx_module_idx_from_rdi(RDI_Parsed *rdi) -{ - U32 result = 0; - for(U64 idx = 0; idx < e_parse_ctx->modules_count; idx += 1) - { - if(e_parse_ctx->modules[idx].rdi == rdi) - { - result = (U32)idx; - break; - } - } - return result; -} - //////////////////////////////// //~ rjf: Expression Tree Building Functions internal E_Expr * -e_push_expr(Arena *arena, E_ExprKind kind, void *location) +e_push_expr(Arena *arena, E_ExprKind kind, Rng1U64 range) { E_Expr *e = push_array(arena, E_Expr, 1); - e->first = e->last = e->next = e->ref = &e_expr_nil; - e->location = location; + e->first = e->last = e->next = e->prev = e->ref = &e_expr_nil; + e->range = range; e->kind = kind; return e; } @@ -676,79 +329,100 @@ e_expr_remove_child(E_Expr *parent, E_Expr *child) internal E_Expr * e_expr_ref(Arena *arena, E_Expr *ref) { - E_Expr *expr = e_push_expr(arena, E_ExprKind_Ref, 0); + E_Expr *expr = e_push_expr(arena, E_ExprKind_Ref, ref->range); expr->ref = ref; return expr; } internal E_Expr * -e_expr_ref_addr(Arena *arena, E_Expr *rhs) +e_expr_copy(Arena *arena, E_Expr *src) { - E_Expr *expr = e_push_expr(arena, E_ExprKind_Address, 0); - E_Expr *rhs_ref = e_expr_ref(arena, rhs); - e_expr_push_child(expr, rhs_ref); - return expr; + E_Expr *result = &e_expr_nil; + Temp scratch = scratch_begin(&arena, 1); + if(src != &e_expr_nil) + { + typedef struct Task Task; + struct Task + { + Task *next; + E_Expr *dst_parent; + E_Expr *src; + B32 is_ref; + B32 is_sib; + }; + Task start_task = {0, &e_expr_nil, src}; + Task *first_task = &start_task; + Task *last_task = first_task; + for(Task *t = first_task; t != 0; t = t->next) + { + E_Expr *dst = e_push_expr(arena, t->src->kind, t->src->range); + dst->mode = t->src->mode; + dst->space = t->src->space; + dst->type_key = t->src->type_key; + dst->value = t->src->value; + dst->string = push_str8_copy(arena, t->src->string); + dst->bytecode = push_str8_copy(arena, t->src->bytecode); + dst->qualifier = push_str8_copy(arena, t->src->qualifier); + if(t->dst_parent == &e_expr_nil) + { + result = dst; + } + else if(t->is_ref) + { + t->dst_parent->ref = dst; + } + else if(t->is_sib) + { + t->dst_parent->next = dst; + dst->prev = t->dst_parent; + } + else + { + e_expr_push_child(t->dst_parent, dst); + } + if(t->src->next != &e_expr_nil) + { + Task *task = push_array(scratch.arena, Task, 1); + task->dst_parent = dst; + task->src = t->src->next; + task->is_sib = 1; + SLLQueuePush(first_task, last_task, task); + } + if(t->src->ref != &e_expr_nil) + { + Task *task = push_array(scratch.arena, Task, 1); + task->dst_parent = dst; + task->src = t->src->ref; + task->is_ref = 1; + SLLQueuePush(first_task, last_task, task); + } + for(E_Expr *src_child = t->src->first; src_child != &e_expr_nil; src_child = src_child->next) + { + Task *task = push_array(scratch.arena, Task, 1); + task->dst_parent = dst; + task->src = src_child; + SLLQueuePush(first_task, last_task, task); + } + } + } + scratch_end(scratch); + return result; } -internal E_Expr * -e_expr_ref_member_access(Arena *arena, E_Expr *lhs, String8 member_name) +internal void +e_expr_list_push(Arena *arena, E_ExprList *list, E_Expr *expr) { - E_Expr *root = e_push_expr(arena, E_ExprKind_MemberAccess, 0); - E_Expr *lhs_ref = e_expr_ref(arena, lhs); - E_Expr *rhs = e_push_expr(arena, E_ExprKind_LeafMember, 0); - rhs->string = push_str8_copy(arena, member_name); - e_expr_push_child(root, lhs_ref); - e_expr_push_child(root, rhs); - return root; -} - -internal E_Expr * -e_expr_ref_array_index(Arena *arena, E_Expr *lhs, U64 index) -{ - E_Expr *root = e_push_expr(arena, E_ExprKind_ArrayIndex, 0); - E_Expr *lhs_ref = e_expr_ref(arena, lhs); - E_Expr *rhs = e_push_expr(arena, E_ExprKind_LeafU64, 0); - rhs->value.u64 = index; - e_expr_push_child(root, lhs_ref); - e_expr_push_child(root, rhs); - return root; -} - -internal E_Expr * -e_expr_ref_deref(Arena *arena, E_Expr *rhs) -{ - E_Expr *root = e_push_expr(arena, E_ExprKind_Deref, 0); - E_Expr *rhs_ref = e_expr_ref(arena, rhs); - e_expr_push_child(root, rhs_ref); - return root; -} - -internal E_Expr * -e_expr_ref_cast(Arena *arena, E_TypeKey type_key, E_Expr *rhs) -{ - E_Expr *root = e_push_expr(arena, E_ExprKind_Cast, 0); - E_Expr *lhs = e_push_expr(arena, E_ExprKind_TypeIdent, 0); - lhs->type_key = type_key; - E_Expr *rhs_ref = e_expr_ref(arena, rhs); - e_expr_push_child(root, lhs); - e_expr_push_child(root, rhs_ref); - return root; -} - -internal E_Expr * -e_expr_ref_bswap(Arena *arena, E_Expr *rhs) -{ - E_Expr *root = e_push_expr(arena, E_ExprKind_ByteSwap, 0); - E_Expr *rhs_ref = e_expr_ref(arena, rhs); - e_expr_push_child(root, rhs_ref); - return root; + E_ExprNode *n = push_array(arena, E_ExprNode, 1); + n->v = expr; + SLLQueuePush(list->first, list->last, n); + list->count +=1; } //////////////////////////////// //~ rjf: Expression Tree -> String Conversions internal void -e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out) +e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8 parent_expr_string, String8List *out) { switch(expr->kind) { @@ -761,12 +435,17 @@ e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out) op_info->sep, op_info->post, }; - U64 idx = 0; - for(E_Expr *child = expr->first;; child = child->next, idx += 1) + U64 sep_idx = 0; + for(E_Expr *child = expr->first;; child = child->next) { - if(seps[idx].size != 0) + if(sep_idx == ArrayCount(seps)-1 && child != &e_expr_nil) { - str8_list_push(arena, out, seps[idx]); + str8_list_push(arena, out, op_info->chain); + } + else + { + str8_list_push(arena, out, seps[sep_idx]); + sep_idx += 1; } if(child == &e_expr_nil) { @@ -778,7 +457,7 @@ e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out) { str8_list_pushf(arena, out, "("); } - e_append_strings_from_expr(arena, child, out); + e_append_strings_from_expr(arena, child, parent_expr_string, out); if(need_parens) { str8_list_pushf(arena, out, ")"); @@ -786,17 +465,22 @@ e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out) } }break; case E_ExprKind_LeafBytecode: - case E_ExprKind_LeafMember: - case E_ExprKind_LeafIdent: + case E_ExprKind_LeafIdentifier: { - str8_list_push(arena, out, expr->string); + if(str8_match(expr->string, str8_lit("$"), 0) && parent_expr_string.size != 0) + { + str8_list_push(arena, out, parent_expr_string); + } + else + { + str8_list_push(arena, out, expr->string); + } }break; case E_ExprKind_LeafStringLiteral: { str8_list_pushf(arena, out, "\"%S\"", expr->string); }break; case E_ExprKind_LeafU64: - case E_ExprKind_LeafBool: { str8_list_pushf(arena, out, "%I64u", expr->value.u64); }break; @@ -823,16 +507,16 @@ e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out) }break; case E_ExprKind_Ref: { - e_append_strings_from_expr(arena, expr->ref, out); + e_append_strings_from_expr(arena, expr->ref, parent_expr_string, out); }break; } } internal String8 -e_string_from_expr(Arena *arena, E_Expr *expr) +e_string_from_expr(Arena *arena, E_Expr *expr, String8 parent_expr_string) { String8List strings = {0}; - e_append_strings_from_expr(arena, expr, &strings); + e_append_strings_from_expr(arena, expr, parent_expr_string, &strings); String8 result = str8_list_join(arena, &strings, 0); return result; } @@ -845,109 +529,155 @@ e_leaf_type_from_name(String8 name) { E_TypeKey key = zero_struct; B32 found = 0; - for(U64 module_idx = 0; module_idx < e_parse_ctx->modules_count; module_idx += 1) - { - RDI_Parsed *rdi = e_parse_ctx->modules[module_idx].rdi; - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Types); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); - if(node != 0) - { - U32 match_count = 0; - U32 *matches = rdi_matches_from_map_node(rdi, node, &match_count); - if(match_count != 0) - { - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, matches[0]); - found = (type_node->kind != RDI_TypeKind_NULL); - key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), matches[0], module_idx); - break; - } - } - } if(!found) { #define Case(str) (str8_match(name, str8_lit(str), 0)) if(0){} - else if(Case("u8") || Case("uint8") || Case("uint8_t") || Case("U8")) + else if(Case("uint8") || Case("uint8_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_U8); } else if(Case("uchar8") || Case("uchar")) { + found = 1; key = e_type_key_basic(E_TypeKind_UChar8); } - else if(Case("u16") || Case("uint16") || Case("uint16_t") || Case("U16")) + else if(Case("uint16") || Case("uint16_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_U16); } else if(Case("uchar16")) { + found = 1; key = e_type_key_basic(E_TypeKind_UChar16); } - else if(Case("u32") || Case("uint32") || Case("uint32_t") || Case("U32") || Case("uint")) + else if(Case("uint32") || Case("uint32_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_U32); } else if(Case("uchar32")) { + found = 1; key = e_type_key_basic(E_TypeKind_UChar32); } - else if(Case("u64") || Case("uint64") || Case("uint64_t") || Case("U64") || Case("size_t")) + else if(Case("uint64") || Case("uint64_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_U64); } - else if(Case("s8") || Case("b8") || Case("B8") || Case("i8") || Case("int8") || Case("int8_t") || Case("S8")) + else if(Case("uint128") || Case("uint128_t")) { + found = 1; + key = e_type_key_basic(E_TypeKind_U128); + } + else if(Case("uint256") || Case("uint256_t")) + { + found = 1; + key = e_type_key_basic(E_TypeKind_U256); + } + else if(Case("uint512") || Case("uint512_t")) + { + found = 1; + key = e_type_key_basic(E_TypeKind_U512); + } + else if(Case("s8") || Case("b8") || Case("B8") || Case("i8") || Case("int8") || Case("int8_t")) + { + found = 1; key = e_type_key_basic(E_TypeKind_S8); } else if(Case("char8") || Case("char")) { + found = 1; key = e_type_key_basic(E_TypeKind_Char8); } - else if(Case("s16") || Case("b16") || Case("B16") || Case("i16") || Case("int16") || Case("int16_t") || Case("S16")) + else if(Case("int16") || Case("int16_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_S16); } else if(Case("char16")) { + found = 1; key = e_type_key_basic(E_TypeKind_Char16); } - else if(Case("s32") || Case("b32") || Case("B32") || Case("i32") || Case("int32") || Case("int32_t") || Case("char32") || Case("S32") || Case("int")) + else if(Case("int32") || Case("int32_t") || Case("char32")) { + found = 1; key = e_type_key_basic(E_TypeKind_S32); } else if(Case("char32")) { + found = 1; key = e_type_key_basic(E_TypeKind_Char32); } - else if(Case("s64") || Case("b64") || Case("B64") || Case("i64") || Case("int64") || Case("int64_t") || Case("S64") || Case("ssize_t")) + else if(Case("int64") || Case("int64_t")) { + found = 1; key = e_type_key_basic(E_TypeKind_S64); } + else if(Case("int256") || Case("int256_t")) + { + found = 1; + key = e_type_key_basic(E_TypeKind_S256); + } + else if(Case("int512") || Case("int512_t")) + { + found = 1; + key = e_type_key_basic(E_TypeKind_S512); + } else if(Case("void")) { + found = 1; key = e_type_key_basic(E_TypeKind_Void); } else if(Case("bool")) { + found = 1; key = e_type_key_basic(E_TypeKind_Bool); } - else if(Case("float") || Case("f32") || Case("F32") || Case("r32") || Case("R32")) + else if(Case("float") || Case("float32")) { + found = 1; key = e_type_key_basic(E_TypeKind_F32); } - else if(Case("double") || Case("f64") || Case("F64") || Case("r64") || Case("R64")) + else if(Case("double") || Case("float64")) { + found = 1; key = e_type_key_basic(E_TypeKind_F64); } #undef Case } + if(!found) + { + for(U64 module_idx = 0; module_idx < e_base_ctx->modules_count; module_idx += 1) + { + RDI_Parsed *rdi = e_base_ctx->modules[module_idx].rdi; + RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Types); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, name.str, name.size); + if(node != 0) + { + U32 match_count = 0; + U32 *matches = rdi_matches_from_map_node(rdi, node, &match_count); + if(match_count != 0) + { + RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, matches[0]); + found = (type_node->kind != RDI_TypeKind_NULL); + key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), matches[0], module_idx); + break; + } + } + } + } return key; } internal E_TypeKey -e_type_from_expr(E_Expr *expr) +e_type_key_from_expr(E_Expr *expr) { E_TypeKey result = zero_struct; E_ExprKind kind = expr->kind; @@ -955,59 +685,39 @@ e_type_from_expr(E_Expr *expr) { // TODO(rjf): do we support E_ExprKind_Func here? default:{}break; + case E_ExprKind_LeafIdentifier: + { + result = e_leaf_type_from_name(expr->string); + }break; case E_ExprKind_TypeIdent: { result = expr->type_key; }break; case E_ExprKind_Ptr: { - E_TypeKey direct_type_key = e_type_from_expr(expr->first); - result = e_type_key_cons_ptr(e_parse_ctx->primary_module->arch, direct_type_key, 0); + E_TypeKey direct_type_key = e_type_key_from_expr(expr->first); + result = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, direct_type_key, 1, 0); }break; case E_ExprKind_Array: { E_Expr *child_expr = expr->first; - E_TypeKey direct_type_key = e_type_from_expr(child_expr); - result = e_type_key_cons_array(direct_type_key, expr->value.u64); + E_TypeKey direct_type_key = e_type_key_from_expr(child_expr); + result = e_type_key_cons_array(direct_type_key, expr->value.u64, 0); }break; } return result; } -internal void -e_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, E_String2ExprMap *map, E_Expr *expr) -{ - switch(expr->kind) - { - default: - { - for(E_Expr *child = expr->first; child != &e_expr_nil; child = child->next) - { - e_push_leaf_ident_exprs_from_expr__in_place(arena, map, child); - } - }break; - case E_ExprKind_Define: - { - E_Expr *exprl = expr->first; - E_Expr *exprr = exprl->next; - if(exprl->kind == E_ExprKind_LeafIdent) - { - e_string2expr_map_insert(arena, map, exprl->string, exprr); - } - }break; - } -} - internal E_Parse -e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) +e_push_type_parse_from_text_tokens(Arena *arena, String8 text, E_TokenArray tokens) { - E_Parse parse = {0, &e_expr_nil}; - E_Token *token_it = tokens->v; + E_Parse parse = {tokens, 0, &e_expr_nil, &e_expr_nil}; + E_Token *token_it = tokens.v; //- rjf: parse unsigned marker B32 unsigned_marker = 0; { - E_Token token = e_token_at_it(token_it, tokens); + E_Token token = e_token_at_it(token_it, &tokens); if(token.kind == E_TokenKind_Identifier) { String8 token_string = str8_substr(text, token.range); @@ -1021,7 +731,7 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) //- rjf: parse base type { - E_Token token = e_token_at_it(token_it, tokens); + E_Token token = e_token_at_it(token_it, &tokens); if(token.kind == E_TokenKind_Identifier) { String8 token_string = str8_substr(text, token.range); @@ -1053,7 +763,7 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) } // rjf: construct leaf type - parse.expr = e_push_expr(arena, E_ExprKind_TypeIdent, token_string.str); + parse.expr = e_push_expr(arena, E_ExprKind_TypeIdent, token.range); parse.expr->type_key = type_key; } } @@ -1064,7 +774,7 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) { for(;;) { - E_Token token = e_token_at_it(token_it, tokens); + E_Token token = e_token_at_it(token_it, &tokens); if(token.kind != E_TokenKind_Symbol) { break; @@ -1074,7 +784,7 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) { token_it += 1; E_Expr *ptee = parse.expr; - parse.expr = e_push_expr(arena, E_ExprKind_Ptr, token_string.str); + parse.expr = e_push_expr(arena, E_ExprKind_Ptr, token.range); e_expr_push_child(parse.expr, ptee); } else @@ -1090,82 +800,216 @@ e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens) } internal E_Parse -e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *tokens, S64 max_precedence) +e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray tokens, S64 max_precedence, U64 max_chain_count) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - E_Token *it = tokens->v; - E_Token *it_opl = tokens->v + tokens->count; - E_Parse result = {0, &e_expr_nil}; + E_Token *it = tokens.v; + E_Token *it_opl = tokens.v + tokens.count; + E_Parse result = {tokens, 0, &e_expr_nil, &e_expr_nil}; - //- rjf: parse prefix unaries - typedef struct PrefixUnaryNode PrefixUnaryNode; - struct PrefixUnaryNode - { - PrefixUnaryNode *next; - E_ExprKind kind; - E_Expr *cast_expr; - void *location; - }; - PrefixUnaryNode *first_prefix_unary = 0; - PrefixUnaryNode *last_prefix_unary = 0; + ////////////////////////////// + //- rjf: parse chain of expressions + // + for(U64 chain_count = 0; it < it_opl && chain_count < max_chain_count;) { + //////////////////////////// + //- rjf: exit on symbols callers may be waiting on + // + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Symbol && + (str8_match(token_string, str8_lit(")"), 0) || + str8_match(token_string, str8_lit("]"), 0) || + str8_match(token_string, str8_lit(":"), 0) || + str8_match(token_string, str8_lit("?"), 0))) + { + break; + } + } + + //////////////////////////// + //- rjf: skip commas, semicolons, etc. + // for(;it < it_opl;) { - E_Token *start_it = it; - E_Token token = e_token_at_it(it, tokens); + E_Token token = e_token_at_it(it, &tokens); String8 token_string = str8_substr(text, token.range); - S64 prefix_unary_precedence = 0; - E_ExprKind prefix_unary_kind = 0; - E_Expr *cast_expr = &e_expr_nil; - void *location = 0; - - // rjf: try op table - for EachNonZeroEnumVal(E_ExprKind, k) + if(token.kind == E_TokenKind_Symbol && + (str8_match(token_string, str8_lit(","), 0) || + str8_match(token_string, str8_lit(";"), 0))) { - E_OpInfo *op_info = &e_expr_kind_op_info_table[k]; - if(op_info->kind == E_OpKind_UnaryPrefix && str8_match(op_info->pre, token_string, 0)) + it += 1; + } + else + { + break; + } + } + + //////////////////////////// + //- rjf: parse atom, gather prefix unary tasks + // + typedef struct PrefixUnaryTask PrefixUnaryTask; + struct PrefixUnaryTask + { + PrefixUnaryTask *next; + E_ExprKind kind; + Rng1U64 range; + E_Expr *cast_type_expr; + }; + PrefixUnaryTask *first_prefix_unary = 0; + PrefixUnaryTask *last_prefix_unary = 0; + E_Expr *atom = &e_expr_nil; + B32 atom_is_maybe_cast = 0; + for(B32 done = 0; !done && it < it_opl;) + { + ////////////////////////// + //- rjf: prefix unary operators + // + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + S64 prefix_unary_precedence = 0; + E_ExprKind prefix_unary_kind = 0; + E_Expr *prefix_unary_cast_expr = &e_expr_nil; + + // rjf: try op table + for EachNonZeroEnumVal(E_ExprKind, k) + { + E_OpInfo *op_info = &e_expr_kind_op_info_table[k]; + if(op_info->kind == E_OpKind_UnaryPrefix && str8_match(str8_skip_chop_whitespace(op_info->pre), token_string, 0)) + { + prefix_unary_precedence = op_info->precedence; + prefix_unary_kind = k; + break; + } + } + + // rjf: if we found a symbolic prefix unary operator, but we are + // looking for a casted expression, then we need to abort this + // path. C-style casts are only legal in very simple and unambiguous + // cases, e.g. (x)123, but they cannot be made legal in more + // complex cases like (x) * y, because this is fundamentally ambiguous + // (the meaning / tree shape / etc. is entirely different depending on + // the type / mode of `x`). + // + // because of things like hover-evaluation we do actually want to + // support basic C-style casts. but past a certain point of complexity, + // we will simply require usage of the explicit `cast` operator. + // + if(prefix_unary_precedence != 0 && atom_is_maybe_cast) { - prefix_unary_precedence = op_info->precedence; - prefix_unary_kind = k; break; } + + // rjf: try 'unsigned' marker + if(str8_match(token_string, str8_lit("unsigned"), 0)) + { + prefix_unary_kind = E_ExprKind_Unsigned; + prefix_unary_precedence = 2; + } + + // rjf: try explicit cast + if(str8_match(token_string, str8_lit("cast"), 0)) + { + // rjf: consume cast & open paren + E_Token open_paren_maybe = e_token_at_it(it+1, &tokens); + String8 open_paren_maybe_string = str8_substr(text, open_paren_maybe.range); + if(!str8_match(open_paren_maybe_string, str8_lit("("), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected `(` following `cast`."); + goto end_cast_parse; + } + it += 2; + + // rjf: parse type expression + E_Parse type_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); + it = type_parse.last_token; + + // rjf: expect ) + E_Token close_paren_maybe = e_token_at_it(it, &tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing `)`."); + } + + // rjf: fill prefix unary info + prefix_unary_kind = E_ExprKind_Cast; + prefix_unary_precedence = 2; + prefix_unary_cast_expr = type_parse.expr; + end_cast_parse:; + } + + // rjf: push prefix unary if we got one + if(prefix_unary_precedence != 0) + { + PrefixUnaryTask *prefix_unary_task = push_array(scratch.arena, PrefixUnaryTask, 1); + prefix_unary_task->kind = prefix_unary_kind; + prefix_unary_task->range = token.range; + prefix_unary_task->cast_type_expr = prefix_unary_cast_expr; + SLLQueuePush(first_prefix_unary, last_prefix_unary, prefix_unary_task); + it += 1; + } } - // rjf: consume valid op - if(prefix_unary_precedence != 0) + ////////////////////////// + //- rjf: try to parse an atom + // + if(atom == &e_expr_nil || atom_is_maybe_cast) { - location = token_string.str; - it += 1; - } - - // rjf: try casting expression - if(prefix_unary_precedence == 0 && str8_match(token_string, str8_lit("("), 0)) - { - E_Token some_type_identifier_maybe = e_token_at_it(it+1, tokens); - String8 some_type_identifier_maybe_string = str8_substr(text, some_type_identifier_maybe.range); - if(some_type_identifier_maybe.kind == E_TokenKind_Identifier) + B32 got_new_atom = 0; + E_Expr *maybe_cast = atom_is_maybe_cast ? atom : &e_expr_nil; + atom_is_maybe_cast = 0; + + //////////////////////// + //- rjf: consume resolution qualifiers + // + String8 resolution_qualifier = {0}; { - E_TypeKey type_key = e_leaf_type_from_name(some_type_identifier_maybe_string); - if(!e_type_key_match(type_key, e_type_key_zero()) || str8_match(some_type_identifier_maybe_string, str8_lit("unsigned"), 0)) + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Identifier) { - // rjf: move past open paren + E_Token next_token = e_token_at_it(it+1, &tokens); + String8 next_token_string = str8_substr(text, next_token.range); + if(next_token.range.min == token.range.max && next_token.kind == E_TokenKind_Symbol && str8_match(next_token_string, str8_lit(":"), 0)) + { + it += 2; + resolution_qualifier = token_string; + } + } + } + + //////////////////////// + //- rjf: descent to nested expression (...) + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("("), 0)) + { + // rjf: skip ( it += 1; - // rjf: parse type expr - E_TokenArray type_parse_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse type_parse = e_parse_type_from_text_tokens(arena, text, &type_parse_tokens); - E_Expr *type = type_parse.expr; - e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); - it = type_parse.last_token; - location = token_string.str; + // rjf: parse () contents + E_Parse nested_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); + atom = nested_parse.expr; + it = nested_parse.last_token; + atom_is_maybe_cast = 1; + got_new_atom = 1; // rjf: expect ) - E_Token close_paren_maybe = e_token_at_it(it, tokens); + E_Token close_paren_maybe = e_token_at_it(it, &tokens); String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing `)`."); + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing `)`."); } // rjf: consume ) @@ -1173,935 +1017,526 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to { it += 1; } + } + } + + //////////////////////// + //- rjf: descent to assembly-style dereference sub-expression [...] + // + if(atom == &e_expr_nil && !got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("["), 0)) + { + // rjf: skip [ + it += 1; - // rjf: fill - prefix_unary_precedence = 2; - prefix_unary_kind = E_ExprKind_Cast; - cast_expr = type; + // rjf: parse [] contents + E_Parse nested_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); + atom = nested_parse.expr; + it = nested_parse.last_token; + got_new_atom = 1; + + // rjf: build cast-to-U64*, and dereference operators + if(nested_parse.expr == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected expression following `[`."); + } + else + { + E_Expr *type = e_push_expr(arena, E_ExprKind_TypeIdent, token.range); + type->type_key = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, e_type_key_basic(E_TypeKind_U64), 1, 0); + E_Expr *casted = atom; + E_Expr *cast = e_push_expr(arena, E_ExprKind_Cast, token.range); + e_expr_push_child(cast, type); + e_expr_push_child(cast, casted); + atom = e_push_expr(arena, E_ExprKind_Deref, token.range); + e_expr_push_child(atom, cast); + } + + // rjf: expect ] + E_Token close_paren_maybe = e_token_at_it(it, &tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit("]"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing `]`."); + } + + // rjf: consume ) + else + { + it += 1; + } + } + } + + //////////////////////// + //- rjf: leaf identifier + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Identifier) + { + String8 identifier_string = token_string; + if(identifier_string.size >= 2 && identifier_string.str[0] == '`' && identifier_string.str[identifier_string.size-1] == '`') + { + identifier_string = str8_skip(str8_chop(identifier_string, 1), 1); + } + atom = e_push_expr(arena, E_ExprKind_LeafIdentifier, token.range); + atom->string = identifier_string; + it += 1; + got_new_atom = 1; + } + } + + //////////////////////// + //- rjf: leaf numeric + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_Numeric) + { + U64 dot_pos = str8_find_needle(token_string, 0, str8_lit("."), 0); + it += 1; + + // rjf: no . => integral + if(dot_pos == token_string.size) + { + U64 val = 0; + try_u64_from_str8_c_rules(token_string, &val); + atom = e_push_expr(arena, E_ExprKind_LeafU64, token.range); + atom->value.u64 = val; + } + + // rjf: presence of . => double or float + if(dot_pos < token_string.size) + { + F64 val = f64_from_str8(token_string); + U64 f_pos = str8_find_needle(token_string, 0, str8_lit("f"), StringMatchFlag_CaseInsensitive); + + // rjf: presence of f after . => f32 + if(f_pos < token_string.size) + { + atom = e_push_expr(arena, E_ExprKind_LeafF32, token.range); + atom->value.f32 = val; + } + + // rjf: no f => f64 + else + { + atom = e_push_expr(arena, E_ExprKind_LeafF64, token.range); + atom->value.f64 = val; + } + } + + got_new_atom = 1; + } + } + + //////////////////////// + //- rjf: leaf char literal + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_CharLiteral) + { + it += 1; + if(token_string.size > 1 && token_string.str[0] == '\'' && token_string.str[1] != '\'') + { + String8 char_literal_escaped = str8_skip(str8_chop(token_string, 1), 1); + String8 char_literal_raw = raw_from_escaped_str8(scratch.arena, char_literal_escaped); + U8 char_val = char_literal_raw.size > 0 ? char_literal_raw.str[0] : 0; + atom = e_push_expr(arena, E_ExprKind_LeafU64, token.range); + atom->value.u64 = (U64)char_val; + got_new_atom = 1; + } + else + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Malformed character literal."); + } + } + } + + //////////////////////// + //- rjf: filesystem-qualified leaf string literal + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_StringLiteral && + (str8_match(resolution_qualifier, str8_lit("file"), 0) || + str8_match(resolution_qualifier, str8_lit("folder"), 0))) + { + String8 string_value_escaped = str8_chop(str8_skip(token_string, 1), 1); + String8 string_value_raw = raw_from_escaped_str8(arena, string_value_escaped); + atom = e_push_expr(arena, E_ExprKind_LeafFilePath, token.range); + atom->string = string_value_raw; + it += 1; + got_new_atom = 1; + } + } + + //////////////////////// + //- rjf: leaf string literal + // + if(!got_new_atom) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + if(token.kind == E_TokenKind_StringLiteral) + { + String8 string_value_escaped = str8_chop(str8_skip(token_string, 1), 1); + String8 string_value_raw = raw_from_escaped_str8(arena, string_value_escaped); + atom = e_push_expr(arena, E_ExprKind_LeafStringLiteral, token.range); + atom->string = string_value_raw; + it += 1; + got_new_atom = 1; + } + } + + //////////////////////// + //- rjf: upgrade atom w/ qualifier + // + if(atom != &e_expr_nil && resolution_qualifier.size != 0) + { + atom->qualifier = resolution_qualifier; + } + + //////////////////////// + //- rjf: got new atom, but we had a potential cast atom? -> gather cast operator + // + if(got_new_atom && maybe_cast != &e_expr_nil) + { + PrefixUnaryTask *prefix_unary_task = push_array(scratch.arena, PrefixUnaryTask, 1); + prefix_unary_task->kind = E_ExprKind_Cast; + prefix_unary_task->range = maybe_cast->range; + prefix_unary_task->cast_type_expr = maybe_cast; + SLLQueuePush(first_prefix_unary, last_prefix_unary, prefix_unary_task); + } + } + + //////////////////////// + //- rjf: if our atom is not potentially a cast, *or* if we simply did not get an atom, + // then we need to stop parsing at this stage. + // + done = (!atom_is_maybe_cast || atom == &e_expr_nil); + } + + //////////////////////////// + //- rjf: upgrade atom w/ postfix unaries + // + if(atom != &e_expr_nil) for(;it < it_opl;) + { + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); + B32 is_postfix_unary = 0; + + // rjf: dot/arrow operator + if(max_precedence >= 1 && + token.kind == E_TokenKind_Symbol && + (str8_match(token_string, str8_lit("."), 0) || + str8_match(token_string, str8_lit("->"), 0))) + { + is_postfix_unary = 1; + + // rjf: advance past operator + it += 1; + + // rjf: look for member name + E_Token member_name_maybe = e_token_at_it(it, &tokens); + String8 member_name_maybe_string = str8_substr(text, member_name_maybe.range); + B32 member_name_is_good = (member_name_maybe.kind == E_TokenKind_Identifier); + + // rjf: build dot-operator tree + E_Expr *lhs = atom; + E_Expr *rhs = &e_expr_nil; + if(member_name_is_good) + { + rhs = e_push_expr(arena, E_ExprKind_LeafIdentifier, member_name_maybe.range); + rhs->string = member_name_maybe_string; + } + atom = e_push_expr(arena, E_ExprKind_MemberAccess, token.range); + e_expr_push_child(atom, lhs); + if(member_name_is_good) + { + e_expr_push_child(atom, rhs); + } + + // rjf: no identifier after `.`? -> error + if(member_name_is_good) + { + it += 1; + } + else + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing member name after `%S`.", token_string); + } + } + + // rjf: array index + if(token.kind == E_TokenKind_Symbol && + str8_match(token_string, str8_lit("["), 0)) + { + is_postfix_unary = 1; + + // rjf: advance past [ + it += 1; + + // rjf: parse indexing expression + E_Parse idx_expr_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + e_msg_list_concat_in_place(&result.msgs, &idx_expr_parse.msgs); + it = idx_expr_parse.last_token; + + // rjf: valid indexing expression => produce index expr + if(idx_expr_parse.expr != &e_expr_nil) + { + E_Expr *array_expr = atom; + E_Expr *index_expr = idx_expr_parse.expr; + atom = e_push_expr(arena, E_ExprKind_ArrayIndex, token.range); + e_expr_push_child(atom, array_expr); + e_expr_push_child(atom, index_expr); + } + + // rjf: expect ] + { + E_Token close_brace_maybe = e_token_at_it(it, &tokens); + String8 close_brace_maybe_string = str8_substr(text, close_brace_maybe.range); + if(close_brace_maybe.kind != E_TokenKind_Symbol || !str8_match(close_brace_maybe_string, str8_lit("]"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Unclosed `[`."); + } + else + { + it += 1; } } } - // rjf: break if we got no operators - if(prefix_unary_precedence == 0) + // rjf: calls + if(token.kind == E_TokenKind_Symbol && + str8_match(token_string, str8_lit("("), 0)) + { + is_postfix_unary = 1; + + // rjf: skip ( + it += 1; + + // rjf: parse all argument expressions + E_Expr *callee_expr = atom; + E_Expr *call_expr = e_push_expr(arena, E_ExprKind_Call, token.range); + call_expr->string = callee_expr->string; + e_expr_push_child(call_expr, callee_expr); + E_Parse args_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, max_U64); + e_msg_list_concat_in_place(&result.msgs, &args_parse.msgs); + it = args_parse.last_token; + if(args_parse.expr != &e_expr_nil) + { + call_expr->last->next = args_parse.expr; + args_parse.expr->prev = call_expr->last; + for(E_Expr *arg = args_parse.expr; arg != &e_expr_nil; arg = arg->next) + { + call_expr->last = arg; + } + } + atom = call_expr; + + // rjf: expect ) + { + E_Token close_paren_maybe = e_token_at_it(it, &tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Unclosed `(`."); + call_expr->range.max = text.size; + } + else + { + call_expr->range = union_1u64(call_expr->range, close_paren_maybe.range); + it += 1; + } + } + } + + // rjf: quit if this doesn't look like any patterns of postfix unary we know + if(!is_postfix_unary) { break; } + } + + //////////////////////////// + //- rjf: upgrade `atom` w/ previously parsed prefix unaries + // + if(atom != &e_expr_nil) + { + for(PrefixUnaryTask *prefix_unary = first_prefix_unary; + prefix_unary != 0; + prefix_unary = prefix_unary->next) + { + if(prefix_unary->kind == E_ExprKind_Cast) + { + E_Expr *rhs = atom; + atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->range); + e_expr_push_child(atom, prefix_unary->cast_type_expr); + e_expr_push_child(atom, rhs); + } + else + { + E_Expr *rhs = atom; + atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->range); + e_expr_push_child(atom, rhs); + } + } + } + else if(first_prefix_unary != 0) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, last_prefix_unary->range, "Missing expression."); + } + + //////////////////////////// + //- rjf: parse complex operators to further extend `atom` + // + if(atom != &e_expr_nil) for(;it < it_opl;) + { + E_Token *start_it = it; + E_Token token = e_token_at_it(it, &tokens); + String8 token_string = str8_substr(text, token.range); - // rjf: break if the token node iterator has not changed + //- rjf: parse binaries + { + // rjf: first try to find a matching binary operator + S64 binary_precedence = 0; + E_ExprKind binary_kind = 0; + for EachNonZeroEnumVal(E_ExprKind, k) + { + E_OpInfo *op_info = &e_expr_kind_op_info_table[k]; + if(op_info->kind == E_OpKind_Binary && str8_match(str8_skip_chop_whitespace(op_info->sep), token_string, 0)) + { + binary_precedence = op_info->precedence; + binary_kind = k; + break; + } + } + + // rjf: if we got a valid binary precedence, and it's not to be handled by + // a caller, then we need to parse the right-hand-side with a tighter + // precedence + if(binary_precedence != 0 && binary_precedence <= max_precedence) + { + E_Parse rhs_expr_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it+1, it_opl), binary_precedence-1, 1); + e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); + E_Expr *rhs = rhs_expr_parse.expr; + it = rhs_expr_parse.last_token; + if(rhs == &e_expr_nil && binary_kind == E_ExprKind_Mul) + { + // NOTE(rjf): C-style pointer syntax is shared with multiplication. + // carving out a special case here to allow "unfinished *s" to be + // treated as pointers instead. + E_Expr *ptee = atom; + atom = e_push_expr(arena, E_ExprKind_Ptr, token.range); + e_expr_push_child(atom, ptee); + } + else if(rhs == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Missing right-hand-side of `%S`.", token_string); + } + else + { + E_Expr *lhs = atom; + atom = e_push_expr(arena, binary_kind, token.range); + e_expr_push_child(atom, lhs); + e_expr_push_child(atom, rhs); + } + } + } + + //- rjf: parse ternaries + { + if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("?"), 0) && 13 <= max_precedence) + { + it += 1; + + // rjf: parse middle expression + E_Parse middle_expr_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + it = middle_expr_parse.last_token; + E_Expr *middle_expr = middle_expr_parse.expr; + e_msg_list_concat_in_place(&result.msgs, &middle_expr_parse.msgs); + if(middle_expr_parse.expr == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected expression after `?`."); + } + + // rjf: expect : + B32 got_colon = 0; + E_Token colon_token = zero_struct; + String8 colon_token_string = {0}; + { + E_Token colon_token_maybe = e_token_at_it(it, &tokens); + String8 colon_token_maybe_string = str8_substr(text, colon_token_maybe.range); + if(colon_token_maybe.kind != E_TokenKind_Symbol || !str8_match(colon_token_maybe_string, str8_lit(":"), 0)) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token.range, "Expected `:` after `?`."); + } + else + { + got_colon = 1; + colon_token = colon_token_maybe; + colon_token_string = colon_token_maybe_string; + it += 1; + } + } + + // rjf: parse rhs + E_Parse rhs_expr_parse = e_push_parse_from_string_tokens__prec(arena, text, e_token_array_make_first_opl(it, it_opl), e_max_precedence, 1); + if(got_colon) + { + it = rhs_expr_parse.last_token; + e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); + if(rhs_expr_parse.expr == &e_expr_nil) + { + e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, colon_token.range, "Expected expression after `:`."); + } + } + + // rjf: build ternary + if(atom != &e_expr_nil && + middle_expr_parse.expr != &e_expr_nil && + rhs_expr_parse.expr != &e_expr_nil) + { + E_Expr *lhs = atom; + E_Expr *mhs = middle_expr_parse.expr; + E_Expr *rhs = rhs_expr_parse.expr; + atom = e_push_expr(arena, E_ExprKind_Ternary, token.range); + e_expr_push_child(atom, lhs); + e_expr_push_child(atom, mhs); + e_expr_push_child(atom, rhs); + } + } + } + + // rjf: if we parsed nothing successfully, we're done if(it == start_it) { break; } - - // rjf: push prefix unary if we got one - { - PrefixUnaryNode *op_n = push_array(scratch.arena, PrefixUnaryNode, 1); - op_n->kind = prefix_unary_kind; - op_n->cast_expr = cast_expr; - op_n->location = location; - SLLQueuePushFront(first_prefix_unary, last_prefix_unary, op_n); - } - } - } - - //- rjf: parse atom - E_Expr *atom = &e_expr_nil; - String8 atom_implicit_member_name = {0}; - if(it < it_opl) - { - E_Token token = e_token_at_it(it, tokens); - String8 token_string = str8_substr(text, token.range); - - //- rjf: gather resolution qualifier - String8 resolution_qualifier = {0}; - if(token.kind == E_TokenKind_Identifier) - { - E_Token next_token = e_token_at_it(it+1, tokens); - String8 next_token_string = str8_substr(text, next_token.range); - if(next_token.kind == E_TokenKind_Symbol && str8_match(next_token_string, str8_lit(":"), 0)) - { - it += 2; - resolution_qualifier = token_string; - token = e_token_at_it(it, tokens); - token_string = str8_substr(text, token.range); - } } - //- rjf: descent to nested expression - if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("("), 0)) + //- rjf: store parsed atom to expression chain - if we didn't get an expression, break + if(atom != &e_expr_nil) { - // rjf: skip ( - it += 1; - - // rjf: parse () contents - E_TokenArray nested_parse_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse nested_parse = e_parse_expr_from_text_tokens__prec(arena, text, &nested_parse_tokens, e_max_precedence); - e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); - atom = nested_parse.expr; - it = nested_parse.last_token; - - // rjf: expect ) - E_Token close_paren_maybe = e_token_at_it(it, tokens); - String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); - if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit(")"), 0)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing `)`."); - } - - // rjf: consume ) - else - { - it += 1; - } + DLLPushBack_NPZ(&e_expr_nil, result.expr, result.last_expr, atom, next, prev); + chain_count += 1; } - - //- rjf: descent to assembly-style dereference sub-expression - else if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("["), 0)) - { - // rjf: skip [ - it += 1; - - // rjf: parse [] contents - E_TokenArray nested_parse_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse nested_parse = e_parse_expr_from_text_tokens__prec(arena, text, &nested_parse_tokens, e_max_precedence); - e_msg_list_concat_in_place(&result.msgs, &nested_parse.msgs); - atom = nested_parse.expr; - it = nested_parse.last_token; - - // rjf: build cast-to-U64*, and dereference operators - if(nested_parse.expr == &e_expr_nil) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected expression following `[`."); - } - else - { - E_Expr *type = e_push_expr(arena, E_ExprKind_TypeIdent, token_string.str); - type->type_key = e_type_key_cons_ptr(e_parse_ctx->primary_module->arch, e_type_key_basic(E_TypeKind_U64), 0); - E_Expr *casted = atom; - E_Expr *cast = e_push_expr(arena, E_ExprKind_Cast, token_string.str); - e_expr_push_child(cast, type); - e_expr_push_child(cast, casted); - atom = e_push_expr(arena, E_ExprKind_Deref, token_string.str); - e_expr_push_child(atom, cast); - } - - // rjf: expect ] - E_Token close_paren_maybe = e_token_at_it(it, tokens); - String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); - if(close_paren_maybe.kind != E_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit("]"), 0)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing `]`."); - } - - // rjf: consume ) - else - { - it += 1; - } - } - - //- rjf: leaf (identifier, literal) - else if(token.kind != E_TokenKind_Symbol) - { - switch(token.kind) - { - //- rjf: identifier => name resolution - default: - case E_TokenKind_Identifier: - { - B32 mapped_identifier = 0; - B32 identifier_is_constant_value = 0; - B32 identifier_type_is_possibly_dynamically_overridden = 0; - B32 identifier_looks_like_type_expr = 0; - RDI_LocationKind loc_kind = RDI_LocationKind_NULL; - RDI_LocationReg loc_reg = {0}; - RDI_LocationRegPlusU16 loc_reg_u16 = {0}; - String8 loc_bytecode = {0}; - U64 constant_value = 0; - REGS_RegCode reg_code = 0; - REGS_AliasCode alias_code = 0; - E_TypeKey type_key = zero_struct; - String8 local_lookup_string = token_string; - E_Space space = {0}; - Arch arch = Arch_Null; - - //- rjf: identifiers surrounded by ``s should have those `s stripped - if(local_lookup_string.size >= 2 && - local_lookup_string.str[0] == '`' && - local_lookup_string.str[local_lookup_string.size-1] == '`') - { - token_string = local_lookup_string = str8_substr(local_lookup_string, r1u64(1, local_lookup_string.size-1)); - } - - //- rjf: form namespaceified fallback versions of this lookup string - String8List namespaceified_token_strings = {0}; - { - E_Module *module = e_parse_ctx->primary_module; - RDI_Parsed *rdi = module->rdi; - U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, e_parse_ctx->ip_voff); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); - U64 proc_idx = scope->proc_idx; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); - U64 name_size = 0; - U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); - String8 containing_procedure_name = str8(name_ptr, name_size); - U64 last_past_scope_resolution_pos = 0; - for(;;) - { - U64 past_next_dbl_colon_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("::"), 0)+2; - U64 past_next_dot_pos = str8_find_needle(containing_procedure_name, last_past_scope_resolution_pos, str8_lit("."), 0)+1; - U64 past_next_scope_resolution_pos = Min(past_next_dbl_colon_pos, past_next_dot_pos); - if(past_next_scope_resolution_pos >= containing_procedure_name.size) - { - break; - } - String8 new_namespace_prefix_possibility = str8_prefix(containing_procedure_name, past_next_scope_resolution_pos); - String8 namespaceified_token_string = push_str8f(scratch.arena, "%S%S", new_namespace_prefix_possibility, token_string); - str8_list_push_front(scratch.arena, &namespaceified_token_strings, namespaceified_token_string); - last_past_scope_resolution_pos = past_next_scope_resolution_pos; - } - } - - //- rjf: try members - 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) - { - atom_implicit_member_name = token_string; - local_lookup_string = str8_lit("this"); - } - } - - //- rjf: try locals - 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; - U64 local_num = e_num_from_string(e_parse_ctx->locals_map, local_lookup_string); - if(local_num != 0) - { - identifier_type_is_possibly_dynamically_overridden = 1; - RDI_Local *local_var = rdi_element_from_name_idx(rdi, Locals, local_num-1); - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, local_var->type_idx); - type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local_var->type_idx, (U32)(module - e_parse_ctx->modules)); - - // rjf: grab location info - for(U32 loc_block_idx = local_var->location_first; - loc_block_idx < local_var->location_opl; - loc_block_idx += 1) - { - RDI_LocationBlock *block = rdi_element_from_name_idx(rdi, LocationBlocks, loc_block_idx); - if(block->scope_off_first <= e_parse_ctx->ip_voff && e_parse_ctx->ip_voff < block->scope_off_opl) - { - mapped_identifier = 1; - space = module->space; - arch = module->arch; - U64 all_location_data_size = 0; - U8 *all_location_data = rdi_table_from_name(rdi, LocationData, &all_location_data_size); - loc_kind = *((RDI_LocationKind *)(all_location_data + block->location_data_off)); - switch(loc_kind) - { - default:{mapped_identifier = 0;}break; - case RDI_LocationKind_ValBytecodeStream: goto bytecode_stream; - case RDI_LocationKind_AddrBytecodeStream: goto bytecode_stream; - bytecode_stream:; - { - U64 bytecode_size = 0; - U64 off_first = block->location_data_off + sizeof(RDI_LocationKind); - U64 off_opl = all_location_data_size; - for(U64 off = off_first, next_off = off_opl; - off < all_location_data_size; - off = next_off) - { - next_off = off_opl; - U8 op = all_location_data[off]; - if(op == 0) - { - break; - } - U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; - U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); - bytecode_size += (1 + p_size); - next_off = (off + 1 + p_size); - } - loc_bytecode = str8(all_location_data + off_first, bytecode_size); - }break; - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - MemoryCopy(&loc_reg_u16, (all_location_data + block->location_data_off), sizeof(loc_reg_u16)); - }break; - case RDI_LocationKind_ValReg: - { - MemoryCopy(&loc_reg, (all_location_data + block->location_data_off), sizeof(loc_reg)); - }break; - } - } - } - } - } - - //- rjf: try registers - 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) - { - reg_code = reg_num; - type_key = e_type_key_reg(e_parse_ctx->primary_module->arch, reg_code); - mapped_identifier = 1; - space = e_parse_ctx->ip_thread_space; - arch = e_parse_ctx->primary_module->arch; - } - } - - //- rjf: try register aliases - 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) - { - alias_code = (REGS_AliasCode)alias_num; - type_key = e_type_key_reg_alias(e_parse_ctx->primary_module->arch, alias_code); - mapped_identifier = 1; - space = e_parse_ctx->ip_thread_space; - arch = e_parse_ctx->primary_module->arch; - } - } - - //- rjf: try global variables - 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) - { - E_Module *module = &e_parse_ctx->modules[module_idx]; - RDI_Parsed *rdi = module->rdi; - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); - U32 matches_count = 0; - U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); - for(String8Node *n = namespaceified_token_strings.first; - n != 0 && matches_count == 0; - n = n->next) - { - node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); - matches_count = 0; - matches = rdi_matches_from_map_node(rdi, node, &matches_count); - } - if(matches_count != 0) - { - // NOTE(rjf): apparently, PDBs can be produced such that they - // also keep stale *GLOBAL VARIABLE SYMBOLS* around too. I - // don't know of a magic hash table fixup path in PDBs, so - // in this case, I'm going to prefer the latest-added global. - U32 match_idx = matches[matches_count-1]; - RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, match_idx); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff)); - loc_kind = RDI_LocationKind_AddrBytecodeStream; - loc_bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = global_var->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); - type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); - mapped_identifier = 1; - space = module->space; - arch = module->arch; - break; - } - } - } - - //- rjf: try thread variables - 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) - { - E_Module *module = &e_parse_ctx->modules[module_idx]; - RDI_Parsed *rdi = module->rdi; - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_ThreadVariables); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); - U32 matches_count = 0; - U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); - for(String8Node *n = namespaceified_token_strings.first; - n != 0 && matches_count == 0; - n = n->next) - { - node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); - matches_count = 0; - matches = rdi_matches_from_map_node(rdi, node, &matches_count); - } - if(matches_count != 0) - { - U32 match_idx = matches[0]; - RDI_ThreadVariable *thread_var = rdi_element_from_name_idx(rdi, ThreadVariables, match_idx); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off)); - loc_kind = RDI_LocationKind_AddrBytecodeStream; - loc_bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = thread_var->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); - type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); - mapped_identifier = 1; - space = module->space; - arch = module->arch; - break; - } - } - } - - //- rjf: try procedures - 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) - { - E_Module *module = &e_parse_ctx->modules[module_idx]; - RDI_Parsed *rdi = module->rdi; - RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures); - RDI_ParsedNameMap parsed_name_map = {0}; - rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map); - RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, token_string.str, token_string.size); - U32 matches_count = 0; - U32 *matches = rdi_matches_from_map_node(rdi, node, &matches_count); - for(String8Node *n = namespaceified_token_strings.first; - n != 0 && matches_count == 0; - n = n->next) - { - node = rdi_name_map_lookup(rdi, &parsed_name_map, n->string.str, n->string.size); - matches_count = 0; - matches = rdi_matches_from_map_node(rdi, node, &matches_count); - } - if(matches_count != 0) - { - U32 match_idx = matches[0]; - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, match_idx); - RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx); - U64 voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); - loc_kind = RDI_LocationKind_ValBytecodeStream; - loc_bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = procedure->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx); - type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)module_idx); - mapped_identifier = 1; - space = module->space; - arch = module->arch; - break; - } - } - } - - //- rjf: try types - 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)) - { - mapped_identifier = 1; - identifier_looks_like_type_expr = 1; - MemoryZeroStruct(&space); - arch = e_parse_ctx->primary_module->arch; - } - } - - //- rjf: try basic constants - if(mapped_identifier == 0 && str8_match(token_string, str8_lit("true"), 0)) - { - mapped_identifier = 1; - identifier_is_constant_value = 1; - type_key = e_type_key_basic(E_TypeKind_Bool); - constant_value = 1; - } - if(mapped_identifier == 0 && str8_match(token_string, str8_lit("false"), 0)) - { - mapped_identifier = 1; - identifier_is_constant_value = 1; - type_key = e_type_key_basic(E_TypeKind_Bool); - constant_value = 0; - } - - //- rjf: attach on map - if(mapped_identifier != 0) ProfScope("attach on map") - { - it += 1; - - // rjf: build atom - switch(loc_kind) - { - default: - { - if(identifier_is_constant_value) - { - atom = e_push_expr(arena, E_ExprKind_LeafBool, token_string.str); - atom->value.u64 = constant_value; - atom->type_key = type_key; - } - else if(identifier_looks_like_type_expr) - { - E_TokenArray type_parse_tokens = e_token_array_make_first_opl(it-1, it_opl); - E_Parse type_parse = e_parse_type_from_text_tokens(arena, text, &type_parse_tokens); - E_Expr *type = type_parse.expr; - e_msg_list_concat_in_place(&result.msgs, &type_parse.msgs); - it = type_parse.last_token; - atom = type; - } - else if(reg_code != 0) - { - REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(e_parse_ctx->primary_module->arch)[reg_code]; - E_OpList oplist = {0}; - e_oplist_push_uconst(arena, &oplist, reg_rng.byte_off); - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Offset; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = e_bytecode_from_oplist(arena, &oplist); - } - else if(alias_code != 0) - { - REGS_Slice alias_slice = regs_alias_code_slice_table_from_arch(e_parse_ctx->primary_module->arch)[alias_code]; - REGS_Rng alias_reg_rng = regs_reg_code_rng_table_from_arch(e_parse_ctx->primary_module->arch)[alias_slice.code]; - E_OpList oplist = {0}; - e_oplist_push_uconst(arena, &oplist, alias_reg_rng.byte_off + alias_slice.byte_off); - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Offset; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = e_bytecode_from_oplist(arena, &oplist); - } - else - { - e_msgf(arena, &result.msgs, E_MsgKind_MissingInfo, token_string.str, "Missing location information for `%S`.", token_string); - } - }break; - case RDI_LocationKind_AddrBytecodeStream: - { - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Offset; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = loc_bytecode; - }break; - case RDI_LocationKind_ValBytecodeStream: - { - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Value; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = loc_bytecode; - }break; - case RDI_LocationKind_AddrRegPlusU16: - { - E_OpList oplist = {0}; - U64 byte_size = bit_size_from_arch(arch)/8; - U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.reg_code, byte_size, 0); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, e_value_u64(loc_reg_u16.offset)); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, e_value_u64(0)); - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Offset; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = e_bytecode_from_oplist(arena, &oplist); - }break; - case RDI_LocationKind_AddrAddrRegPlusU16: - { - E_OpList oplist = {0}; - U64 byte_size = bit_size_from_arch(arch)/8; - U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.reg_code, byte_size, 0); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, e_value_u64(loc_reg_u16.offset)); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, e_value_u64(0)); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_MemRead, e_value_u64(bit_size_from_arch(arch)/8)); - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Offset; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = e_bytecode_from_oplist(arena, &oplist); - }break; - case RDI_LocationKind_ValReg: - { - REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(arch, loc_reg.reg_code); - REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(arch)[regs_reg_code]; - E_OpList oplist = {0}; - U64 byte_size = (U64)reg_rng.byte_size; - U64 byte_pos = 0; - U64 regread_param = RDI_EncodeRegReadParam(loc_reg.reg_code, byte_size, byte_pos); - e_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, e_value_u64(regread_param)); - atom = e_push_expr(arena, E_ExprKind_LeafBytecode, token_string.str); - atom->mode = E_Mode_Value; - atom->space = space; - atom->type_key = type_key; - atom->string = token_string; - atom->bytecode = e_bytecode_from_oplist(arena, &oplist); - }break; - } - - // rjf: implicit local lookup -> attach member access node - if(atom_implicit_member_name.size != 0 && atom != &e_expr_nil) - { - E_Expr *member_container = atom; - E_Expr *member_expr = e_push_expr(arena, E_ExprKind_LeafMember, atom_implicit_member_name.str); - member_expr->string = atom_implicit_member_name; - atom = e_push_expr(arena, E_ExprKind_MemberAccess, atom_implicit_member_name.str); - atom->space = space; - e_expr_push_child(atom, member_container); - e_expr_push_child(atom, member_expr); - } - } - - //- rjf: map failure -> attach as leaf identifier, to be resolved later - if(!mapped_identifier) - { - atom = e_push_expr(arena, E_ExprKind_LeafIdent, token_string.str); - atom->string = token_string; - it += 1; - } - }break; - - //- rjf: numeric => directly extract value - case E_TokenKind_Numeric: - { - U64 dot_pos = str8_find_needle(token_string, 0, str8_lit("."), 0); - it += 1; - - // rjf: no . => integral - if(dot_pos == token_string.size) - { - U64 val = 0; - try_u64_from_str8_c_rules(token_string, &val); - atom = e_push_expr(arena, E_ExprKind_LeafU64, token_string.str); - atom->value.u64 = val; - break; - } - - // rjf: presence of . => double or float - if(dot_pos < token_string.size) - { - F64 val = f64_from_str8(token_string); - U64 f_pos = str8_find_needle(token_string, 0, str8_lit("f"), StringMatchFlag_CaseInsensitive); - - // rjf: presence of f after . => f32 - if(f_pos < token_string.size) - { - atom = e_push_expr(arena, E_ExprKind_LeafF32, token_string.str); - atom->value.f32 = val; - } - - // rjf: no f => f64 - else - { - atom = e_push_expr(arena, E_ExprKind_LeafF64, token_string.str); - atom->value.f64 = val; - } - } - }break; - - //- rjf: char => extract char value - case E_TokenKind_CharLiteral: - { - it += 1; - if(token_string.size > 1 && token_string.str[0] == '\'' && token_string.str[1] != '\'') - { - String8 char_literal_escaped = str8_skip(str8_chop(token_string, 1), 1); - String8 char_literal_raw = raw_from_escaped_str8(scratch.arena, char_literal_escaped); - U8 char_val = char_literal_raw.size > 0 ? char_literal_raw.str[0] : 0; - atom = e_push_expr(arena, E_ExprKind_LeafU64, token_string.str); - atom->value.u64 = (U64)char_val; - } - else - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Malformed character literal."); - } - }break; - - // rjf: string => leaf string literal, or file path - case E_TokenKind_StringLiteral: - { - if(str8_match(resolution_qualifier, str8_lit("file"), 0)) - { - String8 string_value_escaped = str8_chop(str8_skip(token_string, 1), 1); - String8 string_value_raw = raw_from_escaped_str8(arena, string_value_escaped); - atom = e_push_expr(arena, E_ExprKind_LeafFilePath, token_string.str); - atom->string = string_value_raw; - it += 1; - } - else - { - String8 string_value_escaped = str8_chop(str8_skip(token_string, 1), 1); - String8 string_value_raw = raw_from_escaped_str8(arena, string_value_escaped); - atom = e_push_expr(arena, E_ExprKind_LeafStringLiteral, token_string.str); - atom->string = string_value_raw; - it += 1; - } - }break; - - } - } - } - - //- rjf: upgrade atom w/ postfix unaries - if(atom != &e_expr_nil) for(;it < it_opl;) - { - E_Token token = e_token_at_it(it, tokens); - String8 token_string = str8_substr(text, token.range); - B32 is_postfix_unary = 0; - - // rjf: dot/arrow operator - if(token.kind == E_TokenKind_Symbol && - (str8_match(token_string, str8_lit("."), 0) || - str8_match(token_string, str8_lit("->"), 0))) - { - is_postfix_unary = 1; - - // rjf: advance past operator - it += 1; - - // rjf: expect member name - String8 member_name = {0}; - B32 good_member_name = 0; - { - E_Token member_name_maybe = e_token_at_it(it, tokens); - String8 member_name_maybe_string = str8_substr(text, member_name_maybe.range); - if(member_name_maybe.kind != E_TokenKind_Identifier) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected member name after `%S`.", token_string); - } - else - { - member_name = member_name_maybe_string; - good_member_name = 1; - } - } - - // rjf: produce lookup member expr - if(good_member_name) - { - E_Expr *member_container = atom; - E_Expr *member_expr = e_push_expr(arena, E_ExprKind_LeafMember, member_name.str); - member_expr->string = member_name; - atom = e_push_expr(arena, E_ExprKind_MemberAccess, token_string.str); - e_expr_push_child(atom, member_container); - e_expr_push_child(atom, member_expr); - } - - // rjf: increment past good member names - if(good_member_name) - { - it += 1; - } - } - - // rjf: array index - if(token.kind == E_TokenKind_Symbol && - str8_match(token_string, str8_lit("["), 0)) - { - is_postfix_unary = 1; - - // rjf: advance past [ - it += 1; - - // rjf: parse indexing expression - E_TokenArray idx_expr_parse_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse idx_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &idx_expr_parse_tokens, e_max_precedence); - e_msg_list_concat_in_place(&result.msgs, &idx_expr_parse.msgs); - it = idx_expr_parse.last_token; - - // rjf: valid indexing expression => produce index expr - if(idx_expr_parse.expr != &e_expr_nil) - { - E_Expr *array_expr = atom; - E_Expr *index_expr = idx_expr_parse.expr; - atom = e_push_expr(arena, E_ExprKind_ArrayIndex, token_string.str); - e_expr_push_child(atom, array_expr); - e_expr_push_child(atom, index_expr); - } - - // rjf: expect ] - { - E_Token close_brace_maybe = e_token_at_it(it, tokens); - String8 close_brace_maybe_string = str8_substr(text, close_brace_maybe.range); - if(close_brace_maybe.kind != E_TokenKind_Symbol || !str8_match(close_brace_maybe_string, str8_lit("]"), 0)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Unclosed `[`."); - } - else - { - it += 1; - } - } - } - - // rjf: quit if this doesn't look like any patterns of postfix unary we know - if(!is_postfix_unary) - { - break; - } - } - - //- rjf: upgrade atom w/ previously parsed prefix unaries - if(atom == &e_expr_nil && first_prefix_unary != 0 && first_prefix_unary->cast_expr != &e_expr_nil) - { - atom = first_prefix_unary->cast_expr; - for(PrefixUnaryNode *prefix_unary = first_prefix_unary->next; - prefix_unary != 0; - prefix_unary = prefix_unary->next) - { - E_Expr *rhs = atom; - atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->location); - if(prefix_unary->cast_expr != &e_expr_nil) - { - e_expr_push_child(atom, prefix_unary->cast_expr); - } - e_expr_push_child(atom, rhs); - } - } - else if(atom == &e_expr_nil && first_prefix_unary != 0) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, last_prefix_unary->location, "Missing expression."); - } - else - { - for(PrefixUnaryNode *prefix_unary = first_prefix_unary; - prefix_unary != 0; - prefix_unary = prefix_unary->next) - { - E_Expr *rhs = atom; - atom = e_push_expr(arena, prefix_unary->kind, prefix_unary->location); - if(prefix_unary->cast_expr != &e_expr_nil) - { - e_expr_push_child(atom, prefix_unary->cast_expr); - } - e_expr_push_child(atom, rhs); - } - } - - //- rjf: parse complex operators - if(atom != &e_expr_nil) for(;it < it_opl;) - { - E_Token *start_it = it; - E_Token token = e_token_at_it(it, tokens); - String8 token_string = str8_substr(text, token.range); - - //- rjf: parse binaries - { - // rjf: first try to find a matching binary operator - S64 binary_precedence = 0; - E_ExprKind binary_kind = 0; - for EachNonZeroEnumVal(E_ExprKind, k) - { - E_OpInfo *op_info = &e_expr_kind_op_info_table[k]; - if(op_info->kind == E_OpKind_Binary && str8_match(op_info->sep, token_string, 0)) - { - binary_precedence = op_info->precedence; - binary_kind = k; - break; - } - } - - // rjf: if we got a valid binary precedence, and it's not to be handled by - // a caller, then we need to parse the right-hand-side with a tighter - // precedence - if(binary_precedence != 0 && binary_precedence <= max_precedence) - { - E_TokenArray rhs_expr_parse_tokens = e_token_array_make_first_opl(it+1, it_opl); - E_Parse rhs_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &rhs_expr_parse_tokens, binary_precedence-1); - e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); - E_Expr *rhs = rhs_expr_parse.expr; - it = rhs_expr_parse.last_token; - if(rhs == &e_expr_nil) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Missing right-hand-side of `%S`.", token_string); - } - else - { - E_Expr *lhs = atom; - atom = e_push_expr(arena, binary_kind, token_string.str); - e_expr_push_child(atom, lhs); - e_expr_push_child(atom, rhs); - } - } - } - - //- rjf: parse ternaries - { - if(token.kind == E_TokenKind_Symbol && str8_match(token_string, str8_lit("?"), 0) && 13 <= max_precedence) - { - it += 1; - - // rjf: parse middle expression - E_TokenArray middle_expr_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse middle_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &middle_expr_tokens, e_max_precedence); - it = middle_expr_parse.last_token; - E_Expr *middle_expr = middle_expr_parse.expr; - e_msg_list_concat_in_place(&result.msgs, &middle_expr_parse.msgs); - if(middle_expr_parse.expr == &e_expr_nil) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected expression after `?`."); - } - - // rjf: expect : - B32 got_colon = 0; - E_Token colon_token = zero_struct; - String8 colon_token_string = {0}; - { - E_Token colon_token_maybe = e_token_at_it(it, tokens); - String8 colon_token_maybe_string = str8_substr(text, colon_token_maybe.range); - if(colon_token_maybe.kind != E_TokenKind_Symbol || !str8_match(colon_token_maybe_string, str8_lit(":"), 0)) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, token_string.str, "Expected `:` after `?`."); - } - else - { - got_colon = 1; - colon_token = colon_token_maybe; - colon_token_string = colon_token_maybe_string; - it += 1; - } - } - - // rjf: parse rhs - E_TokenArray rhs_expr_parse_tokens = e_token_array_make_first_opl(it, it_opl); - E_Parse rhs_expr_parse = e_parse_expr_from_text_tokens__prec(arena, text, &rhs_expr_parse_tokens, e_max_precedence); - if(got_colon) - { - it = rhs_expr_parse.last_token; - e_msg_list_concat_in_place(&result.msgs, &rhs_expr_parse.msgs); - if(rhs_expr_parse.expr == &e_expr_nil) - { - e_msgf(arena, &result.msgs, E_MsgKind_MalformedInput, colon_token_string.str, "Expected expression after `:`."); - } - } - - // rjf: build ternary - if(atom != &e_expr_nil && - middle_expr_parse.expr != &e_expr_nil && - rhs_expr_parse.expr != &e_expr_nil) - { - E_Expr *lhs = atom; - E_Expr *mhs = middle_expr_parse.expr; - E_Expr *rhs = rhs_expr_parse.expr; - atom = e_push_expr(arena, E_ExprKind_Ternary, token_string.str); - e_expr_push_child(atom, lhs); - e_expr_push_child(atom, mhs); - e_expr_push_child(atom, rhs); - } - } - } - - // rjf: if we parsed nothing successfully, we're done - if(it == start_it) + else { break; } @@ -2109,27 +1544,17 @@ e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *to //- rjf: fill result & return result.last_token = it; - result.expr = atom; scratch_end(scratch); ProfEnd(); return result; } 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; -} - -internal E_Expr * -e_parse_expr_from_text(Arena *arena, String8 text) +e_push_parse_from_string(Arena *arena, String8 text) { Temp scratch = scratch_begin(&arena, 1); E_TokenArray tokens = e_token_array_from_text(scratch.arena, text); - E_Parse parse = e_parse_expr_from_text_tokens(arena, text, &tokens); + E_Parse parse = e_push_parse_from_string_tokens__prec(arena, text, tokens, e_max_precedence, max_U64); scratch_end(scratch); - return parse.expr; + return parse; } diff --git a/src/eval/eval_parse.h b/src/eval/eval_parse.h index 9f46e6f7..c8e91b4b 100644 --- a/src/eval/eval_parse.h +++ b/src/eval/eval_parse.h @@ -4,243 +4,40 @@ #ifndef EVAL_PARSE_H #define EVAL_PARSE_H -//////////////////////////////// -//~ rjf: Generated Code - -#include "generated/eval.meta.h" - -//////////////////////////////// -//~ rjf: Token Types - -typedef struct E_Token E_Token; -struct E_Token -{ - E_TokenKind kind; - Rng1U64 range; -}; - -typedef struct E_TokenChunkNode E_TokenChunkNode; -struct E_TokenChunkNode -{ - E_TokenChunkNode *next; - E_Token *v; - U64 count; - U64 cap; -}; - -typedef struct E_TokenChunkList E_TokenChunkList; -struct E_TokenChunkList -{ - E_TokenChunkNode *first; - E_TokenChunkNode *last; - U64 node_count; - U64 total_count; -}; - -typedef struct E_TokenArray E_TokenArray; -struct E_TokenArray -{ - E_Token *v; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Expression Tree Types - -typedef struct E_Expr E_Expr; -struct E_Expr -{ - E_Expr *first; - E_Expr *last; - E_Expr *next; - E_Expr *prev; - E_Expr *ref; - void *location; - E_ExprKind kind; - E_Mode mode; - E_Space space; - E_TypeKey type_key; - E_Value value; - String8 string; - String8 bytecode; -}; - -//////////////////////////////// -//~ rjf: Map Types - -//- rjf: string -> num - -typedef struct E_String2NumMapNode E_String2NumMapNode; -struct E_String2NumMapNode -{ - E_String2NumMapNode *order_next; - E_String2NumMapNode *hash_next; - String8 string; - U64 num; -}; - -typedef struct E_String2NumMapNodeArray E_String2NumMapNodeArray; -struct E_String2NumMapNodeArray -{ - E_String2NumMapNode **v; - U64 count; -}; - -typedef struct E_String2NumMapSlot E_String2NumMapSlot; -struct E_String2NumMapSlot -{ - E_String2NumMapNode *first; - E_String2NumMapNode *last; -}; - -typedef struct E_String2NumMap E_String2NumMap; -struct E_String2NumMap -{ - U64 slots_count; - U64 node_count; - E_String2NumMapSlot *slots; - E_String2NumMapNode *first; - E_String2NumMapNode *last; -}; - -//- rjf: string -> expr - -typedef struct E_String2ExprMapNode E_String2ExprMapNode; -struct E_String2ExprMapNode -{ - E_String2ExprMapNode *hash_next; - String8 string; - E_Expr *expr; - U64 poison_count; -}; - -typedef struct E_String2ExprMapSlot E_String2ExprMapSlot; -struct E_String2ExprMapSlot -{ - E_String2ExprMapNode *first; - E_String2ExprMapNode *last; -}; - -typedef struct E_String2ExprMap E_String2ExprMap; -struct E_String2ExprMap -{ - U64 slots_count; - E_String2ExprMapSlot *slots; -}; - -//////////////////////////////// -//~ rjf: Parse Context - -typedef struct E_ParseCtx E_ParseCtx; -struct E_ParseCtx -{ - // rjf: instruction pointer info - U64 ip_vaddr; - U64 ip_voff; - E_Space ip_thread_space; - - // rjf: modules - E_Module *modules; - U64 modules_count; - E_Module *primary_module; - - // rjf: local identifier resolution maps - E_String2NumMap *regs_map; - E_String2NumMap *reg_alias_map; - E_String2NumMap *locals_map; // (within `rdis[rdis_primary_idx]`) - E_String2NumMap *member_map; // (within `rdis[rdis_primary_idx]`) -}; - -//////////////////////////////// -//~ rjf: Parse Results - -typedef struct E_Parse E_Parse; -struct E_Parse -{ - E_Token *last_token; - E_Expr *expr; - E_MsgList msgs; -}; - -//////////////////////////////// -//~ rjf: Globals - -global read_only E_String2NumMap e_string2num_map_nil = {0}; -global read_only E_String2ExprMap e_string2expr_map_nil = {0}; -global read_only E_Expr e_expr_nil = {&e_expr_nil, &e_expr_nil, &e_expr_nil}; -thread_static E_ParseCtx *e_parse_ctx = 0; - -//////////////////////////////// -//~ rjf: Basic Map Functions - -//- rjf: string -> num -internal E_String2NumMap e_string2num_map_make(Arena *arena, U64 slot_count); -internal void e_string2num_map_insert(Arena *arena, E_String2NumMap *map, String8 string, U64 num); -internal U64 e_num_from_string(E_String2NumMap *map, String8 string); -internal E_String2NumMapNodeArray e_string2num_map_node_array_from_map(Arena *arena, E_String2NumMap *map); -internal int e_string2num_map_node_qsort_compare__num_ascending(E_String2NumMapNode **a, E_String2NumMapNode **b); -internal void e_string2num_map_node_array_sort__in_place(E_String2NumMapNodeArray *array); - -//- rjf: string -> expr -internal E_String2ExprMap e_string2expr_map_make(Arena *arena, U64 slot_count); -internal void e_string2expr_map_insert(Arena *arena, E_String2ExprMap *map, String8 string, E_Expr *expr); -internal void e_string2expr_map_inc_poison(E_String2ExprMap *map, String8 string); -internal void e_string2expr_map_dec_poison(E_String2ExprMap *map, String8 string); -internal E_Expr *e_string2expr_lookup(E_String2ExprMap *map, String8 string); - -//////////////////////////////// -//~ rjf: Debug-Info-Driven Map Building Functions - -internal E_String2NumMap *e_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); -internal E_String2NumMap *e_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); - //////////////////////////////// //~ rjf: Tokenization Functions -#define e_token_at_it(it, arr) (((it) < (arr)->v+(arr)->count) ? (*(it)) : e_token_zero()) +#define e_token_at_it(it, arr) (((arr)->v <= (it) && (it) < (arr)->v+(arr)->count) ? (*(it)) : e_token_zero()) internal E_Token e_token_zero(void); internal void e_token_chunk_list_push(Arena *arena, E_TokenChunkList *list, U64 chunk_size, E_Token *token); internal E_TokenArray e_token_array_from_chunk_list(Arena *arena, E_TokenChunkList *list); internal E_TokenArray e_token_array_from_text(Arena *arena, String8 text); internal E_TokenArray e_token_array_make_first_opl(E_Token *first, E_Token *opl); -//////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) - -internal E_ParseCtx *e_selected_parse_ctx(void); -internal void e_select_parse_ctx(E_ParseCtx *ctx); -internal U32 e_parse_ctx_module_idx_from_rdi(RDI_Parsed *rdi); - //////////////////////////////// //~ rjf: Expression Tree Building Functions -internal E_Expr *e_push_expr(Arena *arena, E_ExprKind kind, void *location); +internal E_Expr *e_push_expr(Arena *arena, E_ExprKind kind, Rng1U64 range); internal void e_expr_insert_child(E_Expr *parent, E_Expr *prev, E_Expr *child); internal void e_expr_push_child(E_Expr *parent, E_Expr *child); internal void e_expr_remove_child(E_Expr *parent, E_Expr *child); internal E_Expr *e_expr_ref(Arena *arena, E_Expr *ref); -internal E_Expr *e_expr_ref_addr(Arena *arena, E_Expr *rhs); -internal E_Expr *e_expr_ref_member_access(Arena *arena, E_Expr *lhs, String8 member_name); -internal E_Expr *e_expr_ref_array_index(Arena *arena, E_Expr *lhs, U64 index); -internal E_Expr *e_expr_ref_deref(Arena *arena, E_Expr *rhs); -internal E_Expr *e_expr_ref_cast(Arena *arena, E_TypeKey type_key, E_Expr *rhs); -internal E_Expr *e_expr_ref_bswap(Arena *arena, E_Expr *rhs); +internal E_Expr *e_expr_copy(Arena *arena, E_Expr *src); +internal void e_expr_list_push(Arena *arena, E_ExprList *list, E_Expr *expr); //////////////////////////////// //~ rjf: Expression Tree -> String Conversions -internal void e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8List *out); -internal String8 e_string_from_expr(Arena *arena, E_Expr *expr); +internal void e_append_strings_from_expr(Arena *arena, E_Expr *expr, String8 parent_expr_string, String8List *out); +internal String8 e_string_from_expr(Arena *arena, E_Expr *expr, String8 parent_expr_string); //////////////////////////////// //~ rjf: Parsing Functions internal E_TypeKey e_leaf_type_from_name(String8 name); -internal E_TypeKey e_type_from_expr(E_Expr *expr); -internal void e_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, E_String2ExprMap *map, E_Expr *expr); -internal E_Parse e_parse_type_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens); -internal E_Parse e_parse_expr_from_text_tokens__prec(Arena *arena, String8 text, E_TokenArray *tokens, S64 max_precedence); -internal E_Parse e_parse_expr_from_text_tokens(Arena *arena, String8 text, E_TokenArray *tokens); -internal E_Expr *e_parse_expr_from_text(Arena *arena, String8 text); +internal E_TypeKey e_type_key_from_expr(E_Expr *expr); +internal E_Parse e_push_type_parse_from_text_tokens(Arena *arena, String8 text, E_TokenArray tokens); +internal E_Parse e_push_parse_from_string_tokens__prec(Arena *arena, String8 text, E_TokenArray tokens, S64 max_precedence, U64 max_chain_count); +internal E_Parse e_push_parse_from_string(Arena *arena, String8 text); #endif // EVAL_PARSE_H diff --git a/src/eval/eval_types.c b/src/eval/eval_types.c index 57706489..4db6fab9 100644 --- a/src/eval/eval_types.c +++ b/src/eval/eval_types.c @@ -223,33 +223,31 @@ e_member_array_from_list(Arena *arena, E_MemberList *list) } //////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) - -internal E_TypeCtx * -e_selected_type_ctx(void) -{ - return e_type_state->ctx; -} +//~ rjf: Enum Value Functions internal void -e_select_type_ctx(E_TypeCtx *ctx) +e_enum_val_list_push(Arena *arena, E_EnumValList *list, E_EnumVal *enum_val) { - if(e_type_state == 0) + E_EnumValNode *n = push_array(arena, E_EnumValNode, 1); + MemoryCopyStruct(&n->v, enum_val); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal E_EnumValArray +e_enum_val_array_from_list(Arena *arena, E_EnumValList *list) +{ + E_EnumValArray array = {0}; + array.count = list->count; + array.v = push_array(arena, E_EnumVal, array.count); { - Arena *arena = arena_alloc(); - e_type_state = push_array(arena, E_TypeState, 1); - e_type_state->arena = arena; - e_type_state->arena_eval_start_pos = arena_pos(e_type_state->arena); + U64 idx = 0; + for(E_EnumValNode *n = list->first; n != 0; n = n->next, idx += 1) + { + MemoryCopyStruct(&array.v[idx], &n->v); + } } - arena_pop_to(e_type_state->arena, e_type_state->arena_eval_start_pos); - e_type_state->ctx = ctx; - e_type_state->cons_id_gen = 0; - e_type_state->cons_content_slots_count = 256; - e_type_state->cons_key_slots_count = 256; - e_type_state->cons_content_slots = push_array(e_type_state->arena, E_ConsTypeSlot, e_type_state->cons_content_slots_count); - e_type_state->cons_key_slots = push_array(e_type_state->arena, E_ConsTypeSlot, e_type_state->cons_key_slots_count); - e_type_state->member_cache_slots_count = 256; - e_type_state->member_cache_slots = push_array(e_type_state->arena, E_MemberCacheSlot, e_type_state->member_cache_slots_count); + return array; } //////////////////////////////// @@ -321,6 +319,8 @@ e_hash_from_cons_type_params(E_ConsTypeParams *params) params->direct_key.u32[2], (U32)((params->count & 0x00000000ffffffffull)>> 0), (U32)((params->count & 0xffffffff00000000ull)>> 32), + (U32)((params->depth & 0x00000000ffffffffull)>> 0), + (U32)((params->depth & 0xffffffff00000000ull)>> 32), }; U64 hash = e_hash_from_string(5381, str8((U8 *)buffer, sizeof(buffer))); hash = e_hash_from_string(hash, params->name); @@ -330,11 +330,13 @@ e_hash_from_cons_type_params(E_ConsTypeParams *params) internal B32 e_cons_type_params_match(E_ConsTypeParams *l, E_ConsTypeParams *r) { - B32 result = (l->kind == r->kind && + B32 result = (l->kind != E_TypeKind_Lens && + l->kind == r->kind && l->flags == r->flags && str8_match(l->name, r->name, 0) && e_type_key_match(l->direct_key, r->direct_key) && - l->count == r->count); + l->count == r->count && + l->depth == r->depth); if(result && l->members != 0 && r->members != 0) { for(U64 idx = 0; idx < l->count; idx += 1) @@ -368,8 +370,8 @@ internal E_TypeKey e_type_key_cons_(E_ConsTypeParams *params) { U64 content_hash = e_hash_from_cons_type_params(params); - U64 content_slot_idx = content_hash%e_type_state->cons_content_slots_count; - E_ConsTypeSlot *content_slot = &e_type_state->cons_content_slots[content_slot_idx]; + U64 content_slot_idx = content_hash%e_cache->cons_content_slots_count; + E_ConsTypeSlot *content_slot = &e_cache->cons_content_slots[content_slot_idx]; E_ConsTypeNode *node = 0; for(E_ConsTypeNode *n = content_slot->first; n != 0; n = n->content_next) { @@ -384,39 +386,53 @@ e_type_key_cons_(E_ConsTypeParams *params) { E_TypeKey key = {E_TypeKeyKind_Cons}; key.u32[0] = (U32)params->kind; - key.u32[1] = (U32)e_type_state->cons_id_gen; - e_type_state->cons_id_gen += 1; + key.u32[1] = (U32)e_cache->cons_id_gen; + e_cache->cons_id_gen += 1; 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]; - E_ConsTypeNode *node = push_array(e_type_state->arena, E_ConsTypeNode, 1); + U64 key_slot_idx = key_hash%e_cache->cons_key_slots_count; + E_ConsTypeSlot *key_slot = &e_cache->cons_key_slots[key_slot_idx]; + E_ConsTypeNode *node = push_array(e_cache->arena, E_ConsTypeNode, 1); SLLQueuePush_N(content_slot->first, content_slot->last, node, content_next); SLLQueuePush_N(key_slot->first, key_slot->last, node, key_next); node->key = key; MemoryCopyStruct(&node->params, params); - node->params.name = push_str8_copy(e_type_state->arena, params->name); + node->params.name = push_str8_copy(e_cache->arena, params->name); + if(node->params.expand.info != 0) + { + if(node->params.expand.range == 0) {node->params.expand.range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(default);} + if(node->params.expand.id_from_num == 0) {node->params.expand.id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity);} + if(node->params.expand.num_from_id == 0) {node->params.expand.num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity);} + } if(params->members != 0) { - node->params.members = push_array(e_type_state->arena, E_Member, params->count); + node->params.members = push_array(e_cache->arena, E_Member, params->count); MemoryCopy(node->params.members, params->members, sizeof(E_Member)*params->count); for(U64 idx = 0; idx < node->params.count; idx += 1) { - 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); + node->params.members[idx].name = push_str8_copy(e_cache->arena, node->params.members[idx].name); + node->params.members[idx].inheritance_key_chain = e_type_key_list_copy(e_cache->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) { - node->params.enum_vals = push_array(e_type_state->arena, E_EnumVal, params->count); + node->params.enum_vals = push_array(e_cache->arena, E_EnumVal, params->count); MemoryCopy(node->params.enum_vals, params->enum_vals, sizeof(E_EnumVal)*params->count); for(U64 idx = 0; idx < node->params.count; idx += 1) { - node->params.enum_vals[idx].name = push_str8_copy(e_type_state->arena, node->params.enum_vals[idx].name); + node->params.enum_vals[idx].name = push_str8_copy(e_cache->arena, node->params.enum_vals[idx].name); } node->byte_size = e_type_byte_size_from_key(node->params.direct_key); } + else if(params->args != 0) + { + node->params.args = push_array(e_cache->arena, E_Expr *, params->count); + for EachIndex(idx, params->count) + { + node->params.args[idx] = e_expr_copy(e_cache->arena, params->args[idx]); + } + } else switch(params->kind) { default: @@ -445,16 +461,37 @@ e_type_key_cons_(E_ConsTypeParams *params) //- rjf: constructed type helpers internal E_TypeKey -e_type_key_cons_array(E_TypeKey element_type_key, U64 count) +e_type_key_cons_array(E_TypeKey element_type_key, U64 count, E_TypeFlags flags) { - E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_Array, .direct_key = element_type_key, .count = count); + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_Array, .direct_key = element_type_key, .count = count, .flags = flags); return key; } internal E_TypeKey -e_type_key_cons_ptr(Arch arch, E_TypeKey element_type_key, E_TypeFlags flags) +e_type_key_cons_ptr(Arch arch, E_TypeKey element_type_key, U64 count, E_TypeFlags flags) { - E_TypeKey key = e_type_key_cons(.arch = arch, .kind = E_TypeKind_Ptr, .flags = flags, .direct_key = element_type_key); + E_TypeKey key = e_type_key_cons(.arch = arch, .kind = E_TypeKind_Ptr, .flags = flags, .direct_key = element_type_key, .count = count); + return key; +} + +internal E_TypeKey +e_type_key_cons_meta_expr(E_TypeKey type_key, String8 expr) +{ + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_MetaExpr, .direct_key = type_key, .name = expr); + return key; +} + +internal E_TypeKey +e_type_key_cons_meta_display_name(E_TypeKey type_key, String8 name) +{ + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_MetaDisplayName, .direct_key = type_key, .name = name); + return key; +} + +internal E_TypeKey +e_type_key_cons_meta_description(E_TypeKey type_key, String8 desc) +{ + E_TypeKey key = e_type_key_cons(.kind = E_TypeKind_MetaDescription, .direct_key = type_key, .name = desc); return key; } @@ -474,16 +511,15 @@ e_type_key_cons_base(Type *type) { E_TypeKey direct_type = e_type_key_cons_base(type->direct); E_TypeFlags flags = 0; - if(type->flags & TypeFlag_IsExternal) { flags |= E_TypeFlag_External; } if(type->flags & TypeFlag_IsPlainText){ flags |= E_TypeFlag_IsPlainText; } if(type->flags & TypeFlag_IsCodeText) { flags |= E_TypeFlag_IsCodeText; } if(type->flags & TypeFlag_IsPathText) { flags |= E_TypeFlag_IsPathText; } - result = e_type_key_cons_ptr(arch_from_context(), direct_type, flags); + result = e_type_key_cons_ptr(arch_from_context(), direct_type, 1, flags); }break; case TypeKind_Array: { E_TypeKey direct_type = e_type_key_cons_base(type->direct); - result = e_type_key_cons_array(direct_type, type->count); + result = e_type_key_cons_array(direct_type, type->count, 0); }break; case TypeKind_Struct: { @@ -492,7 +528,7 @@ e_type_key_cons_base(Type *type) for(U64 idx = 0; idx < type->count; idx += 1) { E_TypeKey member_type_key = e_type_key_cons_base(type->members[idx].type); - e_member_list_push_new(scratch.arena, &members, .name = type->members[idx].name, .off = type->members[idx].value, .type_key = member_type_key, .pretty_name = type->members[idx].pretty_name); + e_member_list_push_new(scratch.arena, &members, .name = type->members[idx].name, .off = type->members[idx].value, .type_key = member_type_key); } E_MemberArray members_array = e_member_array_from_list(scratch.arena, &members); result = e_type_key_cons(.arch = arch_from_context(), @@ -506,6 +542,20 @@ e_type_key_cons_base(Type *type) return result; } +internal E_TypeKey +e_type_key_file(void) +{ + E_TypeKey key = e_cache->file_type_key; + return key; +} + +internal E_TypeKey +e_type_key_folder(void) +{ + E_TypeKey key = e_cache->folder_type_key; + return key; +} + //- rjf: basic type key functions internal B32 @@ -515,16 +565,15 @@ e_type_key_match(E_TypeKey l, E_TypeKey r) return result; } -//- rjf: key -> info extraction +//- rjf: type key -> info extraction internal U64 -e_hash_from_type_key(E_TypeKey key) +e_hash_from_type(E_Type *type) { U64 hash = 0; - if(!e_type_key_match(e_type_key_zero(), key)) + if(type != &e_type_nil) { Temp scratch = scratch_begin(0, 0); - E_Type *type = e_type_from_key(scratch.arena, key); String8List strings = {0}; str8_serial_begin(scratch.arena, &strings); str8_serial_push_struct(scratch.arena, &strings, &type->kind); @@ -581,8 +630,50 @@ e_type_kind_from_key(E_TypeKey key) return kind; } +internal U64 +e_type_byte_size_from_key(E_TypeKey key) +{ + ProfBeginFunction(); + U64 result = 0; + switch(key.kind) + { + default:{}break; + case E_TypeKeyKind_Basic: + { + E_TypeKind kind = (E_TypeKind)key.u32[0]; + result = e_type_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_base_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: + { + U64 key_hash = e_hash_from_string(5381, str8_struct(&key)); + U64 key_slot_idx = key_hash%e_cache->cons_key_slots_count; + E_ConsTypeSlot *key_slot = &e_cache->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; +} + internal E_Type * -e_type_from_key(Arena *arena, E_TypeKey key) +e_push_type_from_key(Arena *arena, E_TypeKey key) { ProfBeginFunction(); E_Type *type = &e_type_nil; @@ -600,8 +691,8 @@ e_type_from_key(Arena *arena, E_TypeKey key) { type = push_array(arena, E_Type, 1); type->kind = kind; - type->name = e_kind_basic_string_table[kind]; - type->byte_size = e_kind_basic_byte_size_table[kind]; + type->name = e_type_kind_basic_string_table[kind]; + type->byte_size = e_type_kind_basic_byte_size_table[kind]; } }break; @@ -609,8 +700,8 @@ e_type_from_key(Arena *arena, E_TypeKey key) case E_TypeKeyKind_Cons: { 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]; + U64 key_slot_idx = key_hash%e_cache->cons_key_slots_count; + E_ConsTypeSlot *key_slot = &e_cache->cons_key_slots[key_slot_idx]; for(E_ConsTypeNode *node = key_slot->first; node != 0; node = node->key_next) @@ -618,14 +709,29 @@ e_type_from_key(Arena *arena, E_TypeKey key) if(e_type_key_match(node->key, key)) { type = push_array(arena, E_Type, 1); - type->kind = e_type_kind_from_key(node->key); - type->flags = node->params.flags; - 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; + type->kind = e_type_kind_from_key(node->key); + type->flags = node->params.flags; + type->name = push_str8_copy(arena, node->params.name); + type->direct_type_key = node->params.direct_key; + type->count = node->params.count; + type->depth = node->params.depth; + type->arch = node->params.arch; + type->irext = node->params.irext; + type->access = node->params.access; + type->expand = node->params.expand; + type->byte_size = node->byte_size; switch(type->kind) { + default:{}break; + case E_TypeKind_Lens: + { + type->args = push_array(arena, E_Expr *, type->count); + MemoryCopy(type->args, node->params.args, sizeof(E_Expr *)*type->count); + for EachIndex(idx, type->count) + { + type->args[idx] = e_expr_copy(arena, type->args[idx]); + } + }break; case E_TypeKind_Struct: case E_TypeKind_Union: case E_TypeKind_Class: @@ -653,7 +759,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) { 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_Parsed *rdi = e_base_ctx->modules[rdi_idx].rdi; RDI_TypeNode *rdi_type = rdi_element_from_name_idx(rdi, TypeNodes, type_node_idx); if(rdi_type->kind != RDI_TypeKind_NULL) { @@ -700,6 +806,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->name = push_str8_copy(arena, name); type->byte_size = (U64)rdi_type->byte_size; type->count = members_count; + type->arch = e_base_ctx->modules[rdi_idx].arch; type->members = members; } @@ -744,6 +851,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->name = push_str8_copy(arena, name); type->byte_size = (U64)rdi_type->byte_size; type->count = enum_vals_count; + type->arch = e_base_ctx->modules[rdi_idx].arch; type->enum_vals = enum_vals; type->direct_type_key = direct_type_key; } @@ -783,6 +891,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->direct_type_key = direct_type_key; type->byte_size = direct_type_byte_size; type->flags = flags; + type->arch = e_base_ctx->modules[rdi_idx].arch; }break; case RDI_TypeKind_Ptr: case RDI_TypeKind_LRef: @@ -791,7 +900,9 @@ e_type_from_key(Arena *arena, E_TypeKey key) type = push_array(arena, E_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; - type->byte_size = bit_size_from_arch(e_type_state->ctx->modules[rdi_idx].arch)/8; + type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; + type->count = 1; + type->arch = e_base_ctx->modules[rdi_idx].arch; }break; case RDI_TypeKind_Array: @@ -801,6 +912,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->direct_type_key = direct_type_key; type->count = rdi_type->constructed.count; type->byte_size = direct_type_byte_size * type->count; + type->arch = e_base_ctx->modules[rdi_idx].arch; }break; case RDI_TypeKind_Function: { @@ -812,10 +924,11 @@ e_type_from_key(Arena *arena, E_TypeKey key) { type = push_array(arena, E_Type, 1); type->kind = kind; - type->byte_size = bit_size_from_arch(e_type_state->ctx->modules[rdi_idx].arch)/8; + type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; type->direct_type_key = direct_type_key; type->count = count; type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); + type->arch = e_base_ctx->modules[rdi_idx].arch; for(U32 idx = 0; idx < type->count; idx += 1) { U32 param_type_idx = idx_run[idx]; @@ -845,10 +958,11 @@ e_type_from_key(Arena *arena, E_TypeKey key) { type = push_array(arena, E_Type, 1); type->kind = kind; - type->byte_size = bit_size_from_arch(e_type_state->ctx->modules[rdi_idx].arch)/8; + type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; type->owner_type_key = direct_type_key; type->count = count; type->param_type_keys = push_array_no_zero(arena, E_TypeKey, type->count); + type->arch = e_base_ctx->modules[rdi_idx].arch; for(U32 idx = 0; idx < type->count; idx += 1) { U32 param_type_idx = idx_run[idx]; @@ -883,9 +997,10 @@ e_type_from_key(Arena *arena, E_TypeKey key) } type = push_array(arena, E_Type, 1); type->kind = kind; - type->byte_size = bit_size_from_arch(e_type_state->ctx->modules[rdi_idx].arch)/8; + type->byte_size = bit_size_from_arch(e_base_ctx->modules[rdi_idx].arch)/8; type->owner_type_key = owner_type_key; type->direct_type_key = direct_type_key; + type->arch = e_base_ctx->modules[rdi_idx].arch; }break; } } @@ -914,6 +1029,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->name = push_str8_copy(arena, name); type->byte_size = direct_type_byte_size; type->direct_type_key = direct_type_key; + type->arch = e_base_ctx->modules[rdi_idx].arch; } //- rjf: bitfields @@ -937,6 +1053,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->direct_type_key = direct_type_key; type->off = (U32)rdi_type->bitfield.off; type->count = (U64)rdi_type->bitfield.size; + type->arch = e_base_ctx->modules[rdi_idx].arch; } //- rjf: incomplete types @@ -950,6 +1067,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type = push_array(arena, E_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); + type->arch = e_base_ctx->modules[rdi_idx].arch; } } @@ -977,6 +1095,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) type->kind = E_TypeKind_Union; type->name = push_str8f(arena, "reg_%I64u_bit", reg_byte_count*8); type->byte_size = (U64)reg_byte_count; + type->arch = (Arch)key.u32[0]; // rjf: build register type members E_MemberList members = {0}; @@ -1045,7 +1164,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u128s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U128), reg_byte_count/16); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U128), reg_byte_count/16, 0); } if(type->byte_size > 8 && type->byte_size%8 == 0) { @@ -1055,7 +1174,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u64s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U64), reg_byte_count/8); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U64), reg_byte_count/8, 0); } if(type->byte_size > 4 && type->byte_size%4 == 0) { @@ -1065,7 +1184,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u32s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U32), reg_byte_count/4); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U32), reg_byte_count/4, 0); } if(type->byte_size > 2 && type->byte_size%2 == 0) { @@ -1075,7 +1194,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u16s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U16), reg_byte_count/2); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U16), reg_byte_count/2, 0); } if(type->byte_size > 1) { @@ -1085,7 +1204,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("u8s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), reg_byte_count); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), reg_byte_count, E_TypeFlag_IsNotText); } if(type->byte_size > 4 && type->byte_size%4 == 0) { @@ -1095,7 +1214,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("f32s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F32), reg_byte_count/4); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F32), reg_byte_count/4, 0); } if(type->byte_size > 8 && type->byte_size%8 == 0) { @@ -1105,7 +1224,7 @@ e_type_from_key(Arena *arena, E_TypeKey key) E_Member *mem = &n->v; mem->kind = E_MemberKind_DataField; mem->name = str8_lit("f64s"); - mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F64), reg_byte_count/8); + mem->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_F64), reg_byte_count/8, 0); } } } @@ -1127,301 +1246,19 @@ e_type_from_key(Arena *arena, E_TypeKey key) return type; } -internal U64 -e_type_byte_size_from_key(E_TypeKey key) -{ - ProfBeginFunction(); - U64 result = 0; - switch(key.kind) - { - default:{}break; - case E_TypeKeyKind_Basic: - { - E_TypeKind kind = (E_TypeKind)key.u32[0]; - 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: - { - 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; -} - -internal E_TypeKey -e_type_direct_from_key(E_TypeKey key) -{ - E_TypeKey result = zero_struct; - switch(key.kind) - { - default:{}break; - case E_TypeKeyKind_Ext: - case E_TypeKeyKind_Cons: - { - Temp scratch = scratch_begin(0, 0); - E_Type *type = e_type_from_key(scratch.arena, key); - result = type->direct_type_key; - scratch_end(scratch); - }break; - } - return result; -} - -internal E_TypeKey -e_type_owner_from_key(E_TypeKey key) -{ - E_TypeKey result = zero_struct; - switch(key.kind) - { - default:{}break; - case E_TypeKeyKind_Ext: - case E_TypeKeyKind_Cons: - { - Temp scratch = scratch_begin(0, 0); - E_Type *type = e_type_from_key(scratch.arena, key); - result = type->owner_type_key; - scratch_end(scratch); - }break; - } - return result; -} - -internal E_TypeKey -e_type_ptee_from_key(E_TypeKey key) -{ - E_TypeKey result = key; - B32 passed_ptr = 0; - for(;;) - { - E_TypeKind kind = e_type_kind_from_key(result); - result = e_type_direct_from_key(result); - if(kind == E_TypeKind_Ptr || kind == E_TypeKind_LRef || kind == E_TypeKind_RRef) - { - passed_ptr = 1; - } - E_TypeKind next_kind = e_type_kind_from_key(result); - if(passed_ptr && - next_kind != E_TypeKind_IncompleteStruct && - next_kind != E_TypeKind_IncompleteUnion && - next_kind != E_TypeKind_IncompleteEnum && - next_kind != E_TypeKind_IncompleteClass && - next_kind != E_TypeKind_Alias && - next_kind != E_TypeKind_Modifier) - { - break; - } - if(kind == E_TypeKind_Null) - { - break; - } - } - return result; -} - -internal E_TypeKey -e_type_unwrap_enum(E_TypeKey key) -{ - E_TypeKey result = key; - for(B32 good = 1; good;) - { - E_TypeKind kind = e_type_kind_from_key(result); - if(kind == E_TypeKind_Enum) - { - result = e_type_direct_from_key(result); - } - else - { - good = 0; - } - } - return result; -} - -internal E_TypeKey -e_type_unwrap(E_TypeKey key) -{ - E_TypeKey result = key; - for(B32 good = 1; good;) - { - E_TypeKind kind = e_type_kind_from_key(result); - if((E_TypeKind_FirstIncomplete <= kind && kind <= E_TypeKind_LastIncomplete) || - kind == E_TypeKind_Modifier || - kind == E_TypeKind_Alias) - { - result = e_type_direct_from_key(result); - } - else - { - good = 0; - } - } - return result; -} - -internal E_TypeKey -e_type_promote(E_TypeKey key) -{ - E_TypeKey result = key; - E_TypeKind kind = e_type_kind_from_key(key); - if(kind == E_TypeKind_Bool || - kind == E_TypeKind_S8 || - kind == E_TypeKind_S16 || - kind == E_TypeKind_U8 || - kind == E_TypeKind_U16) - { - result = e_type_key_basic(E_TypeKind_S32); - } - return result; -} - -internal B32 -e_type_match(E_TypeKey l, E_TypeKey r) -{ - // rjf: unpack parameters - E_TypeKey lu = e_type_unwrap(l); - E_TypeKey ru = e_type_unwrap(r); - - // rjf: exact key matches -> match - B32 result = e_type_key_match(lu, ru); - - // rjf: if keys don't match, type *contents* could still match, - // so we need to unpack the type info & compare - if(!result) - { - E_TypeKind luk = e_type_kind_from_key(lu); - E_TypeKind ruk = e_type_kind_from_key(ru); - if(luk == ruk) - { - switch(luk) - { - default: - { - result = 1; - }break; - - case E_TypeKind_Ptr: - case E_TypeKind_LRef: - case E_TypeKind_RRef: - { - E_TypeKey lud = e_type_direct_from_key(lu); - E_TypeKey rud = e_type_direct_from_key(ru); - result = e_type_match(lud, rud); - }break; - - case E_TypeKind_MemberPtr: - { - E_TypeKey lud = e_type_direct_from_key(lu); - E_TypeKey rud = e_type_direct_from_key(ru); - E_TypeKey luo = e_type_owner_from_key(lu); - E_TypeKey ruo = e_type_owner_from_key(ru); - result = (e_type_match(lud, rud) && e_type_match(luo, ruo)); - }break; - - case E_TypeKind_Array: - { - Temp scratch = scratch_begin(0, 0); - E_Type *lt = e_type_from_key(scratch.arena, l); - E_Type *rt = e_type_from_key(scratch.arena, r); - if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) - { - result = 1; - } - scratch_end(scratch); - }break; - - case E_TypeKind_Function: - { - Temp scratch = scratch_begin(0, 0); - E_Type *lt = e_type_from_key(scratch.arena, l); - E_Type *rt = e_type_from_key(scratch.arena, r); - if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) - { - B32 params_match = 1; - E_TypeKey *lp = lt->param_type_keys; - E_TypeKey *rp = rt->param_type_keys; - U64 count = lt->count; - for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) - { - if(!e_type_match(*lp, *rp)) - { - params_match = 0; - break; - } - } - result = params_match; - } - scratch_end(scratch); - }break; - - case E_TypeKind_Method: - { - Temp scratch = scratch_begin(0, 0); - E_Type *lt = e_type_from_key(scratch.arena, l); - E_Type *rt = e_type_from_key(scratch.arena, r); - if(lt->count == rt->count && - e_type_match(lt->direct_type_key, rt->direct_type_key) && - e_type_match(lt->owner_type_key, rt->owner_type_key)) - { - B32 params_match = 1; - E_TypeKey *lp = lt->param_type_keys; - E_TypeKey *rp = rt->param_type_keys; - U64 count = lt->count; - for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) - { - if(!e_type_match(*lp, *rp)) - { - params_match = 0; - break; - } - } - result = params_match; - } - scratch_end(scratch); - }break; - } - } - } - - return result; -} - -internal E_Member * -e_type_member_copy(Arena *arena, E_Member *src) -{ - E_Member *dst = push_array(arena, E_Member, 1); - MemoryCopyStruct(dst, src); - dst->name = push_str8_copy(arena, src->name); - dst->pretty_name = push_str8_copy(arena, src->pretty_name); - dst->inheritance_key_chain = e_type_key_list_copy(arena, &src->inheritance_key_chain); - return dst; -} - internal int e_type_qsort_compare_members_offset(E_Member *a, E_Member *b) { int result = 0; - if(a->off < b->off) + if(a->kind < b->kind) + { + result = -1; + } + else if(a->kind > b->kind) + { + result = +1; + } + else if(a->off < b->off) { result = -1; } @@ -1442,7 +1279,7 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) E_MemberList members_list = {0}; B32 members_need_offset_sort = 0; { - E_Type *root_type = e_type_from_key(scratch.arena, key); + E_Type *root_type = e_type_from_key(key); typedef struct Task Task; struct Task { @@ -1463,7 +1300,7 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) U64 last_member_off = 0; for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) { - if(type->members[member_idx].kind == E_MemberKind_DataField) + if(type->members[member_idx].name.size != 0 && type->members[member_idx].kind == E_MemberKind_DataField) { E_MemberNode *n = push_array(scratch.arena, E_MemberNode, 1); MemoryCopyStruct(&n->v, &type->members[member_idx]); @@ -1471,7 +1308,7 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) n->v.inheritance_key_chain = task->inheritance_chain; SLLQueuePush(members_list.first, members_list.last, n); members_list.count += 1; - members_need_offset_sort = members_need_offset_sort || (n->v.off < last_member_off); + members_need_offset_sort = members_need_offset_sort || (type->members[member_idx].kind == E_MemberKind_DataField && n->v.off < last_member_off); last_member_off = n->v.off; } else if(type->members[member_idx].kind == E_MemberKind_Base) @@ -1481,7 +1318,7 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) t->inheritance_chain = e_type_key_list_copy(scratch.arena, &task->inheritance_chain); e_type_key_list_push(scratch.arena, &t->inheritance_chain, type->members[member_idx].type_key); t->type_key = type->members[member_idx].type_key; - t->type = e_type_from_key(scratch.arena, type->members[member_idx].type_key); + t->type = e_type_from_key(type->members[member_idx].type_key); SLLQueuePush(first_task, last_task, t); members_need_offset_sort = 1; } @@ -1564,9 +1401,9 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) E_Member *padding_member = &new_members.v[n->prev_member_idx+padding_idx+1]; MemoryZeroStruct(padding_member); padding_member->kind = E_MemberKind_Padding; - padding_member->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), n->size); + padding_member->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), n->size, E_TypeFlag_IsNotText); padding_member->off = n->off; - padding_member->name = push_str8f(arena, "[padding %I64u]", padding_idx); + padding_member->name = push_str8f(arena, "$padding_%I64u", padding_idx); padding_idx += 1; } members = new_members; @@ -1576,23 +1413,237 @@ e_type_data_members_from_key(Arena *arena, E_TypeKey key) return members; } -internal E_Member * -e_type_member_from_array_name(E_MemberArray *members, String8 name) +internal E_TypeExpandRule * +e_expand_rule_from_type_key(E_TypeKey key) { - E_Member *member = 0; - for(U64 idx = 0; idx < members->count; idx += 1) + E_TypeExpandRule *rule = &e_type_expand_rule__default; { - if((members->v[idx].kind == E_MemberKind_DataField || - members->v[idx].kind == E_MemberKind_Padding) && - str8_match(members->v[idx].name, name, 0)) + E_Type *type = e_type_from_key(e_type_key_unwrap(key, E_TypeUnwrapFlag_Meta)); + if(type->expand.info != 0) { - member = &members->v[idx]; - break; + rule = &type->expand; + } + for(E_Type *lens_type = type; + lens_type->kind == E_TypeKind_Lens || lens_type->kind == E_TypeKind_Set; + lens_type = e_type_from_key(e_type_key_unwrap(lens_type->direct_type_key, E_TypeUnwrapFlag_Meta))) + { + if(lens_type->expand.info != 0) + { + rule = &lens_type->expand; + break; + } } } - return member; + return rule; } +//- rjf: type key traversal + +internal E_TypeKey +e_type_key_direct(E_TypeKey key) +{ + E_TypeKey result = zero_struct; + switch(key.kind) + { + default:{}break; + case E_TypeKeyKind_Ext: + case E_TypeKeyKind_Cons: + { + E_Type *type = e_type_from_key(key); + result = type->direct_type_key; + }break; + } + return result; +} + +internal E_TypeKey +e_type_key_owner(E_TypeKey key) +{ + E_TypeKey result = zero_struct; + switch(key.kind) + { + default:{}break; + case E_TypeKeyKind_Ext: + case E_TypeKeyKind_Cons: + { + E_Type *type = e_type_from_key(key); + result = type->owner_type_key; + }break; + } + return result; +} + +internal E_TypeKey +e_type_key_promote(E_TypeKey key) +{ + E_TypeKey result = key; + E_TypeKind kind = e_type_kind_from_key(key); + if(kind == E_TypeKind_Bool || + kind == E_TypeKind_S8 || + kind == E_TypeKind_S16 || + kind == E_TypeKind_U8 || + kind == E_TypeKind_U16) + { + result = e_type_key_basic(E_TypeKind_S32); + } + return result; +} + +internal E_TypeKey +e_type_key_unwrap(E_TypeKey key, E_TypeUnwrapFlags flags) +{ + E_TypeKey result = key; + E_TypeKind kind = e_type_kind_from_key(result); + B32 did_ptr = 0; + for(;;) + { + B32 done = 0; + switch(kind) + { + default:{done = 1;}break; + case E_TypeKind_Modifier: {done = !(flags & E_TypeUnwrapFlag_Modifiers);}break; + case E_TypeKind_Lens: {done = !(flags & E_TypeUnwrapFlag_Lenses);}break; + case E_TypeKind_MetaDisplayName: + case E_TypeKind_MetaDescription: + case E_TypeKind_MetaExpr: {done = !(flags & E_TypeUnwrapFlag_Meta);}break; + case E_TypeKind_Enum: {done = !(flags & E_TypeUnwrapFlag_Enums);}break; + case E_TypeKind_Alias: {done = !(flags & E_TypeUnwrapFlag_Aliases);}break; + case E_TypeKind_Array: + case E_TypeKind_Ptr: + case E_TypeKind_RRef: + case E_TypeKind_LRef: + case E_TypeKind_MemberPtr: + { + done = (did_ptr || !(flags & E_TypeUnwrapFlag_Pointers)); + did_ptr = 1; + }break; + } + if(done) + { + break; + } + result = e_type_key_direct(result); + kind = e_type_kind_from_key(result); + } + return result; +} + +//- rjf: type comparisons + +internal B32 +e_type_match(E_TypeKey l, E_TypeKey r) +{ + // rjf: unpack parameters + E_TypeKey lu = e_type_key_unwrap(l, E_TypeUnwrapFlag_AllDecorative); + E_TypeKey ru = e_type_key_unwrap(r, E_TypeUnwrapFlag_AllDecorative); + + // rjf: exact key matches -> match + B32 result = e_type_key_match(lu, ru); + + // rjf: if keys don't match, type *contents* could still match, + // so we need to unpack the type info & compare + if(!result) + { + E_TypeKind luk = e_type_kind_from_key(lu); + E_TypeKind ruk = e_type_kind_from_key(ru); + if(luk == ruk) + { + switch(luk) + { + default: + { + if(e_type_kind_is_basic_or_enum(luk)) + { + result = 1; + } + else + { + result = 0; + } + }break; + + case E_TypeKind_Ptr: + case E_TypeKind_LRef: + case E_TypeKind_RRef: + { + E_TypeKey lud = e_type_key_direct(lu); + E_TypeKey rud = e_type_key_direct(ru); + result = e_type_match(lud, rud); + }break; + + case E_TypeKind_MemberPtr: + { + E_TypeKey lud = e_type_key_direct(lu); + E_TypeKey rud = e_type_key_direct(ru); + E_TypeKey luo = e_type_key_owner(lu); + E_TypeKey ruo = e_type_key_owner(ru); + result = (e_type_match(lud, rud) && e_type_match(luo, ruo)); + }break; + + case E_TypeKind_Array: + { + E_Type *lt = e_type_from_key(l); + E_Type *rt = e_type_from_key(r); + if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) + { + result = 1; + } + }break; + + case E_TypeKind_Function: + { + E_Type *lt = e_type_from_key(l); + E_Type *rt = e_type_from_key(r); + if(lt->count == rt->count && e_type_match(lt->direct_type_key, rt->direct_type_key)) + { + B32 params_match = 1; + E_TypeKey *lp = lt->param_type_keys; + E_TypeKey *rp = rt->param_type_keys; + U64 count = lt->count; + for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) + { + if(!e_type_match(*lp, *rp)) + { + params_match = 0; + break; + } + } + result = params_match; + } + }break; + + case E_TypeKind_Method: + { + E_Type *lt = e_type_from_key(l); + E_Type *rt = e_type_from_key(r); + if(lt->count == rt->count && + e_type_match(lt->direct_type_key, rt->direct_type_key) && + e_type_match(lt->owner_type_key, rt->owner_type_key)) + { + B32 params_match = 1; + E_TypeKey *lp = lt->param_type_keys; + E_TypeKey *rp = rt->param_type_keys; + U64 count = lt->count; + for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) + { + if(!e_type_match(*lp, *rp)) + { + params_match = 0; + break; + } + } + result = params_match; + } + }break; + } + } + } + + return result; +} + +//- rjf: key -> string + internal void e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 prec, B32 skip_return) { @@ -1602,26 +1653,20 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr { default: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); - str8_list_push(arena, out, push_str8_copy(arena, type->name)); - str8_list_push(arena, out, str8_lit(" ")); - scratch_end(scratch); + E_Type *type = e_type_from_key(key); + str8_list_pushf(arena, out, "%S ", type->name); }break; case E_TypeKind_Bitfield: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); e_type_lhs_string_from_key(arena, type->direct_type_key, out, prec, skip_return); str8_list_pushf(arena, out, ": %I64u", type->count); - scratch_end(scratch); }break; case E_TypeKind_Modifier: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); E_TypeKey direct = type->direct_type_key; e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); if(type->flags & E_TypeFlag_Const) @@ -1632,7 +1677,6 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr { str8_list_push(arena, out, str8_lit("volatile ")); } - scratch_end(scratch); }break; case E_TypeKind_Variadic: @@ -1646,11 +1690,8 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr case E_TypeKind_Class: case E_TypeKind_Alias: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); - str8_list_push(arena, out, push_str8_copy(arena, type->name)); - str8_list_push(arena, out, str8_lit(" ")); - scratch_end(scratch); + E_Type *type = e_type_from_key(key); + str8_list_pushf(arena, out, "%S ", type->name); }break; case E_TypeKind_IncompleteStruct: keyword = str8_lit("struct"); goto fwd_udt; @@ -1659,18 +1700,15 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr case E_TypeKind_IncompleteClass: keyword = str8_lit("class"); goto fwd_udt; fwd_udt:; { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); str8_list_push(arena, out, keyword); str8_list_push(arena, out, str8_lit(" ")); - str8_list_push(arena, out, push_str8_copy(arena, type->name)); - str8_list_push(arena, out, str8_lit(" ")); - scratch_end(scratch); + str8_list_pushf(arena, out, "%S ", type->name); }break; case E_TypeKind_Array: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_lhs_string_from_key(arena, direct, out, 2, skip_return); if(prec == 1) { @@ -1682,7 +1720,7 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr { if(!skip_return) { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_lhs_string_from_key(arena, direct, out, 2, 0); } if(prec == 1) @@ -1691,34 +1729,54 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr } }break; + case E_TypeKind_Lens: + { + E_Type *type = e_type_from_key(key); + str8_list_pushf(arena, out, "%S(", type->name); + E_TypeKey direct = e_type_key_direct(key); + String8 direct_string = e_type_string_from_key(arena, direct); + str8_list_push(arena, out, direct_string); + for EachIndex(idx, type->count) + { + String8 string = e_string_from_expr(arena, type->args[idx], str8_zero()); + str8_list_pushf(arena, out, ", "); + str8_list_push(arena, out, string); + } + str8_list_pushf(arena, out, ")"); + }break; + case E_TypeKind_Ptr: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("*")); + E_Type *type = e_type_from_key(key); + if(type->count != 1) + { + str8_list_pushf(arena, out, ".%I64u", type->count); + } }break; case E_TypeKind_LRef: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&")); }break; case E_TypeKind_RRef: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&&")); }break; case E_TypeKind_MemberPtr: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); E_TypeKey direct = type->direct_type_key; e_type_lhs_string_from_key(arena, direct, out, 1, skip_return); - E_Type *container = e_type_from_key(scratch.arena, type->owner_type_key); + E_Type *container = e_type_from_key(type->owner_type_key); if(container->kind != E_TypeKind_Null) { str8_list_push(arena, out, push_str8_copy(arena, container->name)); @@ -1728,7 +1786,14 @@ e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr str8_list_push(arena, out, str8_lit("")); } str8_list_push(arena, out, str8_lit("::*")); - scratch_end(scratch); + }break; + + case E_TypeKind_MetaExpr: + case E_TypeKind_MetaDisplayName: + case E_TypeKind_MetaDescription: + { + E_TypeKey direct = e_type_key_direct(key); + e_type_lhs_string_from_key(arena, direct, out, prec, skip_return); }break; } } @@ -1743,7 +1808,7 @@ e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr case E_TypeKind_Bitfield: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_rhs_string_from_key(arena, direct, out, prec); }break; @@ -1753,14 +1818,13 @@ e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr case E_TypeKind_RRef: case E_TypeKind_MemberPtr: { - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_rhs_string_from_key(arena, direct, out, 1); }break; case E_TypeKind_Array: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); @@ -1769,15 +1833,13 @@ e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr str8_list_push(arena, out, str8_lit("[")); str8_list_push(arena, out, count_str); str8_list_push(arena, out, str8_lit("]")); - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_rhs_string_from_key(arena, direct, out, 2); - scratch_end(scratch); }break; case E_TypeKind_Function: { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, key); + E_Type *type = e_type_from_key(key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); @@ -1804,9 +1866,14 @@ e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 pr } str8_list_push(arena, out, str8_lit(")")); } - E_TypeKey direct = e_type_direct_from_key(key); + E_TypeKey direct = e_type_key_direct(key); e_type_rhs_string_from_key(arena, direct, out, 2); - scratch_end(scratch); + }break; + + case E_TypeKind_MetaExpr: + { + E_TypeKey direct = e_type_key_direct(key); + e_type_rhs_string_from_key(arena, direct, out, prec); }break; } } @@ -1824,37 +1891,143 @@ e_type_string_from_key(Arena *arena, E_TypeKey key) return result; } -//- rjf: type key data structures - -internal void -e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key) +internal E_TypeKey +e_default_expansion_type_from_key(E_TypeKey root_key) { - E_TypeKeyNode *n = push_array(arena, E_TypeKeyNode, 1); - n->v = key; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal E_TypeKeyList -e_type_key_list_copy(Arena *arena, E_TypeKeyList *src) -{ - E_TypeKeyList dst = {0}; - for(E_TypeKeyNode *n = src->first; n != 0; n = n->next) + E_TypeKey type_key = zero_struct; + B32 hit_1ptr = 0; + for(E_TypeKey key = root_key; + !e_type_key_match(e_type_key_zero(), key); + key = e_type_key_direct(key)) { - e_type_key_list_push(arena, &dst, n->v); + B32 done = 1; + E_TypeKind kind = e_type_kind_from_key(key); + + //- rjf: if we have pointers which point to a single thing (count = 1), + // or we have a lens, or we have a modifier node, then we will defer to + // the next type in the chain. + // + // if this pointer points to N things (count > 1), then we can use it for + // array-like expansion. + // + if(e_type_kind_is_pointer_or_ref(kind)) + { + E_Type *type = e_type_from_key(key); + if(!e_type_key_match(e_type_key_basic(E_TypeKind_Void), type->direct_type_key)) + { + if(type->count == 1 && hit_1ptr) + { + type_key = key; + } + else if(type->count == 1 && !hit_1ptr) + { + hit_1ptr = 1; + done = 0; + } + else if(type->count > 1) + { + type_key = key; + } + } + } + + //- rjf: if we have lenses or modifiers in the type chain, then we will + // defer to the next type in the chain. + // + // NOTE(rjf): while it may seem like a lens type needs to do something + // different, because lenses sometimes want to define their own expansion + // rules, they would've redirected to an entirely different expansion + // hook. if we are in the default expansion hook, then the lenses do not + // impact the expansion at all (e.g. they are for other cosmetic things, + // like visualizers or integer radix changes), and so in that case we + // want to ignore them. + // + else if(kind == E_TypeKind_Lens || + kind == E_TypeKind_Modifier) + { + done = 0; + } + + //- rjf: if we have meta-expression tags in the type chain, defer + // to the next type in the chain. + else if(E_TypeKind_FirstMeta <= kind && kind <= E_TypeKind_LastMeta) + { + done = 0; + } + + //- rjf: if we've reached a struct-like, then we can use that for + // struct-like expansion. + else if(kind == E_TypeKind_Struct || + kind == E_TypeKind_Union || + kind == E_TypeKind_Class || + kind == E_TypeKind_Set) + { + type_key = key; + } + + //- rjf: if we've reached an enum-like, then we can use that for + // enum-like expansion. + else if(kind == E_TypeKind_Enum) + { + type_key = key; + } + + //- rjf: if we've reached an array, then we can use that for array-like + // expansion. + else if(kind == E_TypeKind_Array) + { + type_key = key; + } + + //- rjf: if we're done, then just break. + if(done) + { + break; + } } - return dst; + + return type_key; } //////////////////////////////// //~ rjf: Cache Lookups +internal E_Type * +e_type_from_key(E_TypeKey key) +{ + E_Type *type = &e_type_nil; + { + U64 hash = e_hash_from_string(5381, str8_struct(&key)); + U64 slot_idx = hash%e_cache->type_cache_slots_count; + E_TypeCacheNode *node = 0; + for(E_TypeCacheNode *n = e_cache->type_cache_slots[slot_idx].first; n != 0; n = n->next) + { + if(e_type_key_match(key, n->key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(e_cache->arena, E_TypeCacheNode, 1); + node->key = key; + node->type = e_push_type_from_key(e_cache->arena, key); + SLLQueuePush(e_cache->type_cache_slots[slot_idx].first, e_cache->type_cache_slots[slot_idx].last, node); + } + type = node->type; + } + return type; +} + +//- rjf: member lookups + internal E_MemberCacheNode * e_member_cache_node_from_type_key(E_TypeKey key) { U64 hash = e_hash_from_string(5381, str8_struct(&key)); - U64 slot_idx = hash%e_type_state->member_cache_slots_count; - E_MemberCacheSlot *slot = &e_type_state->member_cache_slots[slot_idx]; + U64 slot_idx = hash%e_cache->member_cache_slots_count; + E_MemberCacheSlot *slot = &e_cache->member_cache_slots[slot_idx]; E_MemberCacheNode *node = 0; for(E_MemberCacheNode *n = slot->first; n != 0; n = n->next) { @@ -1866,17 +2039,19 @@ e_member_cache_node_from_type_key(E_TypeKey key) } if(node == 0) { - node = push_array(e_type_state->arena, E_MemberCacheNode, 1); + node = push_array(e_cache->arena, E_MemberCacheNode, 1); SLLQueuePush(slot->first, slot->last, node); node->key = key; - node->members = e_type_data_members_from_key(e_type_state->arena, key); + node->members = e_type_data_members_from_key(e_cache->arena, key); node->member_hash_slots_count = node->members.count; - node->member_hash_slots = push_array(e_type_state->arena, E_MemberHashSlot, node->member_hash_slots_count); + node->member_hash_slots = push_array(e_cache->arena, E_MemberHashSlot, node->member_hash_slots_count); + node->member_filter_slots_count = 16; + node->member_filter_slots = push_array(e_cache->arena, E_MemberFilterSlot, node->member_filter_slots_count); for EachIndex(idx, node->members.count) { U64 hash = e_hash_from_string(5381, node->members.v[idx].name); U64 slot_idx = hash%node->member_hash_slots_count; - E_MemberHashNode *n = push_array(e_type_state->arena, E_MemberHashNode, 1); + E_MemberHashNode *n = push_array(e_cache->arena, E_MemberHashNode, 1); SLLQueuePush(node->member_hash_slots[slot_idx].first, node->member_hash_slots[slot_idx].last, n); n->member_idx = idx; } @@ -1884,6 +2059,55 @@ e_member_cache_node_from_type_key(E_TypeKey key) return node; } +internal E_MemberArray +e_type_data_members_from_key_filter__cached(E_TypeKey key, String8 filter) +{ + E_MemberArray members = {0}; + E_MemberCacheNode *node = e_member_cache_node_from_type_key(key); + if(node != 0) + { + if(filter.size == 0) + { + members = node->members; + } + else + { + U64 hash = e_hash_from_string(5381, filter); + U64 slot_idx = hash%node->member_filter_slots_count; + E_MemberFilterSlot *slot = &node->member_filter_slots[slot_idx]; + E_MemberFilterNode *filter_node = 0; + for(E_MemberFilterNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->filter, filter, 0)) + { + filter_node = n; + break; + } + } + if(filter_node == 0) + { + Temp scratch = scratch_begin(0, 0); + filter_node = push_array(e_cache->arena, E_MemberFilterNode, 1); + filter_node->filter = push_str8_copy(e_cache->arena, filter); + E_MemberList member_list__filtered = {0}; + for EachIndex(idx, node->members.count) + { + E_Member *member = &node->members.v[idx]; + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, member->name); + if(matches.count == matches.needle_part_count) + { + e_member_list_push(scratch.arena, &member_list__filtered, member); + } + } + filter_node->members_filtered = e_member_array_from_list(e_cache->arena, &member_list__filtered); + scratch_end(scratch); + } + members = filter_node->members_filtered; + } + } + return members; +} + internal E_MemberArray e_type_data_members_from_key__cached(E_TypeKey key) { @@ -1916,3 +2140,832 @@ e_type_member_from_key_name__cached(E_TypeKey key, String8 name) } return result; } + +//- rjf: enum val lookups + +internal E_EnumValCacheNode * +e_enum_val_cache_node_from_type_key(E_TypeKey key) +{ + U64 hash = e_hash_from_string(5381, str8_struct(&key)); + U64 slot_idx = hash%e_cache->enum_val_cache_slots_count; + E_EnumValCacheSlot *slot = &e_cache->enum_val_cache_slots[slot_idx]; + E_EnumValCacheNode *node = 0; + for(E_EnumValCacheNode *n = slot->first; n != 0; n = n->next) + { + if(e_type_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + node = push_array(e_cache->arena, E_EnumValCacheNode, 1); + SLLQueuePush(slot->first, slot->last, node); + node->key = key; + E_Type *type = e_type_from_key(key); + if(type->kind == E_TypeKind_Enum) + { + node->val_hash_slots_count = type->count; + node->val_hash_slots = push_array(e_cache->arena, E_EnumValHashSlot, node->val_hash_slots_count); + node->val_filter_slots_count = 16; + node->val_filter_slots = push_array(e_cache->arena, E_EnumValFilterSlot, node->val_filter_slots_count); + for EachIndex(idx, type->count) + { + U64 hash = e_hash_from_string(5381, type->enum_vals[idx].name); + U64 slot_idx = hash%node->val_hash_slots_count; + E_EnumValHashNode *n = push_array(e_cache->arena, E_EnumValHashNode, 1); + SLLQueuePush(node->val_hash_slots[slot_idx].first, node->val_hash_slots[slot_idx].last, n); + n->val_idx = idx; + } + } + } + return node; +} + +internal E_EnumValArray +e_type_enum_vals_from_key_filter__cached(E_TypeKey key, String8 filter) +{ + E_EnumValArray enum_vals = {0}; + E_EnumValCacheNode *node = e_enum_val_cache_node_from_type_key(key); + if(node != 0) + { + if(filter.size == 0) + { + E_Type *type = e_type_from_key(key); + if(type->kind == E_TypeKind_Enum) + { + enum_vals.v = type->enum_vals; + enum_vals.count = type->count; + } + } + else + { + U64 hash = e_hash_from_string(5381, filter); + U64 slot_idx = hash%node->val_filter_slots_count; + E_EnumValFilterSlot *slot = &node->val_filter_slots[slot_idx]; + E_EnumValFilterNode *filter_node = 0; + for(E_EnumValFilterNode *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->filter, filter, 0)) + { + filter_node = n; + break; + } + } + if(filter_node == 0) + { + Temp scratch = scratch_begin(0, 0); + filter_node = push_array(e_cache->arena, E_EnumValFilterNode, 1); + filter_node->filter = push_str8_copy(e_cache->arena, filter); + E_Type *type = e_type_from_key(key); + E_EnumValList enum_val_list__filtered = {0}; + if(type->kind == E_TypeKind_Enum) + { + for EachIndex(idx, type->count) + { + E_EnumVal *enum_val = &type->enum_vals[idx]; + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, enum_val->name); + if(matches.count == matches.needle_part_count) + { + e_enum_val_list_push(scratch.arena, &enum_val_list__filtered, enum_val); + } + } + } + filter_node->vals_filtered = e_enum_val_array_from_list(e_cache->arena, &enum_val_list__filtered); + scratch_end(scratch); + } + enum_vals = filter_node->vals_filtered; + } + } + return enum_vals; +} + +internal E_EnumValArray +e_type_enum_vals_from_key__cached(E_TypeKey key) +{ + E_EnumValArray enum_vals = e_type_enum_vals_from_key_filter__cached(key, str8_zero()); + return enum_vals; +} + +internal E_EnumVal +e_type_enum_val_from_key_name__cached(E_TypeKey key, String8 name) +{ + E_EnumVal result = {0}; + E_EnumValCacheNode *node = e_enum_val_cache_node_from_type_key(key); + if(node != 0 && node->val_hash_slots_count != 0) + { + Temp scratch = scratch_begin(0, 0); + E_Type *type = e_type_from_key(key); + String8 name_qualified_0 = push_str8f(scratch.arena, "%S%S", type->name, name); + String8 name_qualified_1 = push_str8f(scratch.arena, "%S_%S", type->name, name); + U64 hash = e_hash_from_string(5381, name); + U64 slot_idx = hash%node->val_hash_slots_count; + for(E_EnumValHashNode *n = node->val_hash_slots[slot_idx].first; n != 0; n = n->next) + { + if(str8_match(type->enum_vals[n->val_idx].name, name, 0) || + str8_match(type->enum_vals[n->val_idx].name, name_qualified_0, 0) || + str8_match(type->enum_vals[n->val_idx].name, name_qualified_1, 0)) + { + result = type->enum_vals[n->val_idx]; + break; + } + } + scratch_end(scratch); + } + return result; +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) Default Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(default) +{ + E_TypeExpandInfo result = {0}; + { + //- rjf: try to extract a struct-like type key, enum-like, or array-like + // type key, for expansion + E_TypeKey expand_type_key = e_default_expansion_type_from_key(eval.irtree.type_key); + + //- rjf: struct type? -> use the struct type for expansion + B32 did_expansion = 0; + if(!did_expansion) + { + E_TypeKind struct_type_kind = e_type_kind_from_key(expand_type_key); + if(struct_type_kind == E_TypeKind_Struct || + struct_type_kind == E_TypeKind_Class || + struct_type_kind == E_TypeKind_Union) + { + E_MemberArray data_members = e_type_data_members_from_key_filter__cached(expand_type_key, filter); + result.expr_count = data_members.count; + did_expansion = 1; + } + } + + //- rjf: array-like type? -> use the array-like for expansion + if(!did_expansion) + { + E_TypeKind array_type_kind = e_type_kind_from_key(expand_type_key); + if(array_type_kind == E_TypeKind_Array || + array_type_kind == E_TypeKind_Ptr) + { + E_Type *array_type = e_type_from_key(expand_type_key); + result.expr_count = array_type->count; + did_expansion = 1; + } + } + + //- rjf: enum-like type? -> use the enum-like for expansion + if(!did_expansion) + { + E_TypeKind enum_type_kind = e_type_kind_from_key(expand_type_key); + if(enum_type_kind == E_TypeKind_Enum) + { + E_EnumValArray enum_vals = e_type_enum_vals_from_key_filter__cached(expand_type_key, filter); + result.expr_count = enum_vals.count; + did_expansion = 1; + } + } + } + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(default) +{ + Temp scratch = scratch_begin(&arena, 1); + { + //- rjf: try to extract a struct-like type key, enum-like, or array-like + // type key, for expansion + E_TypeKey expand_type_key = e_default_expansion_type_from_key(eval.irtree.type_key); + E_TypeKind expand_type_kind = e_type_kind_from_key(expand_type_key); + + //- rjf: struct case -> the lookup-range will return a range of members + if(expand_type_kind == E_TypeKind_Struct || + expand_type_kind == E_TypeKind_Class || + expand_type_kind == E_TypeKind_Union) + { + E_MemberArray data_members = e_type_data_members_from_key_filter__cached(expand_type_key, filter); + Rng1U64 legal_idx_range = r1u64(0, data_members.count); + Rng1U64 read_range = intersect_1u64(legal_idx_range, idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + U64 member_idx = idx + read_range.min; + String8 member_name = data_members.v[member_idx].name; + evals_out[idx] = e_eval_wrapf(eval, "$.%S", member_name); + } + } + + //- rjf: enum case -> the lookup-range will return a range of enum constants + else if(expand_type_kind == E_TypeKind_Enum) + { + E_Type *type = e_type_from_key(expand_type_key); + E_EnumValArray enum_vals = e_type_enum_vals_from_key_filter__cached(expand_type_key, filter); + Rng1U64 legal_idx_range = r1u64(0, enum_vals.count); + Rng1U64 read_range = intersect_1u64(legal_idx_range, idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + U64 val_idx = idx + read_range.min; + String8 member_name = enum_vals.v[val_idx].name; + String8 sufficient_suffix = member_name; + if(str8_match(sufficient_suffix, type->name, StringMatchFlag_RightSideSloppy)) + { + sufficient_suffix = str8_skip(sufficient_suffix, type->name.size); + if(str8_match(sufficient_suffix, str8_lit("_"), StringMatchFlag_RightSideSloppy)) + { + sufficient_suffix = str8_skip(sufficient_suffix, 1); + } + } + evals_out[idx] = e_eval_wrapf(eval, "$.%S", sufficient_suffix); + } + } + + //- rjf: ptr case -> the lookup-range will return a range of dereferences + else if(expand_type_kind == E_TypeKind_Ptr || + expand_type_kind == E_TypeKind_Array || + expand_type_kind == E_TypeKind_Set) + { + U64 read_range_count = dim_1u64(idx_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", idx_range.min + idx); + } + } + } + scratch_end(scratch); +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(identity) +{ + return num; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity) +{ + return id; +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `rows` lens + +typedef struct E_RowsAccel E_RowsAccel; +struct E_RowsAccel +{ + E_Eval *root_evals; + Rng1U64 *root_evals_ranges; +}; + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(rows) +{ + E_Type *type = e_type_from_key(eval.irtree.type_key); + E_RowsAccel *accel = push_array(arena, E_RowsAccel, 1); + accel->root_evals = push_array(arena, E_Eval, type->count); + accel->root_evals_ranges = push_array(arena, Rng1U64, type->count); + E_ParentKey(eval.key) + { + for EachIndex(idx, type->count) + { + accel->root_evals[idx] = e_eval_from_expr(type->args[idx]); + accel->root_evals_ranges[idx] = r1u64(idx, idx+1); + } + } + E_TypeExpandInfo info = {accel, type->count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(rows) +{ + E_RowsAccel *accel = (E_RowsAccel *)user_data; + U64 out_idx = 0; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + evals_out[out_idx] = accel->root_evals[idx]; + } +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `omit` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(omit) +{ + E_Type *type = e_type_from_key(eval.irtree.type_key); + String8Array allowed_children_array = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + String8List allowed_children = {0}; + { + E_Eval eval_stripped = e_eval_wrapf(eval, "q:raw($)"); + E_TypeExpandRule *expand_rule = e_expand_rule_from_type_key(eval_stripped.irtree.type_key); + E_TypeExpandInfo expand_info = expand_rule->info(scratch.arena, eval_stripped, filter); + if(expand_info.expr_count < 4096) + { + E_Eval *evals = push_array(scratch.arena, E_Eval, expand_info.expr_count); + for EachIndex(idx, expand_info.expr_count) + { + evals[idx] = e_eval_nil; + } + expand_rule->range(scratch.arena, expand_info.user_data, eval_stripped, filter, r1u64(0, expand_info.expr_count), evals); + for EachIndex(idx, expand_info.expr_count) + { + if(evals[idx].expr->kind == E_ExprKind_MemberAccess) + { + String8 name = evals[idx].expr->first->next->string; + B32 name_is_allowed = 1; + for EachIndex(arg_idx, type->count) + { + if(str8_match(type->args[arg_idx]->string, name, 0)) + { + name_is_allowed = 0; + break; + } + } + if(name_is_allowed) + { + str8_list_push(scratch.arena, &allowed_children, push_str8_copy(arena, name)); + } + } + } + } + } + allowed_children_array = str8_array_from_list(arena, &allowed_children); + scratch_end(scratch); + } + String8Array *ext = push_array(arena, String8Array, 1); + *ext = allowed_children_array; + E_TypeExpandInfo info = {ext, ext->count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(omit) +{ + String8Array *ext = (String8Array *)user_data; + U64 out_idx = 0; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + String8 name = ext->v[idx]; + if(name.size != 0) + { + evals_out[out_idx] = e_eval_wrapf(eval, "$.%S", name); + } + } +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `sequence` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(sequence) +{ + E_TypeExpandInfo info = {0, e_value_eval_from_eval(eval).value.u64}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(sequence) +{ + U64 read_range_count = dim_1u64(idx_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + evals_out[idx] = e_eval_from_stringf("%I64u", idx_range.min + idx); + } +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `array` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(array) +{ + E_Type *type = e_type_from_key(eval.irtree.type_key); + U64 count = 1; + if(type->args != 0 && type->count > 0) E_ParentKey(eval.parent_key) + { + E_Key count_key = e_key_from_expr(type->args[0]); + E_Value count_value = e_value_from_key(count_key); + count = count_value.u64; + } + E_TypeExpandInfo info = {0, count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array) +{ + U64 read_range_count = dim_1u64(idx_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", idx_range.min + idx); + } +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `slice` lens + +typedef struct E_SliceIRExt E_SliceIRExt; +struct E_SliceIRExt +{ + E_Member *base_ptr_member; + E_Member *opl_ptr_member; + E_Member *count_member; +}; + +typedef struct E_SliceAccel E_SliceAccel; +struct E_SliceAccel +{ + Arch arch; + U64 count; + U64 base_ptr_vaddr; + E_TypeKey element_type_key; +}; + +E_TYPE_IREXT_FUNCTION_DEF(slice) +{ + E_SliceIRExt *ext = push_array(arena, E_SliceIRExt, 1); + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: build info from struct type + E_TypeKey struct_type_key = e_type_key_unwrap(irtree->type_key, E_TypeUnwrapFlag_All); + E_TypeKind type_kind = e_type_kind_from_key(struct_type_key); + if(type_kind == E_TypeKind_Struct || type_kind == E_TypeKind_Class) + { + // rjf: unpack members + E_MemberArray members = e_type_data_members_from_key__cached(struct_type_key); + + // rjf: choose base pointer & count members + E_Member *base_ptr_member = 0; + E_Member *opl_ptr_member = 0; + E_Member *count_member = 0; + for(U64 idx = 0; idx < members.count; idx += 1) + { + E_Member *member = &members.v[idx]; + E_TypeKey member_type = e_type_key_unwrap(member->type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind member_type_kind = e_type_kind_from_key(member_type); + if(count_member == 0 && e_type_kind_is_integer(member_type_kind)) + { + count_member = member; + } + if(base_ptr_member == 0 && e_type_kind_is_pointer_or_ref(member_type_kind)) + { + base_ptr_member = &members.v[idx]; + } + else if(base_ptr_member != 0 && opl_ptr_member == 0 && e_type_kind_is_pointer_or_ref(member_type_kind)) + { + opl_ptr_member = &members.v[idx]; + } + if(count_member != 0 && base_ptr_member != 0) + { + break; + } + else if(base_ptr_member != 0 && opl_ptr_member != 0) + { + break; + } + } + + // rjf: fill extension + ext->base_ptr_member = base_ptr_member; + ext->opl_ptr_member = opl_ptr_member; + ext->count_member = count_member; + } + scratch_end(scratch); + } + E_IRExt result = {ext}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(slice) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + E_SliceIRExt *ext = (E_SliceIRExt *)lhs_irtree->user_data; + switch(expr->kind) + { + default: + case E_ExprKind_MemberAccess: + { + result = E_TYPE_ACCESS_FUNCTION_NAME(default)(arena, overridden, expr, lhs_irtree); + }break; + case E_ExprKind_ArrayIndex: + if(ext->base_ptr_member != 0) + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: compute ir tree for struct base + E_IRNode *struct_base_tree = &e_irnode_nil; + { + E_OpList lhs_oplist = e_oplist_from_irtree(scratch.arena, lhs_irtree->root); + String8 lhs_bytecode = e_bytecode_from_oplist(arena, &lhs_oplist); + struct_base_tree = e_irtree_bytecode_no_copy(arena, lhs_bytecode); + if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(e_type_key_unwrap(lhs_irtree->type_key, E_TypeUnwrapFlag_AllDecorative)))) + { + struct_base_tree = e_irtree_resolve_to_value(arena, lhs_irtree->mode, lhs_irtree->root, lhs_irtree->type_key); + } + } + + // rjf: compute ir tree for base pointer value calculation + E_IRNode *base_ptr_tree = &e_irnode_nil; + if(struct_base_tree != &e_irnode_nil) + { + base_ptr_tree = struct_base_tree; + if(ext->base_ptr_member->off != 0) + { + base_ptr_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, struct_base_tree, e_irtree_const_u(arena, ext->base_ptr_member->off)); + } + base_ptr_tree = e_irtree_mem_read_type(arena, base_ptr_tree, ext->base_ptr_member->type_key); + } + + // rjf: compute ir tree for adding to the base ptr member + E_IRNode *idxed_base_tree = &e_irnode_nil; + if(base_ptr_tree != &e_irnode_nil) + { + E_IRTreeAndType idx_irtree = e_push_irtree_and_type_from_expr(arena, 0, &e_default_identifier_resolution_rule, 0, 1, expr->first->next); + E_IRNode *idx_root = e_irtree_resolve_to_value(arena, idx_irtree.mode, idx_irtree.root, idx_irtree.type_key); + E_IRNode *off_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, idx_root, e_irtree_const_u(arena, e_type_byte_size_from_key(e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All)))); + idxed_base_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, base_ptr_tree, off_root); + } + + // rjf: form final result + result.root = idxed_base_tree; + result.type_key = e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All); + result.mode = E_Mode_Offset; + + scratch_end(scratch); + }break; + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(slice) +{ + E_SliceIRExt *accel = (E_SliceIRExt *)eval.irtree.user_data; + U64 count = 0; + { + if(accel->count_member != 0) + { + count = e_value_eval_from_eval(e_eval_wrapf(eval, "$.%S", accel->count_member->name)).value.u64; + } + else if(accel->opl_ptr_member != 0 && accel->base_ptr_member != 0) + { + count = e_value_eval_from_eval(e_eval_wrapf(eval, "raw($.%S) - raw($.%S)", accel->opl_ptr_member->name, accel->base_ptr_member->name)).value.u64; + } + } + E_TypeExpandInfo info = {0, count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(slice) +{ + U64 read_range_count = dim_1u64(idx_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", idx_range.min + idx); + } +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `folder` type + +typedef struct E_FolderAccel E_FolderAccel; +struct E_FolderAccel +{ + String8 folder_path; + String8Array folders; + String8Array files; +}; + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(folder) +{ + E_TypeExpandInfo info = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: evaluate lhs file path ID + U64 lhs_string_id = eval.value.u64; + String8 folder_path = e_string_from_id(lhs_string_id); + + //- rjf: compute filter - omit common prefixes (common parent paths) + String8 local_filter = filter; + { + U64 folder_pos_in_filter = str8_find_needle(filter, 0, folder_path, StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive); + if(folder_pos_in_filter < filter.size) + { + local_filter = str8_skip(local_filter, folder_pos_in_filter+folder_path.size); + local_filter = str8_skip_chop_slashes(local_filter); + } + else + { + MemoryZeroStruct(&local_filter); + } + } + + //- rjf: gather & filter files in this folder + String8List folder_paths = {0}; + String8List file_paths = {0}; + { + OS_FileIter *iter = os_file_iter_begin(scratch.arena, folder_path, 0); + for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, iter, &info);) + { + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, local_filter, info.name); + if(matches.count == matches.needle_part_count) + { + if(info.props.flags & FilePropertyFlag_IsFolder) + { + str8_list_push(scratch.arena, &folder_paths, push_str8_copy(arena, info.name)); + } + else + { + str8_list_push(scratch.arena, &file_paths, push_str8_copy(arena, info.name)); + } + } + } + os_file_iter_end(iter); + } + + //- rjf: build accelerator + E_FolderAccel *accel = push_array(arena, E_FolderAccel, 1); + accel->folder_path = push_str8_copy(arena, folder_path); + accel->folders = str8_array_from_list(arena, &folder_paths); + accel->files = str8_array_from_list(arena, &file_paths); + info.user_data = accel; + info.expr_count = accel->folders.count + accel->files.count; + scratch_end(scratch); + } + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(folder) +{ + E_FolderAccel *accel = (E_FolderAccel *)user_data; + U64 out_idx = 0; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + Temp scratch = scratch_begin(&arena, 1); + String8 path_expr_string = {0}; + if(0 <= idx && idx < accel->folders.count) + { + String8 folder_name = accel->folders.v[idx - 0]; + String8 folder_path = push_str8f(scratch.arena, "%S%s%S", accel->folder_path, accel->folder_path.size != 0 ? "/" : "", folder_name); + path_expr_string = push_str8f(arena, "folder:\"%S/\"", escaped_from_raw_str8(scratch.arena, folder_path)); + } + else if(accel->folders.count <= idx && idx < accel->folders.count + accel->files.count) + { + String8 file_name = accel->files.v[idx - accel->folders.count]; + String8 file_path = push_str8f(scratch.arena, "%S%s%S", accel->folder_path, accel->folder_path.size != 0 ? "/" : "", file_name); + path_expr_string = push_str8f(arena, "file:\"%S\"", escaped_from_raw_str8(scratch.arena, file_path)); + } + evals_out[out_idx] = e_eval_from_string(path_expr_string); + scratch_end(scratch); + } +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(folder) +{ + U64 id = 0; + E_FolderAccel *accel = (E_FolderAccel *)user_data; + String8 name = {0}; + if(0 < num && num <= accel->folders.count) + { + name = accel->folders.v[num-1]; + } + else if(accel->folders.count < num && num <= accel->folders.count+accel->files.count) + { + name = accel->files.v[num-accel->folders.count-1]; + } + id = e_hash_from_string(5381, name); + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(folder) +{ + U64 num = 0; + E_FolderAccel *accel = (E_FolderAccel *)user_data; + for(U64 idx = 0; idx < accel->folders.count+accel->files.count; idx += 1) + { + String8 name = {0}; + if(0 <= idx && idx < accel->folders.count) + { + name = accel->folders.v[idx]; + } + else if(accel->folders.count <= idx && idx < accel->folders.count+accel->files.count) + { + name = accel->files.v[idx-accel->folders.count]; + } + U64 hash = e_hash_from_string(5381, name); + if(hash == id) + { + num = idx+1; + break; + } + } + return num; +} + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `file` type + +typedef struct E_FileAccel E_FileAccel; +struct E_FileAccel +{ + String8 file_path; + FileProperties props; + String8Array fields; +}; + +E_TYPE_IREXT_FUNCTION_DEF(file) +{ + E_IRTreeAndType result = *irtree; + E_FileAccel *accel = push_array(arena, E_FileAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: evaluate lhs file path ID + E_OpList lhs_oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 lhs_bytecode = e_bytecode_from_oplist(scratch.arena, &lhs_oplist); + E_Interpretation lhs_interp = e_interpret(lhs_bytecode); + E_Value lhs_value = lhs_interp.value; + U64 lhs_string_id = lhs_value.u64; + + //- rjf: get file path + String8 file_path = e_string_from_id(lhs_string_id); + + //- rjf: build field list + String8List fields = {0}; + str8_list_pushf(arena, &fields, "size"); + str8_list_pushf(arena, &fields, "last_modified_time"); + str8_list_pushf(arena, &fields, "creation_time"); + str8_list_pushf(arena, &fields, "data"); + + //- rjf: fill accel + accel->file_path = push_str8_copy(arena, file_path); + accel->props = os_properties_from_file_path(file_path); + accel->fields = str8_array_from_list(arena, &fields); + + scratch_end(scratch); + } + E_IRExt ext = {accel}; + return ext; +} + +E_TYPE_ACCESS_FUNCTION_DEF(file) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + E_FileAccel *accel = (E_FileAccel *)lhs_irtree->user_data; + if(expr->kind == E_ExprKind_MemberAccess) + { + E_Expr *rhs = expr->first->next; + String8 member_name = rhs->string; + if(str8_match(member_name, str8_lit("size"), 0)) + { + E_Space space = e_space_make(E_SpaceKind_FileSystem); + space.u64_0 = e_id_from_string(accel->file_path); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, accel->props.size)); + result.type_key = e_type_key_basic(E_TypeKind_U64); + result.mode = E_Mode_Value; + } + else if(str8_match(member_name, str8_lit("last_modified_time"), 0)) + { + E_Space space = e_space_make(E_SpaceKind_FileSystem); + space.u64_0 = e_id_from_string(accel->file_path); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, accel->props.modified)); + result.type_key = e_type_key_basic(E_TypeKind_U64); + result.mode = E_Mode_Value; + } + else if(str8_match(member_name, str8_lit("creation_time"), 0)) + { + E_Space space = e_space_make(E_SpaceKind_FileSystem); + space.u64_0 = e_id_from_string(accel->file_path); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, accel->props.created)); + result.type_key = e_type_key_basic(E_TypeKind_U64); + result.mode = E_Mode_Value; + } + else if(str8_match(member_name, str8_lit("data"), 0)) + { + E_Space space = e_space_make(E_SpaceKind_File); + space.u64_0 = e_id_from_string(accel->file_path); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); + result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), accel->props.size, 0); + result.mode = E_Mode_Offset; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(file) +{ + E_FileAccel *accel = (E_FileAccel *)eval.irtree.user_data; + E_TypeExpandInfo info = {accel, accel->fields.count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(file) +{ + E_FileAccel *accel = (E_FileAccel *)user_data; + U64 out_idx = 0; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + E_Expr *expr = &e_expr_nil; + String8 string = {0}; + if(0 <= idx && idx < accel->fields.count) + { + String8 name = accel->fields.v[idx]; + evals_out[out_idx] = e_eval_wrapf(eval, "$.%S", name); + } + } +} diff --git a/src/eval/eval_types.h b/src/eval/eval_types.h index ee4da7ba..1e771975 100644 --- a/src/eval/eval_types.h +++ b/src/eval/eval_types.h @@ -5,250 +5,37 @@ #define EVAL_TYPES_H //////////////////////////////// -//~ rjf: Implicit Type Graph Key Types +//~ rjf: Type Unwrapping -typedef enum E_TypeKeyKind -{ - E_TypeKeyKind_Null, - E_TypeKeyKind_Basic, - E_TypeKeyKind_Ext, - E_TypeKeyKind_Cons, - E_TypeKeyKind_Reg, - E_TypeKeyKind_RegAlias, -} -E_TypeKeyKind; - -typedef struct E_TypeKey E_TypeKey; -struct E_TypeKey -{ - E_TypeKeyKind kind; - U32 u32[3]; - // [0] -> E_TypeKind (Basic, Cons, Ext); Arch (Reg, RegAlias) - // [1] -> Type Index In RDI (Ext); Code (Reg, RegAlias); Type Index In Constructed (Cons) - // [2] -> RDI Index (Ext) -}; - -typedef struct E_TypeKeyNode E_TypeKeyNode; -struct E_TypeKeyNode -{ - E_TypeKeyNode *next; - E_TypeKey v; -}; - -typedef struct E_TypeKeyList E_TypeKeyList; -struct E_TypeKeyList -{ - E_TypeKeyNode *first; - E_TypeKeyNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Full Extracted Type Information Types - -typedef enum E_MemberKind -{ - E_MemberKind_Null, - E_MemberKind_DataField, - E_MemberKind_StaticData, - E_MemberKind_Method, - E_MemberKind_StaticMethod, - E_MemberKind_VirtualMethod, - E_MemberKind_VTablePtr, - E_MemberKind_Base, - E_MemberKind_VirtualBase, - E_MemberKind_NestedType, - E_MemberKind_Padding, - E_MemberKind_COUNT -} -E_MemberKind; - -typedef U32 E_TypeFlags; +typedef U32 E_TypeUnwrapFlags; enum { - E_TypeFlag_Const = (1<<0), - E_TypeFlag_Volatile = (1<<1), - E_TypeFlag_External = (1<<2), - E_TypeFlag_IsPlainText= (1<<3), - E_TypeFlag_IsCodeText = (1<<4), - E_TypeFlag_IsPathText = (1<<5), -}; - -typedef struct E_Member E_Member; -struct E_Member -{ - E_MemberKind kind; - E_TypeKey type_key; - String8 name; - String8 pretty_name; - U64 off; - E_TypeKeyList inheritance_key_chain; -}; - -typedef struct E_MemberNode E_MemberNode; -struct E_MemberNode -{ - E_MemberNode *next; - E_Member v; -}; - -typedef struct E_MemberList E_MemberList; -struct E_MemberList -{ - E_MemberNode *first; - E_MemberNode *last; - U64 count; -}; - -typedef struct E_MemberArray E_MemberArray; -struct E_MemberArray -{ - E_Member *v; - U64 count; -}; - -typedef struct E_EnumVal E_EnumVal; -struct E_EnumVal -{ - String8 name; - U64 val; -}; - -typedef struct E_EnumValArray E_EnumValArray; -struct E_EnumValArray -{ - E_EnumVal *v; - U64 count; -}; - -typedef struct E_Type E_Type; -struct E_Type -{ - E_TypeKind kind; - E_TypeFlags flags; - String8 name; - U64 byte_size; - U64 count; - U32 off; - E_TypeKey direct_type_key; - E_TypeKey owner_type_key; - E_TypeKey *param_type_keys; - E_Member *members; - E_EnumVal *enum_vals; -}; - -//////////////////////////////// -//~ rjf: Evaluation Context - -//- rjf: constructed type cache types - -typedef struct E_ConsTypeParams E_ConsTypeParams; -struct E_ConsTypeParams -{ - Arch arch; - E_TypeKind kind; - E_TypeFlags flags; - String8 name; - E_TypeKey direct_key; - U64 count; - E_Member *members; - E_EnumVal *enum_vals; -}; - -typedef struct E_ConsTypeNode E_ConsTypeNode; -struct E_ConsTypeNode -{ - E_ConsTypeNode *key_next; - E_ConsTypeNode *content_next; - E_TypeKey key; - E_ConsTypeParams params; - U64 byte_size; -}; - -typedef struct E_ConsTypeSlot E_ConsTypeSlot; -struct E_ConsTypeSlot -{ - E_ConsTypeNode *first; - E_ConsTypeNode *last; -}; - -//- rjf: member lookup cache types - -typedef struct E_MemberHashNode E_MemberHashNode; -struct E_MemberHashNode -{ - E_MemberHashNode *next; - U64 member_idx; -}; - -typedef struct E_MemberHashSlot E_MemberHashSlot; -struct E_MemberHashSlot -{ - E_MemberHashNode *first; - E_MemberHashNode *last; -}; - -typedef struct E_MemberCacheNode E_MemberCacheNode; -struct E_MemberCacheNode -{ - E_MemberCacheNode *next; - E_TypeKey key; - E_MemberArray members; - U64 member_hash_slots_count; - E_MemberHashSlot *member_hash_slots; -}; - -typedef struct E_MemberCacheSlot E_MemberCacheSlot; -struct E_MemberCacheSlot -{ - E_MemberCacheNode *first; - E_MemberCacheNode *last; -}; - -//- rjf: context parameterization - -typedef struct E_TypeCtx E_TypeCtx; -struct E_TypeCtx -{ - // rjf: instruction pointer info - U64 ip_vaddr; - U64 ip_voff; // (within `primary_module`) - - // rjf: debug info - E_Module *modules; - U64 modules_count; - E_Module *primary_module; -}; - -//- rjf: stateful machine part of context (not provided by user) - -typedef struct E_TypeState E_TypeState; -struct E_TypeState -{ - Arena *arena; - U64 arena_eval_start_pos; - - // rjf: evaluation context - E_TypeCtx *ctx; - - // rjf: JIT-constructed types tables - U64 cons_id_gen; - U64 cons_content_slots_count; - U64 cons_key_slots_count; - E_ConsTypeSlot *cons_content_slots; - E_ConsTypeSlot *cons_key_slots; - - // rjf: member cache table - U64 member_cache_slots_count; - E_MemberCacheSlot *member_cache_slots; + E_TypeUnwrapFlag_Modifiers = (1<<0), + E_TypeUnwrapFlag_Pointers = (1<<1), + E_TypeUnwrapFlag_Lenses = (1<<2), + E_TypeUnwrapFlag_Meta = (1<<3), + E_TypeUnwrapFlag_Enums = (1<<4), + E_TypeUnwrapFlag_Aliases = (1<<5), + E_TypeUnwrapFlag_All = 0xffffffff, + E_TypeUnwrapFlag_AllDecorative = (E_TypeUnwrapFlag_All & ~E_TypeUnwrapFlag_Pointers) }; //////////////////////////////// //~ rjf: Globals -global read_only E_Member e_member_nil = {E_MemberKind_Null, zero_struct, {0}, {0}, 0, {0}}; +global read_only E_Member e_member_nil = {E_MemberKind_Null}; global read_only E_Type e_type_nil = {E_TypeKind_Null}; -thread_static E_TypeState *e_type_state = 0; +E_TYPE_EXPAND_INFO_FUNCTION_DEF(default); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(default); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(identity); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity); +global read_only E_TypeExpandRule e_type_expand_rule__default = +{ + E_TYPE_EXPAND_INFO_FUNCTION_NAME(default), + E_TYPE_EXPAND_RANGE_FUNCTION_NAME(default), + E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), + E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), +}; //////////////////////////////// //~ rjf: Type Kind Enum Functions @@ -270,10 +57,11 @@ internal void e_member_list_push(Arena *arena, E_MemberList *list, E_Member *mem internal E_MemberArray e_member_array_from_list(Arena *arena, E_MemberList *list); //////////////////////////////// -//~ rjf: Context Selection Functions (Selection Required For All Subsequent APIs) +//~ rjf: Enum Value Functions -internal E_TypeCtx *e_selected_type_ctx(void); -internal void e_select_type_ctx(E_TypeCtx *ctx); +internal void e_enum_val_list_push(Arena *arena, E_EnumValList *list, E_EnumVal *enum_val); +#define e_enum_val_list_push_new(arena, list, ...) e_enum_val_list_push((arena), (list), &(E_EnumVal){.val = 0, __VA_ARGS__}) +internal E_EnumValArray e_enum_val_array_from_list(Arena *arena, E_EnumValList *list); //////////////////////////////// //~ rjf: Type Operation Functions @@ -292,42 +80,113 @@ internal E_TypeKey e_type_key_cons_(E_ConsTypeParams *params); #define e_type_key_cons(...) e_type_key_cons_(&(E_ConsTypeParams){.kind = E_TypeKind_Null, __VA_ARGS__}) //- rjf: constructed type construction helpers -internal E_TypeKey e_type_key_cons_array(E_TypeKey element_type_key, U64 count); -internal E_TypeKey e_type_key_cons_ptr(Arch arch, E_TypeKey element_type_key, E_TypeFlags flags); +internal E_TypeKey e_type_key_cons_array(E_TypeKey element_type_key, U64 count, E_TypeFlags flags); +internal E_TypeKey e_type_key_cons_ptr(Arch arch, E_TypeKey element_type_key, U64 count, E_TypeFlags flags); +internal E_TypeKey e_type_key_cons_meta_expr(E_TypeKey type_key, String8 expr); +internal E_TypeKey e_type_key_cons_meta_display_name(E_TypeKey type_key, String8 name); +internal E_TypeKey e_type_key_cons_meta_description(E_TypeKey type_key, String8 desc); internal E_TypeKey e_type_key_cons_base(Type *type); +internal E_TypeKey e_type_key_file(void); +internal E_TypeKey e_type_key_folder(void); //- rjf: basic type key functions internal B32 e_type_key_match(E_TypeKey l, E_TypeKey r); -//- rjf: key -> info extraction -internal U64 e_hash_from_type_key(E_TypeKey key); +//- rjf: type key -> info extraction +internal U64 e_hash_from_type(E_Type *type); internal E_TypeKind e_type_kind_from_key(E_TypeKey key); internal U64 e_type_byte_size_from_key(E_TypeKey key); -internal E_Type *e_type_from_key(Arena *arena, E_TypeKey key); -internal E_TypeKey e_type_direct_from_key(E_TypeKey key); -internal E_TypeKey e_type_owner_from_key(E_TypeKey key); -internal E_TypeKey e_type_ptee_from_key(E_TypeKey key); -internal E_TypeKey e_type_unwrap_enum(E_TypeKey key); -internal E_TypeKey e_type_unwrap(E_TypeKey key); -internal E_TypeKey e_type_promote(E_TypeKey key); -internal B32 e_type_match(E_TypeKey l, E_TypeKey r); -internal E_Member *e_type_member_copy(Arena *arena, E_Member *src); +internal E_Type *e_push_type_from_key(Arena *arena, E_TypeKey key); internal int e_type_qsort_compare_members_offset(E_Member *a, E_Member *b); internal E_MemberArray e_type_data_members_from_key(Arena *arena, E_TypeKey key); -internal E_Member *e_type_member_from_array_name(E_MemberArray *members, String8 name); +internal E_TypeExpandRule *e_expand_rule_from_type_key(E_TypeKey key); + +//- rjf: type key traversal +internal E_TypeKey e_type_key_direct(E_TypeKey key); +internal E_TypeKey e_type_key_owner(E_TypeKey key); +internal E_TypeKey e_type_key_promote(E_TypeKey key); +internal E_TypeKey e_type_key_unwrap(E_TypeKey key, E_TypeUnwrapFlags flags); + +//- rjf: type comparisons +internal B32 e_type_match(E_TypeKey l, E_TypeKey r); + +//- rjf: type key -> string internal void e_type_lhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 prec, B32 skip_return); internal void e_type_rhs_string_from_key(Arena *arena, E_TypeKey key, String8List *out, U32 prec); internal String8 e_type_string_from_key(Arena *arena, E_TypeKey key); - -//- rjf: type key data structures -internal void e_type_key_list_push(Arena *arena, E_TypeKeyList *list, E_TypeKey key); -internal E_TypeKeyList e_type_key_list_copy(Arena *arena, E_TypeKeyList *src); +internal E_TypeKey e_default_expansion_type_from_key(E_TypeKey key); //////////////////////////////// //~ rjf: Cache Lookups +internal E_Type *e_type_from_key(E_TypeKey key); + +//- rjf: member lookups internal E_MemberCacheNode *e_member_cache_node_from_type_key(E_TypeKey key); +internal E_MemberArray e_type_data_members_from_key_filter__cached(E_TypeKey key, String8 filter); internal E_MemberArray e_type_data_members_from_key__cached(E_TypeKey key); internal E_Member e_type_member_from_key_name__cached(E_TypeKey key, String8 name); +//- rjf: enum val lookups +internal E_EnumValCacheNode *e_enum_val_cache_node_from_type_key(E_TypeKey key); +internal E_EnumValArray e_type_enum_vals_from_key_filter__cached(E_TypeKey key, String8 filter); +internal E_EnumValArray e_type_enum_vals_from_key__cached(E_TypeKey key); +internal E_EnumVal e_type_enum_val_from_key_name__cached(E_TypeKey key, String8 name); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) Default Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(default); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(default); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(identity); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `rows` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(rows); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(rows); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `sequence` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(sequence); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(sequence); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `array` lens + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(array); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `slice` lens + +E_TYPE_IREXT_FUNCTION_DEF(slice); +E_TYPE_ACCESS_FUNCTION_DEF(slice); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(slice); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(slice); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `only`, `omit` lenses + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(only_and_omit); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(only_and_omit); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `folder` type + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(folder); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(folder); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(folder); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(folder); + +//////////////////////////////// +//~ rjf: (Built-In Type Hooks) `file` type + +E_TYPE_IREXT_FUNCTION_DEF(file); +E_TYPE_ACCESS_FUNCTION_DEF(file); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(file); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(file); + #endif // EVAL_TYPES_H diff --git a/src/eval/generated/eval.meta.c b/src/eval/generated/eval.meta.c index 35b65640..a1305840 100644 --- a/src/eval/generated/eval.meta.c +++ b/src/eval/generated/eval.meta.c @@ -14,126 +14,72 @@ str8_lit_comp("CharLiteral"), str8_lit_comp("Symbol"), }; -String8 e_expr_kind_strings[48] = -{ -str8_lit_comp("Nil"), -str8_lit_comp("Ref"), -str8_lit_comp("ArrayIndex"), -str8_lit_comp("MemberAccess"), -str8_lit_comp("Deref"), -str8_lit_comp("Address"), -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"), -str8_lit_comp("Mul"), -str8_lit_comp("Div"), -str8_lit_comp("Mod"), -str8_lit_comp("Add"), -str8_lit_comp("Sub"), -str8_lit_comp("LShift"), -str8_lit_comp("RShift"), -str8_lit_comp("Less"), -str8_lit_comp("LsEq"), -str8_lit_comp("Grtr"), -str8_lit_comp("GrEq"), -str8_lit_comp("EqEq"), -str8_lit_comp("NtEq"), -str8_lit_comp("BitAnd"), -str8_lit_comp("BitXor"), -str8_lit_comp("BitOr"), -str8_lit_comp("LogAnd"), -str8_lit_comp("LogOr"), -str8_lit_comp("Ternary"), -str8_lit_comp("LeafBytecode"), -str8_lit_comp("LeafMember"), -str8_lit_comp("LeafStringLiteral"), -str8_lit_comp("LeafBool"), -str8_lit_comp("LeafU64"), -str8_lit_comp("LeafF64"), -str8_lit_comp("LeafF32"), -str8_lit_comp("LeafIdent"), -str8_lit_comp("LeafOffset"), -str8_lit_comp("LeafFilePath"), -str8_lit_comp("TypeIdent"), -str8_lit_comp("Ptr"), -str8_lit_comp("Array"), -str8_lit_comp("Func"), -str8_lit_comp("Define"), -}; - -String8 e_interpretation_code_display_strings[11] = +String8 e_type_kind_basic_string_table[61] = { str8_lit_comp(""), -str8_lit_comp("Cannot divide by zero."), -str8_lit_comp("Invalid operation."), -str8_lit_comp("Invalid operation types."), -str8_lit_comp("Failed memory read."), -str8_lit_comp("Failed register read."), -str8_lit_comp("Invalid frame base address."), -str8_lit_comp("Invalid module base address."), -str8_lit_comp("Invalid thread-local storage base address."), -str8_lit_comp("Insufficient evaluation machine stack space."), -str8_lit_comp("Malformed bytecode."), +str8_lit_comp("void"), +str8_lit_comp("HANDLE"), +str8_lit_comp("HRESULT"), +str8_lit_comp("char8"), +str8_lit_comp("char16"), +str8_lit_comp("char32"), +str8_lit_comp("uchar8"), +str8_lit_comp("uchar16"), +str8_lit_comp("uchar32"), +str8_lit_comp("uint8"), +str8_lit_comp("uint16"), +str8_lit_comp("uint32"), +str8_lit_comp("uint64"), +str8_lit_comp("uint128"), +str8_lit_comp("uint256"), +str8_lit_comp("uint512"), +str8_lit_comp("int8"), +str8_lit_comp("int16"), +str8_lit_comp("int32"), +str8_lit_comp("int64"), +str8_lit_comp("int128"), +str8_lit_comp("int256"), +str8_lit_comp("int512"), +str8_lit_comp("bool"), +str8_lit_comp("float16"), +str8_lit_comp("float32"), +str8_lit_comp("float32PP"), +str8_lit_comp("float48"), +str8_lit_comp("float64"), +str8_lit_comp("float80"), +str8_lit_comp("float128"), +str8_lit_comp("complex_float32"), +str8_lit_comp("complex_float64"), +str8_lit_comp("complex_float80"), +str8_lit_comp("complex_float128"), +str8_lit_comp("modifier"), +str8_lit_comp("ptr"), +str8_lit_comp("lref"), +str8_lit_comp("rref"), +str8_lit_comp("array"), +str8_lit_comp("function"), +str8_lit_comp("method"), +str8_lit_comp("member_ptr"), +str8_lit_comp("struct"), +str8_lit_comp("class"), +str8_lit_comp("union"), +str8_lit_comp("enum"), +str8_lit_comp("typedef"), +str8_lit_comp("struct"), +str8_lit_comp("union"), +str8_lit_comp("class"), +str8_lit_comp("enum"), +str8_lit_comp("bitfield"), +str8_lit_comp("variadic"), +str8_lit_comp("set"), +str8_lit_comp("lens"), +str8_lit_comp("lens_spec"), +str8_lit_comp("meta_expr"), +str8_lit_comp("meta_display_name"), +str8_lit_comp("meta_description"), }; -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("") }, -{ 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("") }, -{ 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_Null, 1, str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp("") }, -{ 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("") }, -{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("*"), str8_lit_comp("") }, -{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("/"), str8_lit_comp("") }, -{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp("%"), str8_lit_comp("") }, -{ E_OpKind_Binary, 4, str8_lit_comp(""), str8_lit_comp("+"), str8_lit_comp("") }, -{ E_OpKind_Binary, 4, str8_lit_comp(""), str8_lit_comp("-"), str8_lit_comp("") }, -{ E_OpKind_Binary, 5, str8_lit_comp(""), str8_lit_comp("<<"), str8_lit_comp("") }, -{ E_OpKind_Binary, 5, str8_lit_comp(""), str8_lit_comp(">>"), str8_lit_comp("") }, -{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp("<"), str8_lit_comp("") }, -{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp("<="), str8_lit_comp("") }, -{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(">"), str8_lit_comp("") }, -{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(">="), str8_lit_comp("") }, -{ E_OpKind_Binary, 7, str8_lit_comp(""), str8_lit_comp("=="), str8_lit_comp("") }, -{ E_OpKind_Binary, 7, str8_lit_comp(""), str8_lit_comp("!="), str8_lit_comp("") }, -{ E_OpKind_Binary, 8, str8_lit_comp(""), str8_lit_comp("&"), str8_lit_comp("") }, -{ E_OpKind_Binary, 9, str8_lit_comp(""), str8_lit_comp("^"), str8_lit_comp("") }, -{ E_OpKind_Binary, 10, str8_lit_comp(""), str8_lit_comp("|"), str8_lit_comp("") }, -{ E_OpKind_Binary, 11, str8_lit_comp(""), str8_lit_comp("&&"), str8_lit_comp("") }, -{ E_OpKind_Binary, 12, str8_lit_comp(""), str8_lit_comp("||"), str8_lit_comp("") }, -{ 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("") }, -{ 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("") }, -{ 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("") }, -{ 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("") }, -{ 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("") }, -{ 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("") }, -{ 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("") }, -{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, -{ E_OpKind_Binary, 13, str8_lit_comp(""), str8_lit_comp("="), str8_lit_comp("") }, -}; - -U8 e_kind_basic_byte_size_table[56] = +U8 e_type_kind_basic_byte_size_table[61] = { 0, 0, @@ -191,66 +137,132 @@ U8 e_kind_basic_byte_size_table[56] = 0, 0, 0, +0, +0, +0, +0, +0, }; -String8 e_kind_basic_string_table[56] = +String8 e_expr_kind_strings[49] = +{ +str8_lit_comp("Nil"), +str8_lit_comp("Ref"), +str8_lit_comp("ArrayIndex"), +str8_lit_comp("MemberAccess"), +str8_lit_comp("Deref"), +str8_lit_comp("Address"), +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"), +str8_lit_comp("Mul"), +str8_lit_comp("Div"), +str8_lit_comp("Mod"), +str8_lit_comp("Add"), +str8_lit_comp("Sub"), +str8_lit_comp("LShift"), +str8_lit_comp("RShift"), +str8_lit_comp("Less"), +str8_lit_comp("LsEq"), +str8_lit_comp("Grtr"), +str8_lit_comp("GrEq"), +str8_lit_comp("EqEq"), +str8_lit_comp("NtEq"), +str8_lit_comp("BitAnd"), +str8_lit_comp("BitXor"), +str8_lit_comp("BitOr"), +str8_lit_comp("LogAnd"), +str8_lit_comp("LogOr"), +str8_lit_comp("Ternary"), +str8_lit_comp("Call"), +str8_lit_comp("LeafBytecode"), +str8_lit_comp("LeafStringLiteral"), +str8_lit_comp("LeafU64"), +str8_lit_comp("LeafF64"), +str8_lit_comp("LeafF32"), +str8_lit_comp("LeafIdentifier"), +str8_lit_comp("LeafOffset"), +str8_lit_comp("LeafValue"), +str8_lit_comp("LeafFilePath"), +str8_lit_comp("TypeIdent"), +str8_lit_comp("Ptr"), +str8_lit_comp("Array"), +str8_lit_comp("Func"), +str8_lit_comp("Unsigned"), +str8_lit_comp("Define"), +}; + +E_OpInfo e_expr_kind_op_info_table[49] = +{ +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp("["), str8_lit_comp("]"), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp("."), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("*"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("&"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 1, str8_lit_comp("cast("), str8_lit_comp(")"), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("sizeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("typeof "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 1, str8_lit_comp("bswap "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("+"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("-"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("!"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_UnaryPrefix, 2, str8_lit_comp("~"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp(" * "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp(" / "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 3, str8_lit_comp(""), str8_lit_comp(" % "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 4, str8_lit_comp(""), str8_lit_comp(" + "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 4, str8_lit_comp(""), str8_lit_comp(" - "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 5, str8_lit_comp(""), str8_lit_comp(" << "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 5, str8_lit_comp(""), str8_lit_comp(" >> "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(" < "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(" <= "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(" > "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 6, str8_lit_comp(""), str8_lit_comp(" >= "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 7, str8_lit_comp(""), str8_lit_comp(" == "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 7, str8_lit_comp(""), str8_lit_comp(" != "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 8, str8_lit_comp(""), str8_lit_comp(" & "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 9, str8_lit_comp(""), str8_lit_comp(" ^ "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 10, str8_lit_comp(""), str8_lit_comp(" | "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 11, str8_lit_comp(""), str8_lit_comp(" && "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 12, str8_lit_comp(""), str8_lit_comp(" || "), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(" ? "), str8_lit_comp(""), str8_lit_comp(" : ") }, +{ E_OpKind_Null, 15, str8_lit_comp(""), str8_lit_comp("("), str8_lit_comp(")"), str8_lit_comp(", ") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Null, 0, str8_lit_comp("unsigned "), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("") }, +{ E_OpKind_Binary, 13, str8_lit_comp(""), str8_lit_comp(" = "), str8_lit_comp(""), str8_lit_comp("") }, +}; + +String8 e_interpretation_code_display_strings[11] = { str8_lit_comp(""), -str8_lit_comp("void"), -str8_lit_comp("HANDLE"), -str8_lit_comp("HRESULT"), -str8_lit_comp("char8"), -str8_lit_comp("char16"), -str8_lit_comp("char32"), -str8_lit_comp("uchar8"), -str8_lit_comp("uchar16"), -str8_lit_comp("uchar32"), -str8_lit_comp("U8"), -str8_lit_comp("U16"), -str8_lit_comp("U32"), -str8_lit_comp("U64"), -str8_lit_comp("U128"), -str8_lit_comp("U256"), -str8_lit_comp("U512"), -str8_lit_comp("S8"), -str8_lit_comp("S16"), -str8_lit_comp("S32"), -str8_lit_comp("S64"), -str8_lit_comp("S128"), -str8_lit_comp("S256"), -str8_lit_comp("S512"), -str8_lit_comp("bool"), -str8_lit_comp("F16"), -str8_lit_comp("F32"), -str8_lit_comp("F32PP"), -str8_lit_comp("F48"), -str8_lit_comp("F64"), -str8_lit_comp("F80"), -str8_lit_comp("F128"), -str8_lit_comp("ComplexF32"), -str8_lit_comp("ComplexF64"), -str8_lit_comp("ComplexF80"), -str8_lit_comp("ComplexF128"), -str8_lit_comp("modifier"), -str8_lit_comp("ptr"), -str8_lit_comp("lref"), -str8_lit_comp("rref"), -str8_lit_comp("array"), -str8_lit_comp("function"), -str8_lit_comp("method"), -str8_lit_comp("member_ptr"), -str8_lit_comp("struct"), -str8_lit_comp("class"), -str8_lit_comp("union"), -str8_lit_comp("enum"), -str8_lit_comp("typedef"), -str8_lit_comp("struct"), -str8_lit_comp("union"), -str8_lit_comp("class"), -str8_lit_comp("enum"), -str8_lit_comp("bitfield"), -str8_lit_comp("variadic"), -str8_lit_comp("collection"), +str8_lit_comp("Cannot divide by zero."), +str8_lit_comp("Invalid operation."), +str8_lit_comp("Invalid operation types."), +str8_lit_comp("Failed memory read."), +str8_lit_comp("Failed register read."), +str8_lit_comp("Invalid frame base address."), +str8_lit_comp("Invalid module base address."), +str8_lit_comp("Invalid thread-local storage base address."), +str8_lit_comp("Insufficient evaluation machine stack space."), +str8_lit_comp("Malformed bytecode."), }; C_LINKAGE_END diff --git a/src/eval/generated/eval.meta.h b/src/eval/generated/eval.meta.h index 2a6200ba..e85f1b0f 100644 --- a/src/eval/generated/eval.meta.h +++ b/src/eval/generated/eval.meta.h @@ -74,7 +74,12 @@ E_TypeKind_IncompleteClass, E_TypeKind_IncompleteEnum, E_TypeKind_Bitfield, E_TypeKind_Variadic, -E_TypeKind_Collection, +E_TypeKind_Set, +E_TypeKind_Lens, +E_TypeKind_LensSpec, +E_TypeKind_MetaExpr, +E_TypeKind_MetaDisplayName, +E_TypeKind_MetaDescription, E_TypeKind_COUNT, E_TypeKind_FirstBasic = E_TypeKind_Void, E_TypeKind_LastBasic = E_TypeKind_ComplexF128, @@ -86,6 +91,8 @@ E_TypeKind_FirstSigned2 = E_TypeKind_S8, E_TypeKind_LastSigned2 = E_TypeKind_S512, E_TypeKind_FirstIncomplete = E_TypeKind_IncompleteStruct, E_TypeKind_LastIncomplete = E_TypeKind_IncompleteEnum, +E_TypeKind_FirstMeta = E_TypeKind_MetaExpr, +E_TypeKind_LastMeta = E_TypeKind_MetaDescription, } E_TypeKind; typedef U32 E_ExprKind; @@ -124,20 +131,21 @@ E_ExprKind_BitOr, E_ExprKind_LogAnd, E_ExprKind_LogOr, E_ExprKind_Ternary, +E_ExprKind_Call, E_ExprKind_LeafBytecode, -E_ExprKind_LeafMember, E_ExprKind_LeafStringLiteral, -E_ExprKind_LeafBool, E_ExprKind_LeafU64, E_ExprKind_LeafF64, E_ExprKind_LeafF32, -E_ExprKind_LeafIdent, +E_ExprKind_LeafIdentifier, E_ExprKind_LeafOffset, +E_ExprKind_LeafValue, E_ExprKind_LeafFilePath, E_ExprKind_TypeIdent, E_ExprKind_Ptr, E_ExprKind_Array, E_ExprKind_Func, +E_ExprKind_Unsigned, E_ExprKind_Define, E_ExprKind_COUNT, } E_ExprKindEnum; @@ -160,11 +168,11 @@ E_InterpretationCode_COUNT, C_LINKAGE_BEGIN extern String8 e_token_kind_strings[6]; -extern String8 e_expr_kind_strings[48]; +extern String8 e_type_kind_basic_string_table[61]; +extern U8 e_type_kind_basic_byte_size_table[61]; +extern String8 e_expr_kind_strings[49]; +extern E_OpInfo e_expr_kind_op_info_table[49]; extern String8 e_interpretation_code_display_strings[11]; -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]; C_LINKAGE_END diff --git a/src/eval_visualization/eval_visualization.mdesk b/src/eval_visualization/eval_visualization.mdesk deleted file mode 100644 index 3fa5a06a..00000000 --- a/src/eval_visualization/eval_visualization.mdesk +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Built-In View Rules -// -// @view_rule_info -// -// NOTE(rjf): View rules are subtle in that they may impact any subset of the -// eval visualization pipeline. The "array" view rule, for example, functions -// by tweaking the type of an eval from `X *` to `X (*)[N]` (where N is -// computed from whatever expression is specified by the view rule). The "list" -// view rule, on the other hand, does not require any changes to the actual -// eval nor its type - instead, it follows an alternative path in constructing -// "viz blocks", and then constructing "viz rows" from those blocks. Compare -// these to the simpler 'dec', 'bin', or 'oct' rules, which simply tweak the -// radix used when stringizing numbers, which is something that only occurs in -// single-line eval stringization building. -// -// As such, each view rule specification has a mask, which determines which -// stages it may be used for. For a given view rule specification, if the bit -// corresponding to a particular eval stage is set, then that view rule spec- -// -ification also includes a hook which can be called from that stage. -// -// Below is a list of the stages in the eval visualization pipeline, as well as -// abbreviations which are used in the tables. -// -// expr resolution, "xp" -> provides a chance for a view rule to make -// modifications to expression trees that it is -// applied to -// -// viz block prod, "vb" -> given a resolved eval, produce a list of non- -// windowed "viz blocks", which correspond to one or -// many contiguous rows in a watch-window-style UI. -// one level of expanded struct members, with no sub- -// expansions, would be one viz block. if one of those -// members - in the middle - were expanded too, then -// it would require three viz blocks - one for the -// members before the sub-expansion, one for the -// sub expansion members, and one for the members -// after, and so on. this is done recursively. -// -// viz row prod, "vr" -> given a list of viz blocks, a windowed list of viz -// rows may be produced. each of these rows has info -// for building actual UI in e.g. a watch window - -// whether or not the row can be expanded, whether or -// not the row's value can be edited, what the edit- -// able string is for a row, what the display string -// is for a row, what the expression string is for a -// row, what the type is for a row, and so on. -// -// line stringize, "ls" -> this is the stage used to produce display strings -// in the "viz row prod" stage, as well as basically -// any time UI needs to display the result of an eval -// in a single line. this also occurs recursively, -// descending into members & elements as needed, -// constrained by # of available pixels and font size -// and so on. -// -// row ui build, "ru" -> finally, after the previous stages are completed, -// ui can finally be built according to all of the -// per-row information produced. this is the stage -// where view rules can insert their own arbitrary ui -// on a per-row basis. -// -// view ui build, "vu" -> view rules which want to supply more sophisticated -// visualizers have the ability to provide full -// arbitrary UI hooks, which can either be produced -// in a minified form via watch views, or via a -// standalone tab. -// -// A few other bits are included for various ways in which a view rule may be -// applied throughout the eval visualization pipeline. A list follows: -// -// inherited, "ih" -> is this view rule included, or not included, in -// child expansions? -// -// expandable, "ex" -> does this view rule force the ability to expand -// an expression, even if traditional analysis of type -// info would not allow expansion? -// -// Not all of these stages are specified at this layer, however, since the -// "df_core" layer is for the non-graphical core debugger features. So the -// information pertaining to the eval visualization pipeline stages which -// do require graphical subsystems (e.g. UI, fonts, rendering) are specified -// in the "df_gfx" layer. -// -// For any view rules in this layer which also have graphical features, they -// are specified in both tables under the same name. - -@table(coverage_check name name_lower string ih ex xr xe display_name docs schema description) -EV_ViewRuleTable: -{ - {x Default default "default" - - - x "Default" - "" "" } - {x Array array "array" - - x - "Array" x "x:{expr}" "Specifies that a pointer points to N elements, rather than only 1." } - {x List list "list" - - - x "Array" x "x:{expr}" "Specifies that a pointer points to N elements, rather than only 1." } - {x Slice slice "slice" - - x - "Slice" x "" "Specifies that a pointer within a struct, also containing an integer, points to the number of elements encoded by the integer." } - {x ByteSwap bswap "bswap" x - x - "Byte Swap" x "" "Specifies that all integral evaluations should be byte-swapped, such that their endianness is reversed." } - {x Cast cast "cast" - - x - "Cast" x "x:{type}" "Specifies that the expression to which the view rule is applied should be casted to the provided type." } - {x Wrap wrap "wrap" - - x - "Wrap" x "x:{expr}" "Specifies that the expression should be wrapped with the view-rule-specified expression, which will refer to the original expression as `$expr`." } - {x Only only "only" x - x - "Only" x "" "Specifies that only the provided member names should be shown in user-defined-type expansions." } - {x Omit omit "omit" x - x - "Omit" x "" "Specifies that the provided member names should not be shown in user-defined-type expansions." } - {x Bin bin "bin" x - - - "Display In Binary" x "" "Specifies that all numeric values should be shown in base 2 (binary)." } - {x Oct oct "oct" x - - - "Display In Octal" x "" "Specifies that all numeric values should be shown in base 8 (octal)." } - {x Dec dec "dec" x - - - "Display In Decimal" x "" "Specifies that all numeric values should be shown in base 10 (decimal)." } - {x Hex hex "hex" x - - - "Display In Hexadecimal" x "" "Specifies that all numeric values should be shown in base 16 (hexadecimal)." } - {x NoAddress no_addr "no_addr" x - - - "Omit Addresses" x "" "Specifies that addresses should be omitted from visualizations, if possible." } -} - -@enum EV_ViewRuleKind: -{ - @expand(EV_ViewRuleTable a) `$(a.name)`, - COUNT, -} - -@gen -{ - @expand(EV_ViewRuleTable a) `$(a.xr == "x" -> "EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(" .. a.name_lower .. ");")`; - @expand(EV_ViewRuleTable a) `$(a.xe == "x" -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(" .. a.name_lower .. ");")`; - @expand(EV_ViewRuleTable a) `$(a.xe == "x" -> "EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(" .. a.name_lower .. ");")`; -} - -@data(EV_ViewRuleInfo) @c_file ev_builtin_view_rule_info_table: -{ - @expand(EV_ViewRuleTable a) - ```{str8_lit_comp("$(a.string)"), (EV_ViewRuleInfoFlag_Inherited*$(a.ih == "x"))|(EV_ViewRuleInfoFlag_Expandable*$(a.ex == "x")), $(a.xr == "x" -> "EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.xr != "x" -> "EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity)"), $(a.xe == "x" -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME("..a.name_lower..")") $(a.xe != "x" -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil)"), $(a.xe == "x" -> "EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME("..a.name_lower..")") $(a.xe != "x" -> "EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil)"), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }```; -} diff --git a/src/eval_visualization/eval_visualization_builtin_view_rules.c b/src/eval_visualization/eval_visualization_builtin_view_rules.c deleted file mode 100644 index ab4628dd..00000000 --- a/src/eval_visualization/eval_visualization_builtin_view_rules.c +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: View Rule Tree Info Extraction Helpers - -internal U64 -ev_base_offset_from_eval(E_Eval eval) -{ - if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(eval.type_key))) - { - eval = e_value_eval_from_eval(eval); - } - return eval.value.u64; -} - -internal E_Value -ev_value_from_params(MD_Node *params) -{ - Temp scratch = scratch_begin(0, 0); - String8 expr = md_string_from_children(scratch.arena, params); - E_Eval eval = e_eval_from_string(scratch.arena, expr); - E_Eval value_eval = e_value_eval_from_eval(eval); - scratch_end(scratch); - return value_eval.value; -} - -internal E_TypeKey -ev_type_key_from_params(MD_Node *params) -{ - Temp scratch = scratch_begin(0, 0); - String8 expr = md_string_from_children(scratch.arena, params); - E_TokenArray tokens = e_token_array_from_text(scratch.arena, expr); - E_Parse parse = e_parse_type_from_text_tokens(scratch.arena, expr, &tokens); - E_TypeKey type_key = e_type_from_expr(parse.expr); - scratch_end(scratch); - return type_key; -} - -internal E_Value -ev_value_from_params_key(MD_Node *params, String8 key) -{ - Temp scratch = scratch_begin(0, 0); - MD_Node *key_node = md_child_from_string(params, key, 0); - String8 expr = md_string_from_children(scratch.arena, key_node); - E_Eval eval = e_eval_from_string(scratch.arena, expr); - E_Eval value_eval = e_value_eval_from_eval(eval); - scratch_end(scratch); - return value_eval.value; -} - -internal Rng1U64 -ev_range_from_eval_params(E_Eval eval, MD_Node *params) -{ - Temp scratch = scratch_begin(0, 0); - U64 size = ev_value_from_params_key(params, str8_lit("size")).u64; - E_TypeKey type_key = e_type_unwrap(eval.type_key); - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_unwrap(e_type_direct_from_key(eval.type_key)); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - if(size == 0 && e_type_kind_is_pointer_or_ref(type_kind) && (direct_type_kind == E_TypeKind_Struct || - direct_type_kind == E_TypeKind_Union || - direct_type_kind == E_TypeKind_Class || - direct_type_kind == E_TypeKind_Array)) - { - size = e_type_byte_size_from_key(e_type_direct_from_key(e_type_unwrap(eval.type_key))); - } - if(size == 0 && eval.mode == E_Mode_Offset && (type_kind == E_TypeKind_Struct || - type_kind == E_TypeKind_Union || - type_kind == E_TypeKind_Class || - type_kind == E_TypeKind_Array)) - { - size = e_type_byte_size_from_key(e_type_unwrap(eval.type_key)); - } - if(size == 0) - { - size = 16384; - } - Rng1U64 result = {0}; - result.min = ev_base_offset_from_eval(eval); - result.max = result.min + size; - scratch_end(scratch); - return result; -} - -internal Arch -ev_arch_from_eval_params(E_Eval eval, MD_Node *params) -{ - Arch arch = Arch_Null; - MD_Node *arch_node = md_child_from_string(params, str8_lit("arch"), 0); - String8 arch_kind_string = arch_node->first->string; - if(str8_match(arch_kind_string, str8_lit("x64"), StringMatchFlag_CaseInsensitive)) - { - arch = Arch_x64; - } - return arch; -} - -//////////////////////////////// -//~ rjf: default - -typedef struct EV_DefaultExpandAccel EV_DefaultExpandAccel; -struct EV_DefaultExpandAccel -{ - E_MemberArray members; - E_EnumValArray enum_vals; - U64 array_count; - B32 array_need_extra_deref; - B32 is_ptr2ptr; -}; - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(default) -{ - Temp scratch = scratch_begin(&arena, 1); - U64 total_row_count = 0; - EV_DefaultExpandAccel *accel = push_array(arena, EV_DefaultExpandAccel, 1); - - //////////////////////////// - //- rjf: unpack expression type info - // - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - E_TypeKey type_key = e_type_unwrap(irtree.type_key); - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_unwrap(e_type_direct_from_key(type_key)); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - - //////////////////////////// - //- rjf: structs/unions/classes -> expansions generate rows for all members - // - if((type_kind == E_TypeKind_Struct || - type_kind == E_TypeKind_Union || - type_kind == E_TypeKind_Class) || - (e_type_kind_is_pointer_or_ref(type_kind) && (direct_type_kind == E_TypeKind_Struct || - direct_type_kind == E_TypeKind_Union || - direct_type_kind == E_TypeKind_Class))) - { - E_TypeKey struct_type_key = e_type_kind_is_pointer_or_ref(type_kind) ? direct_type_key : type_key; - accel->members = e_type_data_members_from_key__cached(struct_type_key); - total_row_count = accel->members.count; - } - - //////////////////////////// - //- rjf: enums -> expansions generate rows for all members - // - else if(type_kind == E_TypeKind_Enum || - (e_type_kind_is_pointer_or_ref(type_kind) && direct_type_kind == E_TypeKind_Enum)) - { - E_Type *type = e_type_from_key(arena, e_type_kind_is_pointer_or_ref(type_kind) ? direct_type_key : type_key); - accel->enum_vals.v = type->enum_vals; - accel->enum_vals.count = type->count; - total_row_count = accel->enum_vals.count; - } - - //////////////////////////// - //- rjf: arrays -> expansions generate rows for all elements - // - else if(type_kind == E_TypeKind_Array || - (e_type_kind_is_pointer_or_ref(type_kind) && direct_type_kind == E_TypeKind_Array)) - { - B32 need_extra_deref = e_type_kind_is_pointer_or_ref(type_kind); - E_Expr *array_expr = need_extra_deref ? e_expr_ref_deref(arena, expr) : expr; - E_Type *type = e_type_from_key(arena, need_extra_deref ? direct_type_key : type_key); - total_row_count = type->count; - accel->array_count = type->count; - accel->array_need_extra_deref = need_extra_deref; - } - - //////////////////////////// - //- rjf: pointer-to-pointer -> expansions generate dereference - // - else if(e_type_kind_is_pointer_or_ref(type_kind) && e_type_kind_is_pointer_or_ref(direct_type_kind)) - { - total_row_count = 1; - accel->is_ptr2ptr = 1; - } - - //////////////////////////// - //- rjf: package result - // - EV_ExpandInfo result = {0}; - { - result.user_data = accel; - result.row_count = total_row_count; - } - - scratch_end(scratch); - return result; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(default) -{ - EV_DefaultExpandAccel *accel = (EV_DefaultExpandAccel *)user_data; - EV_ExpandRangeInfo result = {0}; - U64 needed_row_count = dim_1u64(idx_range); - - //////////////////////////// - //- rjf: fill with members - // - if(accel->members.count != 0) - { - E_MemberArray *members = &accel->members; - result.row_exprs_count = Min(needed_row_count, members->count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - E_Member *member = &members->v[idx_range.min + row_expr_idx]; - result.row_exprs[row_expr_idx] = e_expr_ref_member_access(arena, expr, member->name); - result.row_members[row_expr_idx] = member; - } - } - - //////////////////////////// - //- rjf: fill with enum vals - // - else if(accel->enum_vals.count != 0) - { - E_EnumValArray *enumvals = &accel->enum_vals; - result.row_exprs_count = Min(needed_row_count, enumvals->count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - E_EnumVal *enumval = &enumvals->v[idx_range.min + row_expr_idx]; - result.row_exprs[row_expr_idx] = e_expr_ref_member_access(arena, expr, enumval->name); - result.row_members[row_expr_idx] = &e_member_nil; - } - } - - //////////////////////////// - //- rjf: fill with array indices - // - else if(accel->array_count != 0) - { - E_Expr *array_expr = accel->array_need_extra_deref ? e_expr_ref_deref(arena, expr) : expr; - result.row_exprs_count = Min(needed_row_count, accel->array_count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - result.row_exprs[row_expr_idx] = e_expr_ref_array_index(arena, array_expr, idx_range.min + row_expr_idx); - result.row_members[row_expr_idx] = &e_member_nil; - } - } - - //////////////////////////// - //- rjf: fill with ptr-to-ptr deref - // - else if(accel->is_ptr2ptr) - { - result.row_exprs_count = 1; - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - result.row_exprs[0] = e_expr_ref_deref(arena, expr); - result.row_members[0] = &e_member_nil; - } - - return result; -} - -//////////////////////////////// -//~ rjf: "array" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(array) -{ - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - E_TypeKey type_key = irtree.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - if(e_type_kind_is_pointer_or_ref(type_kind)) - { - E_Value count = ev_value_from_params(params); - E_TypeKey element_type_key = e_type_ptee_from_key(type_key); - E_TypeKey array_type_key = e_type_key_cons_array(element_type_key, count.u64); - E_TypeKey ptr_type_key = e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, array_type_key, 0); - expr = e_expr_ref_cast(arena, ptr_type_key, expr); - } - scratch_end(scratch); - return expr; -} - -//////////////////////////////// -//~ rjf: "list" - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(list) -{ - EV_ExpandInfo info = {0}; - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(list) -{ - EV_ExpandRangeInfo info = {0}; - return info; -} - -//////////////////////////////// -//~ rjf: "slice" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(slice) -{ - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - E_TypeKind type_kind = e_type_kind_from_key(irtree.type_key); - if(type_kind == E_TypeKind_Struct || type_kind == E_TypeKind_Class) - { - // rjf: unpack members - E_MemberArray members = e_type_data_members_from_key__cached(irtree.type_key); - - // rjf: choose base pointer & count members - E_Member *base_ptr_member = 0; - E_Member *count_member = 0; - for(U64 idx = 0; idx < members.count; idx += 1) - { - E_Member *member = &members.v[idx]; - E_TypeKey member_type = e_type_unwrap(member->type_key); - E_TypeKind member_type_kind = e_type_kind_from_key(member_type); - if(count_member == 0 && e_type_kind_is_integer(member_type_kind)) - { - count_member = member; - } - if(base_ptr_member == 0 && e_type_kind_is_pointer_or_ref(member_type_kind)) - { - base_ptr_member = &members.v[idx]; - } - if(count_member != 0 && base_ptr_member != 0) - { - break; - } - } - - // rjf: evaluate count member, determine count - U64 count = 0; - if(count_member != 0) - { - E_Expr *count_member_expr = e_expr_ref_member_access(scratch.arena, expr, count_member->name); - E_Eval count_member_eval = e_eval_from_expr(scratch.arena, count_member_expr); - E_Eval count_member_value_eval = e_value_eval_from_eval(count_member_eval); - count = count_member_value_eval.value.u64; - } - - // rjf: generate new struct slice type - E_TypeKey slice_type_key = zero_struct; - if(base_ptr_member != 0 && count_member != 0) - { - String8 struct_name = e_type_string_from_key(scratch.arena, irtree.type_key); - E_TypeKey element_type_key = e_type_ptee_from_key(base_ptr_member->type_key); - E_TypeKey array_type_key = e_type_key_cons_array(element_type_key, count); - E_TypeKey sized_base_ptr_type_key = e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, array_type_key, 0); - E_MemberList slice_type_members = {0}; - e_member_list_push(scratch.arena, &slice_type_members, count_member); - e_member_list_push(scratch.arena, &slice_type_members, &(E_Member){.kind = E_MemberKind_DataField, .type_key = sized_base_ptr_type_key, .name = base_ptr_member->name, .pretty_name = base_ptr_member->pretty_name, .off = base_ptr_member->off}); - E_MemberArray slice_type_members_array = e_member_array_from_list(scratch.arena, &slice_type_members); - slice_type_key = e_type_key_cons(.arch = e_type_state->ctx->primary_module->arch, - .kind = E_TypeKind_Struct, - .name = struct_name, - .members = slice_type_members_array.v, - .count = slice_type_members_array.count); - } - - // rjf: generate new expression tree - addr of struct, cast-to-ptr, deref - if(base_ptr_member != 0 && count_member != 0) - { - expr = e_expr_ref_addr(arena, expr); - expr = e_expr_ref_cast(arena, e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, slice_type_key, 0), expr); - expr = e_expr_ref_deref(arena, expr); - } - } - scratch_end(scratch); - return expr; -} - -//////////////////////////////// -//~ rjf: "bswap" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(bswap) -{ - expr = e_expr_ref_bswap(arena, expr); - return expr; -} - -//////////////////////////////// -//~ rjf: "cast" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(cast) -{ - E_TypeKey type_key = ev_type_key_from_params(params); - expr = e_expr_ref_cast(arena, type_key, expr); - return expr; -} - -//////////////////////////////// -//~ rjf: "wrap" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(wrap) -{ - String8 wrap_string = md_string_from_children(arena, params); - E_Expr *wrap_expr = e_parse_expr_from_text(arena, wrap_string); - E_Expr *new_root_expr = wrap_expr; - if(wrap_expr != &e_expr_nil) - { - Temp scratch = scratch_begin(&arena, 1); - typedef struct Task Task; - struct Task - { - Task *next; - E_Expr *parent; - E_Expr *expr; - }; - Task start_task = {0, &e_expr_nil, wrap_expr}; - Task *first_task = &start_task; - Task *last_task = first_task; - for(Task *t = first_task; t != 0; t = t->next) - { - if(t->expr->kind == E_ExprKind_LeafIdent && str8_match(t->expr->string, str8_lit("$expr"), 0)) - { - E_Expr *original_expr_ref = e_expr_ref(arena, expr); - if(t->parent != &e_expr_nil) - { - e_expr_insert_child(t->parent, t->expr, original_expr_ref); - e_expr_remove_child(t->parent, t->expr); - } - else - { - new_root_expr = original_expr_ref; - } - } - else for(E_Expr *child = t->expr->first; child != &e_expr_nil; child = child->next) - { - Task *task = push_array(scratch.arena, Task, 1); - SLLQueuePush(first_task, last_task, task); - task->parent = t->expr; - task->expr = child; - } - } - scratch_end(scratch); - } - return new_root_expr; -} - -//////////////////////////////// -//~ rjf: "only" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(only) -{ - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - E_TypeKey type_key = irtree.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_direct_from_key(type_key); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - B32 is_ptr = e_type_kind_is_pointer_or_ref(type_kind); - E_TypeKey struct_type_key = is_ptr ? direct_type_key : type_key; - E_TypeKind struct_type_kind = is_ptr ? direct_type_kind : type_kind; - if(struct_type_kind == E_TypeKind_Struct || - struct_type_kind == E_TypeKind_Union || - struct_type_kind == E_TypeKind_Class) - { - E_MemberArray current_members = e_type_data_members_from_key__cached(struct_type_key); - E_MemberList new_members = {0}; - for MD_EachNode(node, params->first) - { - for EachIndex(idx, current_members.count) - { - if(str8_match(node->string, current_members.v[idx].name, 0)) - { - e_member_list_push(scratch.arena, &new_members, ¤t_members.v[idx]); - break; - } - } - } - E_MemberArray new_members_array = e_member_array_from_list(scratch.arena, &new_members); - E_TypeKey new_type = {0}; - if(new_members_array.count == 1 && new_members_array.v[0].off == 0) - { - new_type = new_members_array.v[0].type_key; - } - else - { - String8 struct_name = e_type_string_from_key(scratch.arena, struct_type_key); - new_type = e_type_key_cons(.kind = E_TypeKind_Struct, .name = struct_name, .members = new_members_array.v, .count = new_members_array.count); - } - if(!is_ptr) - { - expr = e_expr_ref_addr(arena, expr); - } - expr = e_expr_ref_cast(arena, e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, new_type, 0), expr); - if(!is_ptr) - { - expr = e_expr_ref_deref(arena, expr); - } - } - scratch_end(scratch); - return expr; -} - -//////////////////////////////// -//~ rjf: "omit" - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(omit) -{ - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - E_TypeKey type_key = irtree.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_direct_from_key(type_key); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - B32 is_ptr = e_type_kind_is_pointer_or_ref(type_kind); - E_TypeKey struct_type_key = is_ptr ? direct_type_key : type_key; - E_TypeKind struct_type_kind = is_ptr ? direct_type_kind : type_kind; - if(struct_type_kind == E_TypeKind_Struct || - struct_type_kind == E_TypeKind_Union || - struct_type_kind == E_TypeKind_Class) - { - E_MemberArray current_members = e_type_data_members_from_key__cached(struct_type_key); - E_MemberList new_members = {0}; - for EachIndex(idx, current_members.count) - { - B32 include = 1; - for MD_EachNode(node, params->first) - { - if(str8_match(node->string, current_members.v[idx].name, 0)) - { - include = 0; - break; - } - } - if(include) - { - e_member_list_push(scratch.arena, &new_members, ¤t_members.v[idx]); - } - } - E_MemberArray new_members_array = e_member_array_from_list(scratch.arena, &new_members); - E_TypeKey new_type = {0}; - String8 struct_name = e_type_string_from_key(scratch.arena, struct_type_key); - new_type = e_type_key_cons(.kind = E_TypeKind_Struct, .name = struct_name, .members = new_members_array.v, .count = new_members_array.count); - if(!is_ptr) - { - expr = e_expr_ref_addr(arena, expr); - } - expr = e_expr_ref_cast(arena, e_type_key_cons_ptr(e_type_state->ctx->primary_module->arch, new_type, 0), expr); - if(!is_ptr) - { - expr = e_expr_ref_deref(arena, expr); - } - } - scratch_end(scratch); - return expr; -} diff --git a/src/eval_visualization/eval_visualization_builtin_view_rules.h b/src/eval_visualization/eval_visualization_builtin_view_rules.h deleted file mode 100644 index 1eb1312c..00000000 --- a/src/eval_visualization/eval_visualization_builtin_view_rules.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef EVAL_VISUALIZATION_BUILTIN_VIEW_RULES_H -#define EVAL_VISUALIZATION_BUILTIN_VIEW_RULES_H - -//////////////////////////////// -//~ rjf: View Rule Tree Info Extraction Helpers - -internal U64 ev_base_offset_from_eval(E_Eval eval); -internal E_Value ev_value_from_params(MD_Node *params); -internal E_TypeKey ev_type_key_from_params(MD_Node *params); -internal E_Value ev_value_from_params_key(MD_Node *params, String8 key); -internal Rng1U64 ev_range_from_eval_params(E_Eval eval, MD_Node *params); -internal Arch ev_arch_from_eval_params(E_Eval eval, MD_Node *params); - -#endif // EVAL_VISUALIZATION_BUILTIN_VIEW_RULES_H diff --git a/src/eval_visualization/eval_visualization_core.c b/src/eval_visualization/eval_visualization_core.c index dfaf7e46..84778d07 100644 --- a/src/eval_visualization/eval_visualization_core.c +++ b/src/eval_visualization/eval_visualization_core.c @@ -1,41 +1,15 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -//////////////////////////////// -//~ rjf: Generated Code - -#include "generated/eval_visualization.meta.c" - //////////////////////////////// //~ rjf: Nil/Identity View Rule Hooks -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(identity) -{ - return expr; -} - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(nil) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(nil) { EV_ExpandInfo info = {0}; return info; } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(nil) -{ - EV_ExpandRangeInfo info = {0}; - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(identity) -{ - return num; -} - -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity) -{ - return id; -} - //////////////////////////////// //~ rjf: Key Functions @@ -100,22 +74,68 @@ ev_hash_from_key(EV_Key key) //- rjf: type info -> expandability/editablity +internal E_TypeKey +ev_expansion_type_from_key(E_TypeKey type_key) +{ + E_TypeKey result = zero_struct; + for(E_TypeKey key = type_key; + !e_type_key_match(key, e_type_key_zero()); + key = e_type_key_direct(key)) + { + B32 done = 1; + E_TypeKind kind = e_type_kind_from_key(key); + + //- rjf: lenses -> try to see if this lens has special expansion rules. if + // so, choose the current eval + if(kind == E_TypeKind_Lens) + { + E_Type *type = e_type_from_key(key); + if(type->expand.info != 0 || + ev_expand_rule_from_string(type->name) != &ev_nil_expand_rule) + { + done = 1; + result = key; + } + else + { + done = 0; + } + } + + //- rjf: if we have meta-expression tags in the type chain, defer + // to the next type in the chain. + else if(E_TypeKind_FirstMeta <= kind && kind <= E_TypeKind_LastMeta) + { + done = 0; + } + + //- rjf: break if done + if(done) + { + break; + } + } + return result; +} + internal B32 ev_type_key_and_mode_is_expandable(E_TypeKey type_key, E_Mode mode) { B32 result = 0; - for(E_TypeKey t = type_key; !result; t = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(t)))) + E_TypeKey ev_expansion_type_key = ev_expansion_type_from_key(type_key); + if(!e_type_key_match(ev_expansion_type_key, e_type_key_zero())) { - E_TypeKind kind = e_type_kind_from_key(t); - if(kind == E_TypeKind_Null || kind == E_TypeKind_Function) + result = 1; + } + else + { + E_TypeKey default_expansion_type_key = e_default_expansion_type_from_key(type_key); + E_TypeKind kind = e_type_kind_from_key(default_expansion_type_key); + if(kind == E_TypeKind_Enum) { - break; + result = (mode == E_Mode_Null); } - if(kind == E_TypeKind_Struct || - kind == E_TypeKind_Union || - kind == E_TypeKind_Class || - kind == E_TypeKind_Array || - (kind == E_TypeKind_Enum && mode == E_Mode_Null)) + else if(kind != E_TypeKind_Null) { result = 1; } @@ -127,16 +147,50 @@ internal B32 ev_type_key_is_editable(E_TypeKey type_key) { B32 result = 0; - for(E_TypeKey t = type_key; !result; t = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(t)))) + B32 done = 0; + for(E_TypeKey t = type_key; !result && !done; t = e_type_key_direct(t)) { E_TypeKind kind = e_type_kind_from_key(t); - if(kind == E_TypeKind_Null || kind == E_TypeKind_Function) + switch(kind) { - break; - } - if((E_TypeKind_FirstBasic <= kind && kind <= E_TypeKind_LastBasic) || e_type_kind_is_pointer_or_ref(kind)) - { - result = 1; + case E_TypeKind_Null: + case E_TypeKind_Function: + { + result = 0; + done = 1; + }break; + default: + if((E_TypeKind_FirstBasic <= kind && kind <= E_TypeKind_LastBasic) || e_type_kind_is_pointer_or_ref(kind)) + { + result = 1; + done = 1; + }break; + case E_TypeKind_Array: + { + E_Type *type = e_type_from_key(t); + if(type->flags & E_TypeFlag_IsNotText) + { + result = 0; + done = 1; + } + else + { + E_TypeKind element_kind = e_type_kind_from_key(e_type_key_unwrap(t, E_TypeUnwrapFlag_All)); + result = (element_kind == E_TypeKind_U8 || + element_kind == E_TypeKind_U16 || + element_kind == E_TypeKind_U32 || + element_kind == E_TypeKind_S8 || + element_kind == E_TypeKind_S16 || + element_kind == E_TypeKind_S32 || + element_kind == E_TypeKind_UChar8 || + element_kind == E_TypeKind_UChar16 || + element_kind == E_TypeKind_UChar32 || + element_kind == E_TypeKind_Char8 || + element_kind == E_TypeKind_Char16 || + element_kind == E_TypeKind_Char32); + done = 1; + } + }break; } } return result; @@ -337,383 +391,122 @@ ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_string) //~ rjf: View Rule Info Table Building / Selection / Lookups internal void -ev_view_rule_info_table_push(Arena *arena, EV_ViewRuleInfoTable *table, EV_ViewRuleInfo *info) +ev_expand_rule_table_push(Arena *arena, EV_ExpandRuleTable *table, EV_ExpandRule *info) { if(table->slots_count == 0) { table->slots_count = 512; - table->slots = push_array(arena, EV_ViewRuleInfoSlot, table->slots_count); + table->slots = push_array(arena, EV_ExpandRuleSlot, table->slots_count); } U64 hash = ev_hash_from_seed_string(5381, info->string); U64 slot_idx = hash%table->slots_count; - EV_ViewRuleInfoSlot *slot = &table->slots[slot_idx]; - EV_ViewRuleInfoNode *n = push_array(arena, EV_ViewRuleInfoNode, 1); + EV_ExpandRuleSlot *slot = &table->slots[slot_idx]; + EV_ExpandRuleNode *n = push_array(arena, EV_ExpandRuleNode, 1); SLLQueuePush(slot->first, slot->last, n); MemoryCopyStruct(&n->v, info); n->v.string = push_str8_copy(arena, n->v.string); } internal void -ev_view_rule_info_table_push_builtins(Arena *arena, EV_ViewRuleInfoTable *table) -{ - for EachEnumVal(EV_ViewRuleKind, kind) - { - ev_view_rule_info_table_push(arena, table, &ev_builtin_view_rule_info_table[kind]); - } -} - -internal void -ev_select_view_rule_info_table(EV_ViewRuleInfoTable *table) +ev_select_expand_rule_table(EV_ExpandRuleTable *table) { ev_view_rule_info_table = table; } -internal EV_ViewRuleInfo * -ev_view_rule_info_from_string(String8 string) +internal EV_ExpandRule * +ev_expand_rule_from_string(String8 string) { - EV_ViewRuleInfo *info = &ev_nil_view_rule_info; - U64 hash = ev_hash_from_seed_string(5381, string); - U64 slot_idx = hash%ev_view_rule_info_table->slots_count; - EV_ViewRuleInfoSlot *slot = &ev_view_rule_info_table->slots[slot_idx]; - EV_ViewRuleInfoNode *node = 0; - for(EV_ViewRuleInfoNode *n = slot->first; n != 0; n = n->next) + EV_ExpandRule *info = &ev_nil_expand_rule; + if(ev_view_rule_info_table != 0 && ev_view_rule_info_table->slots_count != 0) { - if(str8_match(n->v.string, string, 0)) + U64 hash = ev_hash_from_seed_string(5381, string); + U64 slot_idx = hash%ev_view_rule_info_table->slots_count; + EV_ExpandRuleSlot *slot = &ev_view_rule_info_table->slots[slot_idx]; + EV_ExpandRuleNode *node = 0; + for(EV_ExpandRuleNode *n = slot->first; n != 0; n = n->next) { - node = n; - break; + if(str8_match(n->v.string, string, 0)) + { + node = n; + break; + } + } + if(node != 0) + { + info = &node->v; } - } - if(node != 0) - { - info = &node->v; } return info; } -//////////////////////////////// -//~ rjf: Automatic Type -> View Rule Table Building / Selection / Lookups - -internal void -ev_auto_view_rule_table_push_new(Arena *arena, EV_AutoViewRuleTable *table, E_TypeKey type_key, String8 view_rule, B32 is_required) +internal EV_ExpandRule * +ev_expand_rule_from_type_key(E_TypeKey type_key) { - if(table->slots_count == 0) + EV_ExpandRule *rule = &ev_nil_expand_rule; { - table->slots_count = 4096; - table->slots = push_array(arena, EV_AutoViewRuleSlot, table->slots_count); - } - U64 hash = e_hash_from_type_key(type_key); - U64 slot_idx = hash%table->slots_count; - EV_AutoViewRuleSlot *slot = &table->slots[slot_idx]; - EV_AutoViewRuleNode *node = 0; - for(EV_AutoViewRuleNode *n = slot->first; n != 0; n = n->next) - { - if(e_type_match(n->key, type_key)) + E_TypeKey k = e_type_key_unwrap(type_key, E_TypeUnwrapFlag_Meta); + E_TypeKind kind = e_type_kind_from_key(k); + for(;kind == E_TypeKind_Lens; k = e_type_key_direct(e_type_key_unwrap(k, E_TypeUnwrapFlag_Meta)), kind = e_type_kind_from_key(k)) { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(arena, EV_AutoViewRuleNode, 1); - node->key = type_key; - node->view_rule = push_str8_copy(arena, view_rule); - node->is_required = is_required; - SLLQueuePush(slot->first, slot->last, node); - } -} - -internal void -ev_select_auto_view_rule_table(EV_AutoViewRuleTable *table) -{ - ev_auto_view_rule_table = table; -} - -internal EV_ViewRuleList * -ev_auto_view_rules_from_type_key(Arena *arena, E_TypeKey type_key, B32 gather_required, B32 gather_optional) -{ - EV_ViewRuleList *result = &ev_nil_view_rule_list; - if(ev_auto_view_rule_table != 0 && ev_auto_view_rule_table->slots_count != 0) - { - U64 hash = e_hash_from_type_key(type_key); - U64 slot_idx = hash%ev_auto_view_rule_table->slots_count; - EV_AutoViewRuleSlot *slot = &ev_auto_view_rule_table->slots[slot_idx]; - EV_AutoViewRuleNode *node = 0; - for(EV_AutoViewRuleNode *n = slot->first; n != 0; n = n->next) - { - if(e_type_match(n->key, type_key) && ((n->is_required && gather_required) || (!n->is_required && gather_optional))) + E_Type *type = e_type_from_key(k); + EV_ExpandRule *candidate = ev_expand_rule_from_string(type->name); + if(candidate != &ev_nil_expand_rule) { - if(result == &ev_nil_view_rule_list) - { - result = push_array(arena, EV_ViewRuleList, 1); - } - ev_view_rule_list_push_string(arena, result, n->view_rule); + rule = candidate; + break; } } } - return result; -} - -//////////////////////////////// -//~ rjf: View Rule Instance List Building - -internal void -ev_view_rule_list_push_tree(Arena *arena, EV_ViewRuleList *list, MD_Node *root) -{ - EV_ViewRuleNode *n = push_array(arena, EV_ViewRuleNode, 1); - n->v.root = root; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal void -ev_view_rule_list_push_string(Arena *arena, EV_ViewRuleList *list, String8 string) -{ - if(string.size != 0) - { - MD_Node *root = md_tree_from_string(arena, string); - for MD_EachNode(tln, root->first) - { - ev_view_rule_list_push_tree(arena, list, tln); - } - } -} - -internal EV_ViewRuleList * -ev_view_rule_list_from_string(Arena *arena, String8 string) -{ - EV_ViewRuleList *dst = push_array(arena, EV_ViewRuleList, 1); - ev_view_rule_list_push_string(arena, dst, string); - return dst; -} - -internal EV_ViewRuleList * -ev_view_rule_list_from_expr_fastpaths(Arena *arena, String8 string) -{ - Temp scratch = scratch_begin(&arena, 1); - - // rjf: parse expression - E_TokenArray tokens = e_token_array_from_text(scratch.arena, string); - E_Parse parse = e_parse_expr_from_text_tokens(scratch.arena, string, &tokens); - - // rjf: extract view rules, encoded via fastpaths in expression string - String8List fastpath_view_rules = {0}; - { - U64 parse_opl = (parse.last_token >= tokens.v + tokens.count ? string.size : parse.last_token->range.min); - U64 comma_pos = str8_find_needle(string, parse_opl, str8_lit(","), 0); - U64 passthrough_pos = str8_find_needle(string, 0, str8_lit("--"), 0); - if(comma_pos < string.size && comma_pos < passthrough_pos) - { - String8 comma_extension = str8_skip_chop_whitespace(str8_substr(string, r1u64(comma_pos+1, passthrough_pos))); - if(str8_match(comma_extension, str8_lit("x"), StringMatchFlag_CaseInsensitive)) - { - str8_list_pushf(scratch.arena, &fastpath_view_rules, "hex"); - } - else if(str8_match(comma_extension, str8_lit("b"), StringMatchFlag_CaseInsensitive)) - { - str8_list_pushf(scratch.arena, &fastpath_view_rules, "bin"); - } - else if(str8_match(comma_extension, str8_lit("o"), StringMatchFlag_CaseInsensitive)) - { - str8_list_pushf(scratch.arena, &fastpath_view_rules, "oct"); - } - else if(comma_extension.size != 0) - { - str8_list_pushf(scratch.arena, &fastpath_view_rules, "array:{%S}", comma_extension); - } - } - if(passthrough_pos < string.size) - { - String8 passthrough_view_rule = str8_skip_chop_whitespace(str8_skip(string, passthrough_pos+2)); - if(passthrough_view_rule.size != 0) - { - str8_list_push(scratch.arena, &fastpath_view_rules, passthrough_view_rule); - } - } - } - - // rjf: convert strings to parsed view rules - EV_ViewRuleList *view_rule_list = push_array(arena, EV_ViewRuleList, 1); - for(String8Node *n = fastpath_view_rules.first; n != 0; n = n->next) - { - ev_view_rule_list_push_string(arena, view_rule_list, push_str8_copy(arena, n->string)); - } - - scratch_end(scratch); - return view_rule_list; -} - -internal EV_ViewRuleList * -ev_view_rule_list_from_inheritance(Arena *arena, EV_ViewRuleList *src) -{ - EV_ViewRuleList *dst = push_array(arena, EV_ViewRuleList, 1); - for(EV_ViewRuleNode *n = src->first; n != 0; n = n->next) - { - EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); - if(info->flags & EV_ViewRuleInfoFlag_Inherited) - { - ev_view_rule_list_push_tree(arena, dst, n->v.root); - } - } - return dst; -} - -internal EV_ViewRuleList * -ev_view_rule_list_copy(Arena *arena, EV_ViewRuleList *src) -{ - EV_ViewRuleList *dst = push_array(arena, EV_ViewRuleList, 1); - for(EV_ViewRuleNode *n = src->first; n != 0; n = n->next) - { - ev_view_rule_list_push_tree(arena, dst, n->v.root); - } - return dst; -} - -internal void -ev_view_rule_list_concat_in_place(EV_ViewRuleList *dst, EV_ViewRuleList **src) -{ - if(dst->first && src[0] != &ev_nil_view_rule_list && src[0]->first) - { - dst->last->next = src[0]->first; - dst->last = src[0]->last; - dst->count += src[0]->count; - } - else if(!dst->first) - { - MemoryCopyStruct(dst, *src); - } - *src = &ev_nil_view_rule_list; -} - -//////////////////////////////// -//~ rjf: Expression Resolution (Dynamic Overrides, View Rule Application) - -internal E_Expr * -ev_resolved_from_expr(Arena *arena, E_Expr *expr, EV_ViewRuleList *view_rules) -{ - ProfBeginFunction(); - { - Temp scratch = scratch_begin(&arena, 1); - E_Eval eval = e_eval_from_expr(scratch.arena, expr); - E_TypeKey type_key = eval.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey ptee_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(type_key))); - E_TypeKind ptee_type_kind = e_type_kind_from_key(ptee_type_key); - if(ptee_type_kind == E_TypeKind_Struct || ptee_type_kind == E_TypeKind_Class) - { - E_Type *ptee_type = e_type_from_key(scratch.arena, ptee_type_key); - B32 has_vtable = 0; - for(U64 idx = 0; idx < ptee_type->count; idx += 1) - { - if(ptee_type->members[idx].kind == E_MemberKind_VirtualMethod) - { - has_vtable = 1; - break; - } - } - if(has_vtable) - { - U64 ptr_vaddr = eval.value.u64; - U64 addr_size = e_type_byte_size_from_key(e_type_unwrap(type_key)); - U64 class_base_vaddr = 0; - U64 vtable_vaddr = 0; - if(e_space_read(eval.space, &class_base_vaddr, r1u64(ptr_vaddr, ptr_vaddr+addr_size)) && - e_space_read(eval.space, &vtable_vaddr, r1u64(class_base_vaddr, class_base_vaddr+addr_size))) - { - Arch arch = e_type_state->ctx->primary_module->arch; - U32 rdi_idx = 0; - RDI_Parsed *rdi = 0; - U64 module_base = 0; - for(U64 idx = 0; idx < e_type_state->ctx->modules_count; idx += 1) - { - if(contains_1u64(e_type_state->ctx->modules[idx].vaddr_range, vtable_vaddr)) - { - arch = e_type_state->ctx->modules[idx].arch; - rdi_idx = (U32)idx; - rdi = e_type_state->ctx->modules[idx].rdi; - module_base = e_type_state->ctx->modules[idx].vaddr_range.min; - break; - } - } - if(rdi != 0) - { - U64 vtable_voff = vtable_vaddr - module_base; - U64 global_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_GlobalVMap, vtable_voff); - RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, global_idx); - if(global_var->link_flags & RDI_LinkFlag_TypeScoped) - { - RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, global_var->container_idx); - RDI_TypeNode *type = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx); - E_TypeKey derived_type_key = e_type_key_ext(e_type_kind_from_rdi(type->kind), udt->self_type_idx, rdi_idx); - E_TypeKey ptr_to_derived_type_key = e_type_key_cons_ptr(arch, derived_type_key, 0); - expr = e_expr_ref_cast(arena, ptr_to_derived_type_key, expr); - } - } - } - } - } - scratch_end(scratch); - } - for(EV_ViewRuleNode *n = view_rules->first; n != 0; n = n->next) - { - EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); - if(info->expr_resolution != 0) - { - expr = info->expr_resolution(arena, expr, n->v.root); - } - } - ProfEnd(); - return expr; + return rule; } //////////////////////////////// //~ rjf: Block Building internal EV_BlockTree -ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 string, E_Expr *expr, EV_ViewRuleList *view_rules) +ev_block_tree_from_eval(Arena *arena, EV_View *view, String8 filter, E_Eval root_eval) { ProfBeginFunction(); EV_BlockTree tree = {&ev_nil_block}; { Temp scratch = scratch_begin(&arena, 1); - EV_ViewRuleInfo *default_expand_view_rule_info = ev_view_rule_info_from_string(str8_lit("default")); - //- rjf: form complete set of view rules - EV_ViewRuleList *top_level_view_rules = ev_view_rule_list_copy(arena, view_rules); - { - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, expr); - EV_ViewRuleList *auto_view_rules = ev_auto_view_rules_from_type_key(arena, irtree.type_key, 1, 1); - ev_view_rule_list_concat_in_place(top_level_view_rules, &auto_view_rules); - } + //- rjf: generate root expression + EV_Key root_key = ev_key_root(); + EV_Key root_row_key = ev_key_make(ev_hash_from_key(root_key), 1); //- rjf: generate root block tree.root = push_array(arena, EV_Block, 1); MemoryCopyStruct(tree.root, &ev_nil_block); - tree.root->key = ev_key_root(); - tree.root->string = string; - tree.root->expr = ev_resolved_from_expr(arena, expr, top_level_view_rules); - tree.root->view_rules = top_level_view_rules; + tree.root->key = root_key; + tree.root->string = str8_zero(); + tree.root->eval = root_eval; + tree.root->type_expand_rule = &e_type_expand_rule__default; + tree.root->viz_expand_rule = &ev_nil_expand_rule; tree.root->row_count = 1; tree.total_row_count += 1; tree.total_item_count += 1; - //- rjf: iterate all expansions & generate blocks for each - typedef struct Task Task; - struct Task + //- rjf: generate initial task, for root's evaluation + typedef struct BlockTreeBuildTask BlockTreeBuildTask; + struct BlockTreeBuildTask { - Task *next; + BlockTreeBuildTask *next; EV_Block *parent_block; - E_Expr *expr; + E_Eval eval; + E_Expr *next_expr; U64 child_id; - EV_ViewRuleList *view_rules; U64 split_relative_idx; B32 default_expanded; + B32 force_expanded; + S32 depth; }; - Task start_task = {0, tree.root, tree.root->expr, 1, top_level_view_rules, 0}; - Task *first_task = &start_task; - Task *last_task = first_task; - for(Task *t = first_task; t != 0; t = t->next) + BlockTreeBuildTask start_task = {0, tree.root, tree.root->eval, tree.root->eval.expr->next, 1, 0}; + BlockTreeBuildTask *first_task = &start_task; + BlockTreeBuildTask *last_task = first_task; + + //- rjf: iterate all expansions & generate blocks for each + for(BlockTreeBuildTask *t = first_task; t != 0; t = t->next) { // rjf: get task key EV_Key key = ev_key_make(ev_hash_from_key(t->parent_block->key), t->child_id); @@ -721,7 +514,7 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str // rjf: obtain expansion node & expansion state EV_ExpandNode *expand_node = ev_expand_node_from_key(view, key); B32 is_expanded = (expand_node != 0 && expand_node->expanded); - if(t->default_expanded) + if(t->default_expanded || t->force_expanded) { is_expanded ^= 1; } @@ -732,25 +525,51 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str continue; } - // rjf: get expansion view rule info - EV_ViewRuleInfo *expand_view_rule_info = default_expand_view_rule_info; - MD_Node *expand_params = &md_nil_node; - for(EV_ViewRuleNode *n = t->view_rules->first; n != 0; n = n->next) + // rjf: unpack eval + E_Mode mode = t->eval.irtree.mode; + E_Eval eval = t->eval; + E_TypeKey expansion_type_key = ev_expansion_type_from_key(eval.irtree.type_key); + if(!e_type_key_match(expansion_type_key, e_type_key_zero())) { - EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); - if(info->expr_expand_info != 0 && info->expr_expand_info != EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil)) - { - expand_view_rule_info = info; - expand_params = n->v.root; - } + eval.irtree.type_key = expansion_type_key; } - // rjf: get expansion info - EV_ExpandInfo expand_info = expand_view_rule_info->expr_expand_info(arena, view, filter, t->expr, expand_params); + // rjf: get expansion rules from type + E_TypeExpandRule *type_expand_rule = e_expand_rule_from_type_key(eval.irtree.type_key); + EV_ExpandRule *viz_expand_rule = ev_expand_rule_from_type_key(eval.irtree.type_key); + + // rjf: skip if no expansion rule, & type info disallows expansion + if(viz_expand_rule == &ev_nil_expand_rule && !ev_type_key_and_mode_is_expandable(eval.irtree.type_key, mode)) + { + continue; + } + + // rjf: get filter for this task + String8 task_filter = t->depth == 0 ? filter : str8_zero(); + + // rjf: get top-level lookup/expansion info + E_TypeExpandInfo type_expand_info = type_expand_rule->info(arena, eval, task_filter); + EV_ExpandInfo viz_expand_info = viz_expand_rule->info(arena, view, task_filter, eval.expr); + + // rjf: determine expansion info + U64 expansion_row_count = type_expand_info.expr_count; + if(viz_expand_rule != &ev_nil_expand_rule) + { + expansion_row_count = viz_expand_info.row_count; + } + expansion_row_count = Min(0x0fffffffffffffffull, expansion_row_count); + + // rjf: determine if this expansion supports child expansions + B32 allow_child_expansions = 1; + if(viz_expand_info.single_item) + { + // NOTE(rjf): for now, just plugging in the heuristic of "is this a single row (a.k.a. visualizer)?" + allow_child_expansions = 0; + } // rjf: generate block for expansion EV_Block *expansion_block = &ev_nil_block; - if(expand_info.row_count != 0) + if(expansion_row_count != 0) { expansion_block = push_array(arena, EV_Block, 1); MemoryCopyStruct(expansion_block, &ev_nil_block); @@ -758,23 +577,22 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str expansion_block->parent = t->parent_block; expansion_block->key = key; expansion_block->split_relative_idx = t->split_relative_idx; - expansion_block->expr = t->expr; - expansion_block->view_rules = t->view_rules; - expansion_block->expand_view_rule_info = expand_view_rule_info; - expansion_block->expand_view_rule_params = expand_params; - expansion_block->expand_view_rule_info_user_data = expand_info.user_data; - expansion_block->row_count = expand_info.row_count; - expansion_block->single_item = expand_info.single_item; - expansion_block->rows_default_expanded = expand_info.rows_default_expanded; - tree.total_row_count += expand_info.row_count; - tree.total_item_count += expand_info.single_item ? 1 : expand_info.row_count; + expansion_block->eval = eval; + expansion_block->filter = task_filter; + expansion_block->type_expand_info = type_expand_info; + expansion_block->type_expand_rule = type_expand_rule; + expansion_block->viz_expand_info = viz_expand_info; + expansion_block->viz_expand_rule = viz_expand_rule; + expansion_block->row_count = expansion_row_count; + tree.total_row_count += expansion_row_count; + tree.total_item_count += viz_expand_info.single_item ? 1 : expansion_row_count; } // rjf: gather children expansions from expansion state U64 child_count = 0; EV_Key *child_keys = 0; U64 *child_nums = 0; - if(!child_count && !expand_info.rows_default_expanded && expand_node != 0 && expand_info.row_count != 0 && expand_view_rule_info->expr_expand_range_info) + if(allow_child_expansions && !child_count && !viz_expand_info.rows_default_expanded && expand_node != 0 && expansion_row_count != 0) { // rjf: count children for(EV_ExpandNode *child = expand_node->first; child != 0; child = child->next, child_count += 1){} @@ -788,7 +606,7 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str for(EV_ExpandNode *child = expand_node->first; child != 0; child = child->next, idx += 1) { child_keys[idx] = child->key; - child_nums[idx] = expand_view_rule_info->expr_expand_num_from_id(child->key.child_id, expand_info.user_data); + child_nums[idx] = type_expand_rule->num_from_id(type_expand_info.user_data, child->key.child_id); if(child_nums[idx] != child_keys[idx].child_id) { needs_sort = 1; @@ -821,14 +639,14 @@ 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(allow_child_expansions && !child_count && (viz_expand_info.rows_default_expanded || (expand_node == 0 && !viz_expand_info.rows_default_expanded))) { - child_count = expand_info.row_count; + child_count = viz_expand_info.row_count; child_keys = push_array(scratch.arena, EV_Key, child_count); child_nums = push_array(scratch.arena, U64, child_count); for(U64 idx = 0; idx < child_count; idx += 1) { - U64 child_id = expand_view_rule_info->expr_expand_id_from_num(idx+1, expand_info.user_data); + U64 child_id = type_expand_rule->id_from_num(type_expand_info.user_data, idx+1); child_keys[idx] = ev_key_make(ev_hash_from_key(key), child_id); child_nums[idx] = idx+1; } @@ -839,44 +657,43 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str { U64 split_num = child_nums[idx]; U64 split_relative_idx = split_num - 1; - if(split_relative_idx >= expand_info.row_count) + if(split_relative_idx >= expansion_row_count) { continue; } - if(expand_info.rows_default_expanded || ev_expansion_from_key(view, child_keys[idx])) + if(viz_expand_info.rows_default_expanded || ev_expansion_from_key(view, child_keys[idx])) { - EV_ExpandRangeInfo child_expand = expand_view_rule_info->expr_expand_range_info(arena, view, filter, t->expr, expand_params, r1u64(split_relative_idx, split_relative_idx+1), expand_info.user_data); - if(child_expand.row_exprs_count > 0) - { - EV_Key child_key = child_keys[idx]; - E_Expr *child_expr = child_expand.row_exprs[0]; - EV_ViewRuleList *child_view_rules = ev_view_rule_list_from_inheritance(arena, t->view_rules); - String8 child_view_rule_string = ev_view_rule_from_key(view, child_key); - ev_view_rule_list_push_string(arena, child_view_rules, child_view_rule_string); - if(child_expand.row_strings[0].size != 0) - { - EV_ViewRuleList *fastpath_view_rules = ev_view_rule_list_from_expr_fastpaths(arena, child_expand.row_strings[0]); - ev_view_rule_list_concat_in_place(child_view_rules, &fastpath_view_rules); - } - { - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType child_irtree = e_irtree_and_type_from_expr(scratch.arena, child_expr); - EV_ViewRuleList *child_auto_view_rules = ev_auto_view_rules_from_type_key(arena, child_irtree.type_key, 1, child_view_rule_string.size == 0); - ev_view_rule_list_concat_in_place(child_view_rules, &child_auto_view_rules); - scratch_end(scratch); - } - E_Expr *child_expr__resolved = ev_resolved_from_expr(arena, child_expr, child_view_rules); - Task *task = push_array(scratch.arena, Task, 1); - SLLQueuePush(first_task, last_task, task); - task->parent_block = expansion_block; - task->expr = child_expr__resolved; - task->child_id = child_key.child_id; - task->view_rules = child_view_rules; - task->split_relative_idx = split_relative_idx; - task->default_expanded = expand_info.rows_default_expanded; - } + Rng1U64 child_range = r1u64(split_relative_idx, split_relative_idx+1); + E_Eval child_eval = {0}; + type_expand_rule->range(arena, type_expand_info.user_data, eval, task_filter, r1u64(split_relative_idx, split_relative_idx+1), &child_eval); + EV_Key child_key = child_keys[idx]; + BlockTreeBuildTask *task = push_array(scratch.arena, BlockTreeBuildTask, 1); + SLLQueuePush(first_task, last_task, task); + task->parent_block = expansion_block; + task->eval = child_eval; + task->next_expr = &e_expr_nil; + task->child_id = child_key.child_id; + task->split_relative_idx = split_relative_idx; + task->default_expanded = viz_expand_info.rows_default_expanded; + task->depth = t->depth+1; } } + + // rjf: if this expr has a sibling, push another task to continue the chain + if(t->next_expr != &e_expr_nil) + { + BlockTreeBuildTask *task = push_array(scratch.arena, BlockTreeBuildTask, 1); + task->next = t->next; + t->next = task; + task->parent_block = t->parent_block; + task->eval = e_eval_from_expr(t->next_expr); + task->next_expr = t->next_expr->next; + task->child_id = t->child_id + 1; + task->split_relative_idx = 0; + task->default_expanded = t->default_expanded; + task->force_expanded = 1; + task->depth = t->depth; + } } scratch_end(scratch); } @@ -884,25 +701,6 @@ ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 str return tree; } -internal EV_BlockTree -ev_block_tree_from_string(Arena *arena, EV_View *view, String8 filter, String8 string, EV_ViewRuleList *view_rules) -{ - ProfBeginFunction(); - EV_BlockTree tree = {0}; - Temp scratch = scratch_begin(&arena, 1); - { - E_TokenArray tokens = e_token_array_from_text(scratch.arena, string); - E_Parse parse = e_parse_expr_from_text_tokens(arena, string, &tokens); - EV_ViewRuleList *fastpath_view_rules = ev_view_rule_list_from_expr_fastpaths(arena, string); - EV_ViewRuleList *all_view_rules = ev_view_rule_list_copy(arena, view_rules); - ev_view_rule_list_concat_in_place(all_view_rules, &fastpath_view_rules); - tree = ev_block_tree_from_expr(arena, view, filter, string, parse.expr, all_view_rules); - } - scratch_end(scratch); - ProfEnd(); - return tree; -} - internal U64 ev_depth_from_block(EV_Block *block) { @@ -917,6 +715,20 @@ ev_depth_from_block(EV_Block *block) //////////////////////////////// //~ rjf: Block Coordinate Spaces +internal U64 +ev_block_id_from_num(EV_Block *block, U64 num) +{ + U64 result = block->type_expand_rule->id_from_num(block->type_expand_info.user_data, num); + return result; +} + +internal U64 +ev_block_num_from_id(EV_Block *block, U64 id) +{ + U64 result = block->type_expand_rule->num_from_id(block->type_expand_info.user_data, id); + return result; +} + internal EV_BlockRangeList ev_block_range_list_from_tree(Arena *arena, EV_BlockTree *block_tree) { @@ -965,7 +777,7 @@ ev_block_range_list_from_tree(Arena *arena, EV_BlockTree *block_tree) // rjf: generate task for post-child rows, if any, after children Rng1U64 remainder_range = r1u64(t->next_child->split_relative_idx+1, t->block_relative_range.max); - if(remainder_range.max > remainder_range.min) + if(remainder_range.max >= remainder_range.min) { BlockTask *remainder_task = push_array(scratch.arena, BlockTask, 1); remainder_task->next = child_task->next; @@ -985,10 +797,10 @@ internal EV_BlockRange ev_block_range_from_num(EV_BlockRangeList *block_ranges, U64 num) { EV_BlockRange result = {&ev_nil_block}; - U64 base_num = 0; + U64 base_num = 1; for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) { - U64 range_size = n->v.block->single_item ? 1 : dim_1u64(n->v.range); + U64 range_size = n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range); Rng1U64 global_range = r1u64(base_num, base_num + range_size); if(contains_1u64(global_range, num)) { @@ -1008,15 +820,15 @@ ev_key_from_num(EV_BlockRangeList *block_ranges, U64 num) { key = ev_key_make(ev_hash_from_key(ev_key_root()), 1); } - U64 base_num = 0; + U64 base_num = 1; for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) { - U64 range_size = n->v.block->single_item ? 1 : dim_1u64(n->v.range); + U64 range_size = n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range); Rng1U64 global_range = r1u64(base_num, base_num + range_size); if(contains_1u64(global_range, num)) { U64 relative_num = (num - base_num) + n->v.range.min + 1; - U64 child_id = n->v.block->expand_view_rule_info->expr_expand_id_from_num(relative_num, n->v.block->expand_view_rule_info_user_data); + U64 child_id = ev_block_id_from_num(n->v.block, relative_num); EV_Key block_key = n->v.block->key; key = ev_key_make(ev_hash_from_key(block_key), child_id); break; @@ -1030,53 +842,104 @@ internal U64 ev_num_from_key(EV_BlockRangeList *block_ranges, EV_Key key) { U64 result = 0; - U64 base_num = 0; + U64 base_num = 1; for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) { U64 hash = ev_hash_from_key(n->v.block->key); if(hash == key.parent_hash) { - U64 relative_num = n->v.block->expand_view_rule_info->expr_expand_num_from_id(key.child_id, n->v.block->expand_view_rule_info_user_data); - Rng1U64 num_range = r1u64(n->v.range.min, n->v.block->single_item ? (n->v.range.min+1) : n->v.range.max); + U64 relative_num = ev_block_num_from_id(n->v.block, key.child_id); + Rng1U64 num_range = r1u64(n->v.range.min, n->v.block->viz_expand_info.single_item ? (n->v.range.min+1) : n->v.range.max); if(contains_1u64(num_range, relative_num-1)) { result = base_num + (relative_num - 1 - n->v.range.min); break; } } - base_num += n->v.block->single_item ? 1 : dim_1u64(n->v.range); + base_num += n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range); } return result; } +internal U64 +ev_vnum_from_num(EV_BlockRangeList *block_ranges, U64 num) +{ + U64 vnum = 0; + { + U64 base_vnum = 1; + U64 base_num = 1; + for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) + { + U64 next_base_num = base_num + (n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range)); + if(base_num <= num && num < next_base_num) + { + U64 relative_vnum = (n->v.block->viz_expand_info.single_item ? 0 : (num - base_num)); + vnum = base_vnum + relative_vnum; + break; + } + base_num = next_base_num; + base_vnum += dim_1u64(n->v.range); + } + if(vnum == 0) + { + vnum = base_vnum; + } + } + return vnum; +} + +internal U64 +ev_num_from_vnum(EV_BlockRangeList *block_ranges, U64 vnum) +{ + U64 num = 0; + { + U64 base_vnum = 1; + U64 base_num = 1; + for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) + { + U64 next_base_vnum = base_vnum + dim_1u64(n->v.range); + if(base_vnum <= vnum && vnum < next_base_vnum) + { + U64 relative_num = (n->v.block->viz_expand_info.single_item ? 0 : (vnum - base_vnum)); + num = base_num + relative_num; + break; + } + base_vnum = next_base_vnum; + base_num += (n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range)); + } + } + return num; +} + //////////////////////////////// //~ rjf: Row Building internal EV_WindowedRowList -ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, String8 filter, EV_BlockRangeList *block_ranges, Rng1U64 visible_range) +ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, Rng1U64 vnum_range) { EV_WindowedRowList rows = {0}; { - U64 visual_idx_off = 0; + U64 base_vnum = 1; for(EV_BlockRangeNode *n = block_ranges->first; n != 0; n = n->next) { // rjf: unpack this block/range pair Rng1U64 block_relative_range = n->v.range; U64 block_num_visual_rows = dim_1u64(block_relative_range); - Rng1U64 block_global_range = r1u64(visual_idx_off, visual_idx_off + block_num_visual_rows); + Rng1U64 block_global_range = r1u64(base_vnum, base_vnum + block_num_visual_rows); + String8 block_filter = n->v.block->filter; // rjf: get skip/chop of global range U64 num_skipped = 0; U64 num_chopped = 0; { - if(visible_range.min > block_global_range.min) + if(vnum_range.min > block_global_range.min) { - num_skipped = (visible_range.min - block_global_range.min); + num_skipped = (vnum_range.min - block_global_range.min); num_skipped = Min(num_skipped, block_num_visual_rows); } - if(visible_range.max < block_global_range.max) + if(vnum_range.max < block_global_range.max) { - num_chopped = (block_global_range.max - visible_range.max); + num_chopped = (block_global_range.max - vnum_range.max); num_chopped = Min(num_chopped, block_num_visual_rows); } } @@ -1086,11 +949,11 @@ ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, String8 block_relative_range.max - num_chopped); // rjf: sum & advance - visual_idx_off += block_num_visual_rows; + base_vnum += block_num_visual_rows; rows.count_before_visual += num_skipped; if(block_num_visual_rows != 0 && num_skipped != 0) { - if(n->v.block->single_item) + if(n->v.block->viz_expand_info.single_item) { if(num_skipped >= block_num_visual_rows) { @@ -1107,97 +970,54 @@ ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, String8 if(block_relative_range__windowed.max > block_relative_range__windowed.min) { // rjf: get info about expansion range - EV_ExpandRangeInfo expand_range_info = n->v.block->expand_view_rule_info->expr_expand_range_info(arena, view, filter, n->v.block->expr, n->v.block->expand_view_rule_params, block_relative_range__windowed, n->v.block->expand_view_rule_info_user_data); + B32 is_standalone_row = 0; + U64 range_exprs_count = dim_1u64(block_relative_range__windowed); + E_Eval *range_evals = push_array(arena, E_Eval, range_exprs_count); + for EachIndex(idx, range_exprs_count) + { + range_evals[idx] = e_eval_nil; + } + if(n->v.block->viz_expand_info.single_item || n->v.block->parent == &ev_nil_block) + { + is_standalone_row = 1; + } + else + { + n->v.block->type_expand_rule->range(arena, n->v.block->type_expand_info.user_data, n->v.block->eval, block_filter, block_relative_range__windowed, range_evals); + } // rjf: no expansion operator applied -> push row for block expression; pass through block info - if(expand_range_info.row_exprs_count == 0) + if(is_standalone_row) { - E_Member *member = &e_member_nil; - if(n->v.block->expr->kind == E_ExprKind_MemberAccess) - { - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType lhs_irtree = e_irtree_and_type_from_expr(scratch.arena, n->v.block->expr->first); - E_TypeKey lhs_type_key = lhs_irtree.type_key; - E_Member expr_member = e_type_member_from_key_name__cached(lhs_type_key, n->v.block->expr->last->string); - if(expr_member.kind != E_MemberKind_Null) - { - member = push_array(arena, E_Member, 1); - MemoryCopyStruct(member, &expr_member); - } - scratch_end(scratch); - } - EV_Row *row = push_array(arena, EV_Row, 1); - SLLQueuePush(rows.first, rows.last, row); + EV_WindowedRowNode *row_node = push_array(arena, EV_WindowedRowNode, 1); + SLLQueuePush(rows.first, rows.last, row_node); rows.count += 1; - row->block = n->v.block; - row->key = ev_key_make(ev_hash_from_key(row->block->key), 1); - row->visual_size = n->v.block->single_item ? (n->v.block->row_count - (num_skipped + num_chopped)) : 1; - row->visual_size_skipped = num_skipped; - row->visual_size_chopped = num_chopped; - row->string = n->v.block->string; - row->expr = n->v.block->expr; - row->member = member; - row->view_rules = n->v.block->view_rules; + row_node->visual_size_skipped = num_skipped; + row_node->visual_size_chopped = num_chopped; + EV_Row *row = &row_node->row; + row->block = n->v.block; + row->key = ev_key_make(ev_hash_from_key(row->block->key), 1); + row->visual_size = n->v.block->viz_expand_info.single_item ? (n->v.block->row_count - (num_skipped + num_chopped)) : 1; + row->edit_string = n->v.block->string; + row->eval = n->v.block->eval; } // rjf: expansion operator applied -> call, and add rows for all expressions in the viewable range - else + else for EachIndex(idx, range_exprs_count) { - for EachIndex(idx, expand_range_info.row_exprs_count) - { - U64 child_num = block_relative_range.min + num_skipped + idx + 1; - U64 child_id = n->v.block->expand_view_rule_info->expr_expand_id_from_num(child_num, n->v.block->expand_view_rule_info_user_data); - EV_Key row_key = ev_key_make(ev_hash_from_key(n->v.block->key), child_id); - E_Expr *row_expr = expand_range_info.row_exprs[idx]; - EV_ViewRuleList *row_view_rules = ev_view_rule_list_from_inheritance(arena, n->v.block->view_rules); - String8 row_view_rule_string = ev_view_rule_from_key(view, row_key); - ev_view_rule_list_push_string(arena, row_view_rules, row_view_rule_string); - if(expand_range_info.row_strings[idx].size != 0) - { - EV_ViewRuleList *fastpath_view_rules = ev_view_rule_list_from_expr_fastpaths(arena, expand_range_info.row_strings[idx]); - ev_view_rule_list_concat_in_place(row_view_rules, &fastpath_view_rules); - } - { - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType row_irtree = e_irtree_and_type_from_expr(scratch.arena, row_expr); - EV_ViewRuleList *row_auto_view_rules = ev_auto_view_rules_from_type_key(arena, row_irtree.type_key, 1, row_view_rule_string.size == 0); - ev_view_rule_list_concat_in_place(row_view_rules, &row_auto_view_rules); - scratch_end(scratch); - } - E_Expr *row_expr__resolved = ev_resolved_from_expr(arena, row_expr, row_view_rules); - EV_Row *row = push_array(arena, EV_Row, 1); - SLLQueuePush(rows.first, rows.last, row); - rows.count += 1; - row->block = n->v.block; - row->key = row_key; - row->visual_size = 1; - row->visual_size_skipped = 0; - row->visual_size_chopped = 0; - row->string = expand_range_info.row_strings[idx]; - row->expr = row_expr__resolved; - row->member = expand_range_info.row_members[idx]; - row->view_rules = row_view_rules; - if(row->member == &e_member_nil || row->member == 0) - { - if(row->expr->kind == E_ExprKind_MemberAccess) - { - Temp scratch = scratch_begin(&arena, 1); - E_IRTreeAndType lhs_irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr->first); - E_TypeKey lhs_type_key = lhs_irtree.type_key; - E_Member expr_member = e_type_member_from_key_name__cached(lhs_type_key, row->expr->last->string); - if(expr_member.kind != E_MemberKind_Null) - { - row->member = push_array(arena, E_Member, 1); - MemoryCopyStruct(row->member, &expr_member); - } - scratch_end(scratch); - } - } - if(expand_range_info.row_view_rules[idx].size != 0) - { - ev_key_set_view_rule(view, row->key, expand_range_info.row_view_rules[idx]); - } - } + U64 child_num = block_relative_range.min + num_skipped + idx + 1; + U64 child_id = ev_block_id_from_num(n->v.block, child_num); + EV_Key row_key = ev_key_make(ev_hash_from_key(n->v.block->key), child_id); + E_Eval row_eval = range_evals[idx]; + EV_WindowedRowNode *row_node = push_array(arena, EV_WindowedRowNode, 1); + SLLQueuePush(rows.first, rows.last, row_node); + rows.count += 1; + EV_Row *row = &row_node->row; + row->block = n->v.block; + row->key = row_key; + row->visual_size = 1; + row->edit_string = row_eval.string; + row->eval = row_eval; } } } @@ -1205,49 +1025,53 @@ ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, String8 return rows; } -internal String8 -ev_expr_string_from_row(Arena *arena, EV_Row *row, EV_StringFlags flags) +internal EV_Row * +ev_row_from_num(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, U64 num) { - String8 result = row->string; - E_Expr *notable_expr = row->expr; - for(B32 good = 0; !good;) + U64 vidx = ev_vnum_from_num(block_ranges, num); + EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(arena, view, block_ranges, r1u64(vidx, vidx+1)); + EV_Row *result = 0; + if(rows.first != 0) { - switch(notable_expr->kind) + result = &rows.first->row; + } + else + { + result = push_array(arena, EV_Row, 1); + result->block = &ev_nil_block; + result->eval = e_eval_nil; + } + return result; +} + +internal EV_WindowedRowList +ev_rows_from_num_range(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, Rng1U64 num_range) +{ + Rng1U64 vnum_range = r1u64(ev_vnum_from_num(block_ranges, num_range.min), ev_vnum_from_num(block_ranges, num_range.max)+1); + EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(arena, view, block_ranges, vnum_range); + return rows; +} + +internal B32 +ev_eval_is_expandable(E_Eval eval) +{ + B32 result = 0; + E_IRTreeAndType irtree = eval.irtree; + + // rjf: determine if lenses force expandability + if(!result) + { + EV_ExpandRule *expand_rule = ev_expand_rule_from_type_key(irtree.type_key); + if(expand_rule != &ev_nil_expand_rule) { - default:{good = 1;}break; - case E_ExprKind_Address: - case E_ExprKind_Deref: - case E_ExprKind_Cast: - { - notable_expr = notable_expr->last; - }break; - case E_ExprKind_Ref: - { - notable_expr = notable_expr->ref; - }break; + result = 1; } } - if(result.size == 0) switch(notable_expr->kind) + + // rjf: determine if type info force expandability + if(!result) { - default: - { - result = e_string_from_expr(arena, notable_expr); - }break; - case E_ExprKind_ArrayIndex: - { - result = push_str8f(arena, "[%S]", e_string_from_expr(arena, notable_expr->last)); - }break; - case E_ExprKind_MemberAccess: - { - if(flags & EV_StringFlag_PrettyNames && row->member->pretty_name.size != 0) - { - result = push_str8_copy(arena, row->member->pretty_name); - } - else - { - result = push_str8f(arena, ".%S", e_string_from_expr(arena, notable_expr->last)); - } - }break; + result = ev_type_key_and_mode_is_expandable(irtree.type_key, irtree.mode); } return result; } @@ -1256,29 +1080,9 @@ internal B32 ev_row_is_expandable(EV_Row *row) { B32 result = 0; + if(!ev_key_match(ev_key_root(), row->block->key)) { - // rjf: determine if view rules force expandability - if(!result) - { - for(EV_ViewRuleNode *n = row->view_rules->first; n != 0; n = n->next) - { - EV_ViewRuleInfo *info = ev_view_rule_info_from_string(n->v.root->string); - if(info->flags & EV_ViewRuleInfoFlag_Expandable) - { - result = 1; - break; - } - } - } - - // rjf: determine if type info force expandability - if(!result) - { - Temp scratch = scratch_begin(0, 0); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr); - result = ev_type_key_and_mode_is_expandable(irtree.type_key, irtree.mode); - scratch_end(scratch); - } + result = ev_eval_is_expandable(row->eval); } return result; } @@ -1287,10 +1091,8 @@ internal B32 ev_row_is_editable(EV_Row *row) { B32 result = 0; - Temp scratch = scratch_begin(0, 0); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, row->expr); + E_IRTreeAndType irtree = row->eval.irtree; result = ev_type_key_is_editable(irtree.type_key); - scratch_end(scratch); return result; } @@ -1479,14 +1281,14 @@ ev_string_from_hresult_code(U32 code) } internal String8 -ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, U32 min_digits, E_Eval eval) +ev_string_from_simple_typed_eval(Arena *arena, EV_StringParams *params, E_Eval eval) { String8 result = {0}; - E_TypeKey type_key = e_type_unwrap(eval.type_key); + E_TypeKey type_key = e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative & ~E_TypeUnwrapFlag_Enums); E_TypeKind type_kind = e_type_kind_from_key(type_key); U64 type_byte_size = e_type_byte_size_from_key(type_key); U8 digit_group_separator = 0; - if(!(flags & EV_StringFlag_ReadOnlyDisplayRules)) + if(!(params->flags & EV_StringFlag_ReadOnlyDisplayRules)) { digit_group_separator = 0; } @@ -1497,19 +1299,19 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, case E_TypeKind_Handle: { - result = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator); + result = str8_from_s64(arena, eval.value.s64, params->radix, params->min_digits, digit_group_separator); }break; case E_TypeKind_HResult: { - if(flags & EV_StringFlag_ReadOnlyDisplayRules) + if(params->flags & EV_StringFlag_ReadOnlyDisplayRules) { Temp scratch = scratch_begin(&arena, 1); U32 hresult_value = (U32)eval.value.u64; U32 is_error = !!(hresult_value & (1ull<<31)); U32 error_code = (hresult_value); U32 facility = (hresult_value & 0x7ff0000) >> 16; - String8 value_string = str8_from_s64(scratch.arena, eval.value.u64, radix, min_digits, digit_group_separator); + String8 value_string = str8_from_s64(scratch.arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator); String8 facility_string = ev_string_from_hresult_facility_code(facility); String8 error_string = ev_string_from_hresult_code(error_code); result = push_str8f(arena, "%S%s%s%S%s%s%S%s", @@ -1525,7 +1327,7 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, } else { - result = str8_from_s64(arena, eval.value.u64, radix, min_digits, digit_group_separator); + result = str8_from_s64(arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator); } }break; @@ -1537,14 +1339,18 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, 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); + String8 char_str = {0}; + if(!(params->flags & EV_StringFlag_DisableChars)) + { + char_str = ev_string_from_ascii_value(arena, eval.value.s64); + } if(char_str.size != 0) { - if(flags & EV_StringFlag_ReadOnlyDisplayRules) + if(params->flags & EV_StringFlag_ReadOnlyDisplayRules) { 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)); + ? str8_from_u64(arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator) + : str8_from_s64(arena, eval.value.s64, params->radix, params->min_digits, digit_group_separator)); result = push_str8f(arena, "'%S' (%S)", char_str, imm_string); } else @@ -1555,8 +1361,8 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, else { 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)); + ? str8_from_u64(arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator) + : str8_from_s64(arena, eval.value.s64, params->radix, params->min_digits, digit_group_separator)); } }break; @@ -1565,7 +1371,7 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, case E_TypeKind_S32: case E_TypeKind_S64: { - result = str8_from_s64(arena, eval.value.s64, radix, min_digits, digit_group_separator); + result = str8_from_s64(arena, eval.value.s64, params->radix, params->min_digits, digit_group_separator); }break; case E_TypeKind_U8: @@ -1573,14 +1379,14 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, case E_TypeKind_U32: case E_TypeKind_U64: { - result = str8_from_u64(arena, eval.value.u64, radix, min_digits, digit_group_separator); + result = str8_from_u64(arena, eval.value.u64, params->radix, params->min_digits, digit_group_separator); }break; case E_TypeKind_U128: { Temp scratch = scratch_begin(&arena, 1); - String8 upper64 = str8_from_u64(scratch.arena, eval.value.u128.u64[0], radix, min_digits, digit_group_separator); - String8 lower64 = str8_from_u64(scratch.arena, eval.value.u128.u64[1], radix, min_digits, digit_group_separator); + String8 upper64 = str8_from_u64(scratch.arena, eval.value.u128.u64[0], params->radix, params->min_digits, digit_group_separator); + String8 lower64 = str8_from_u64(scratch.arena, eval.value.u128.u64[1], params->radix, params->min_digits, digit_group_separator); result = push_str8f(arena, "%S:%S", upper64, lower64); scratch_end(scratch); }break; @@ -1589,7 +1395,7 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, case E_TypeKind_F64:{f64 = eval.value.f64;}goto f64_path; f64_path:; { - result = push_str8f(arena, "%.*f", min_digits ? min_digits : 16, f64); + result = push_str8f(arena, "%.*f", params->min_digits ? params->min_digits : 16, f64); U64 num_to_chop = 0; for(U64 num_trimmed = 0; num_trimmed < result.size; num_trimmed += 1) { @@ -1610,42 +1416,6 @@ ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, case E_TypeKind_LRef:{result = push_str8f(arena, "0x%I64x", eval.value.u64);}break; case E_TypeKind_RRef:{result = push_str8f(arena, "0x%I64x", eval.value.u64);}break; case E_TypeKind_Function:{result = push_str8f(arena, "0x%I64x", eval.value.u64);}break; - - case E_TypeKind_Enum: - { - Temp scratch = scratch_begin(&arena, 1); - E_Type *type = e_type_from_key(scratch.arena, type_key); - String8 constant_name = {0}; - for(U64 val_idx = 0; val_idx < type->count; val_idx += 1) - { - if(eval.value.u64 == type->enum_vals[val_idx].val) - { - constant_name = type->enum_vals[val_idx].name; - break; - } - } - String8 numeric_value_string = str8_from_u64(scratch.arena, eval.value.u64, radix, min_digits, digit_group_separator); - if(flags & EV_StringFlag_ReadOnlyDisplayRules) - { - if(constant_name.size != 0) - { - result = push_str8f(arena, "%S (%S)", numeric_value_string, constant_name); - } - else - { - result = push_str8_copy(arena, numeric_value_string); - } - } - else if(constant_name.size != 0) - { - result = push_str8_copy(arena, constant_name); - } - else - { - result = push_str8_copy(arena, numeric_value_string); - } - scratch_end(scratch); - }break; } return result; } @@ -1674,7 +1444,6 @@ ev_escaped_from_raw_string(Arena *arena, String8 raw) case '\v': {separator_replace = str8_lit("\\v");}break; case '\\': {separator_replace = str8_lit("\\\\");}break; case '"': {separator_replace = str8_lit("\\\"");}break; - case '?': {separator_replace = str8_lit("\\?");}break; } if(split) { @@ -1692,3 +1461,737 @@ ev_escaped_from_raw_string(Arena *arena, String8 raw) scratch_end(scratch); return result; } + +//- rjf: tree stringification iterator + +internal EV_StringIter * +ev_string_iter_begin(Arena *arena, E_Eval eval, EV_StringParams *params) +{ + EV_StringIter *it = push_array(arena, EV_StringIter, 1); + it->top_task = push_array(arena, EV_StringIterTask, 1); + it->top_task->eval = eval; + MemoryCopyStruct(&it->top_task->params, params); + return it; +} + +internal B32 +ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string) +{ + B32 result = 0; + + //- rjf: make progress on top task + MemoryZeroStruct(out_string); + B32 need_pop = 1; + B32 need_new_task = 0; + EV_StringIterTask new_task = {0}; + S32 top_task_depth = 0; + if(it->top_task != 0) + { + result = 1; + + //- rjf: unpack task + U64 task_idx = it->top_task->idx; + S32 depth = top_task_depth = it->top_task->depth; + EV_StringParams *params = &it->top_task->params; + E_Eval eval = it->top_task->eval; + E_TypeKey type_key = eval.irtree.type_key; + E_TypeKind type_kind = e_type_kind_from_key(type_key); + String8 expansion_opener_symbol = str8_lit("{"); + String8 expansion_closer_symbol = str8_lit("}"); + + //- rjf: type evaluations -> display type string + if(eval.irtree.mode == E_Mode_Null && !e_type_key_match(e_type_key_zero(), eval.irtree.type_key)) + { + *out_string = e_type_string_from_key(arena, type_key); + } + + //- rjf: non-type evaluations + else switch(type_kind) + { + ////////////////////////// + //- rjf: default - leaf cases + // + default: + { + E_Eval value_eval = e_value_eval_from_eval(eval); + *out_string = ev_string_from_simple_typed_eval(arena, params, value_eval); + }break; + + ////////////////////////// + //- rjf: enums + // + case E_TypeKind_Enum: + { + switch(task_idx) + { + default:{}break; + case 0: + { + E_Type *type = e_type_from_key(type_key); + E_Eval value_eval = e_value_eval_from_eval(eval); + String8 constant_name = {0}; + for(U64 val_idx = 0; val_idx < type->count; val_idx += 1) + { + if(value_eval.value.u64 == type->enum_vals[val_idx].val) + { + constant_name = type->enum_vals[val_idx].name; + break; + } + } + String8 sufficient_suffix = constant_name; + if(str8_match(sufficient_suffix, type->name, StringMatchFlag_RightSideSloppy)) + { + sufficient_suffix = str8_skip(sufficient_suffix, type->name.size); + if(str8_match(sufficient_suffix, str8_lit("_"), StringMatchFlag_RightSideSloppy)) + { + sufficient_suffix = str8_skip(sufficient_suffix, 1); + } + } + if(sufficient_suffix.size != 0) + { + *out_string = push_str8f(arena, "%S.%S", type->name, sufficient_suffix); + if(params->flags & EV_StringFlag_ReadOnlyDisplayRules) + { + need_pop = 0; + } + } + else + { + need_pop = 1; + need_new_task = 1; + new_task.params = *params; + new_task.eval = e_value_eval_from_eval(eval); + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + } + }break; + case 1: + { + *out_string = str8_lit(" ("); + need_pop = 0; + need_new_task = 1; + new_task.params = *params; + new_task.eval = e_value_eval_from_eval(eval); + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + }break; + case 2: + { + *out_string = str8_lit(")"); + }break; + } + }break; + + ////////////////////////// + //- rjf: lenses + // + case E_TypeKind_Lens: + { + if(it->top_task->redirect_to_sets_and_structs) + { + E_Type *type = e_type_from_key(type_key); + if(type->flags & E_TypeFlag_ArrayLikeExpansion) + { + expansion_opener_symbol = str8_lit("["); + expansion_closer_symbol = str8_lit("]"); + } + goto arrays_and_sets_and_structs; + } + E_Type *type = e_type_from_key(type_key); + E_TypeKind element_type_kind = e_type_kind_from_key(e_type_key_unwrap(type->direct_type_key, E_TypeUnwrapFlag_All)); + B32 lens_applied = 1; + EV_StringParams lens_params = *params; + if(0){} + else if(str8_match(type->name, str8_lit("bin"), 0)) { lens_params.radix = 2; } + else if(str8_match(type->name, str8_lit("oct"), 0)) { lens_params.radix = 8; } + else if(str8_match(type->name, str8_lit("dec"), 0)) { lens_params.radix = 10; } + else if(str8_match(type->name, str8_lit("hex"), 0)) { lens_params.radix = 16; } + else if(str8_match(type->name, str8_lit("digits"), 0) && type->count >= 1) + { + E_ParentKey(eval.key) + { + E_Value value = e_value_from_expr(type->args[0]); + lens_params.min_digits = value.u64; + } + } + else if(str8_match(type->name, str8_lit("no_string"), 0)) + { + lens_params.flags |= EV_StringFlag_DisableStrings; + } + else if(str8_match(type->name, str8_lit("no_char"), 0)) + { + lens_params.flags |= EV_StringFlag_DisableChars; + } + else if(str8_match(type->name, str8_lit("no_addr"), 0)) + { + lens_params.flags |= EV_StringFlag_DisableAddresses; + } + else if(str8_match(type->name, str8_lit("array"), 0) && + type->count >= 1 && + (((E_TypeKind_Char8 <= element_type_kind && element_type_kind <= E_TypeKind_UChar32) || + element_type_kind == E_TypeKind_S8 || + element_type_kind == E_TypeKind_U8))) + { + E_ParentKey(eval.key) + { + lens_params.limit_strings = 1; + lens_params.limit_strings_size = e_value_from_expr(type->args[0]).u64; + } + } + else + { + lens_applied = 0; + } + if(lens_applied) + { + need_new_task = 1; + need_pop = 1; + new_task.params = lens_params; + new_task.eval = eval; + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + } + else if(type->kind != E_TypeKind_Lens || type->expand.info != 0) + { + need_new_task = 1; + need_pop = 1; + new_task.params = *params; + new_task.eval = eval; + new_task.redirect_to_sets_and_structs = 1; + } + else + { + need_new_task = 1; + need_pop = 1; + new_task.params = lens_params; + new_task.eval = eval; + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); +#if 0 // NOTE(rjf): will explicitly visualize lenses in value strings. does not seem useful for now? + switch(task_idx) + { + default:{}break; + + // rjf: step 0 -> generate lens description, then descend to same evaluation w/ direct type + case 0: + { + Temp scratch = scratch_begin(&arena, 1); + String8List strings = {0}; + { + str8_list_pushf(scratch.arena, &strings, "%S(", type->name); + for EachIndex(idx, type->count) + { + String8 string = e_string_from_expr(scratch.arena, type->args[idx]); + str8_list_push(scratch.arena, &strings, string); + if(idx+1 < type->count) + { + str8_list_pushf(scratch.arena, &strings, ", "); + } + } + str8_list_pushf(scratch.arena, &strings, ") <- ("); + } + *out_string = str8_list_join(arena, &strings, 0); + need_new_task = 1; + need_pop = 0; + new_task.params = *params; + new_task.eval = eval; + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + scratch_end(scratch); + }break; + + // rjf: step 1 -> close + case 1: + { + *out_string = str8_lit(")"); + }break; + } +#endif + } + }break; + + ////////////////////////// + //- rjf: meta-expression tags + // + case E_TypeKind_MetaExpr: + { + if(params->flags & EV_StringFlag_ReadOnlyDisplayRules) + { + switch(task_idx) + { + default:{}break; + case 0: + { + E_Type *type = e_type_from_key(type_key); + *out_string = push_str8f(arena, "%S (", type->name); + need_pop = 0; + need_new_task = 1; + new_task.params = *params; + new_task.eval = eval; + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + }break; + case 1: + { + *out_string = str8_lit(")"); + }break; + } + } + else + { + E_Type *type = e_type_from_key(type_key); + *out_string = type->name; + } + }break; + + ////////////////////////// + //- rjf: modifiers / no-ops + // + case E_TypeKind_Modifier: + case E_TypeKind_MetaDescription: + case E_TypeKind_MetaDisplayName: + { + need_pop = 1; + need_new_task = 1; + new_task.params = *params; + new_task.eval = eval; + new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key); + }break; + + ////////////////////////// + //- rjf: pointers + // + case E_TypeKind_Function: + case E_TypeKind_Ptr: + case E_TypeKind_LRef: + case E_TypeKind_RRef: + case E_TypeKind_Array: + { + if(type_kind == E_TypeKind_Array && it->top_task->redirect_to_sets_and_structs) + { + expansion_opener_symbol = str8_lit("["); + expansion_closer_symbol = str8_lit("]"); + goto arrays_and_sets_and_structs; + } + typedef struct EV_StringPtrData EV_StringPtrData; + struct EV_StringPtrData + { + E_Eval value_eval; + E_Type *type; + E_Type *direct_type; + B32 ptee_has_content; + B32 ptee_has_string; + B32 did_prefix_content; + B32 did_redirect; + }; + EV_StringPtrData *ptr_data = it->top_task->user_data; + if(ptr_data == 0) + { + ptr_data = it->top_task->user_data = push_array(arena, EV_StringPtrData, 1); + ptr_data->value_eval = e_value_eval_from_eval(eval); + ptr_data->type = e_type_from_key(type_key); + ptr_data->direct_type = e_type_from_key(e_type_key_unwrap(type_key, E_TypeUnwrapFlag_All)); + ptr_data->ptee_has_content = (ptr_data->value_eval.value.u64 != 0 && ptr_data->direct_type->kind != E_TypeKind_Null && ptr_data->direct_type->kind != E_TypeKind_Void); + ptr_data->ptee_has_string = ((E_TypeKind_Char8 <= ptr_data->direct_type->kind && ptr_data->direct_type->kind <= E_TypeKind_UChar32) || + ptr_data->direct_type->kind == E_TypeKind_S8 || + ptr_data->direct_type->kind == E_TypeKind_U8); + } + if(ptr_data->did_redirect) + { + need_pop = 1; + } + else switch(task_idx) + { + default:{}break; + + //- rjf: step 0 -> try "prefix content", which we want to print before the pointer value, + // like strings or symbol names + case 0: + { + // rjf: try strings + if(!(ptr_data->type->flags & E_TypeFlag_IsNotText) && + !ptr_data->did_prefix_content && ptr_data->ptee_has_string && + !(params->flags & EV_StringFlag_DisableStrings) && + (type_kind == E_TypeKind_Array || + params->flags & EV_StringFlag_ReadOnlyDisplayRules)) + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: read string data +#define EV_STRING_ITER_STRING_BUFFER_CAPACITY 4096 + U64 string_buffer_size = EV_STRING_ITER_STRING_BUFFER_CAPACITY; + U8 *string_buffer = push_array(scratch.arena, U8, string_buffer_size); + if(type_kind == E_TypeKind_Array && eval.irtree.mode == E_Mode_Value) + { + StaticAssert(sizeof(eval.value.u512.u8) <= EV_STRING_ITER_STRING_BUFFER_CAPACITY, ev_string_iter_value_string_buffer_size_check); + MemoryCopy(string_buffer, eval.value.u512.u8, sizeof(eval.value.u512.u8)); + } + else + { + U64 string_memory_addr = ptr_data->value_eval.value.u64; + for(U64 try_size = string_buffer_size; try_size >= 16; try_size /= 2) + { + B32 read_good = e_space_read(eval.space, string_buffer, r1u64(string_memory_addr, string_memory_addr+try_size)); + if(read_good) + { + break; + } + } + string_buffer[string_buffer_size-1] = 0; + } + + // rjf: check element size - if non-U8, assume UTF-16 or UTF-32 based on type, and convert + U64 element_size = ptr_data->direct_type->byte_size; + String8 string = {0}; + switch(element_size) + { + default:{string = str8_cstring((char *)string_buffer);}break; + case 2: {string = str8_from_16(scratch.arena, str16_cstring((U16 *)string_buffer));}break; + case 4: {string = str8_from_32(scratch.arena, str32_cstring((U32 *)string_buffer));}break; + } + + // rjf: apply string size limitation + if(params->limit_strings) + { + string = str8_prefix(string, params->limit_strings_size); + } + + // rjf: escape and quote + B32 string__is_escaped_and_quoted = (!(params->flags & EV_StringFlag_DisableStringQuotes) || depth > 0); + String8 string__escaped_and_quoted = string; + if(string__is_escaped_and_quoted) + { + String8 string_escaped = ev_escaped_from_raw_string(scratch.arena, string); + string__escaped_and_quoted = push_str8f(scratch.arena, "\"%S\"", string_escaped); + } + + // rjf: report + *out_string = push_str8_copy(arena, string__escaped_and_quoted); + ptr_data->did_prefix_content = 1; + + scratch_end(scratch); + } + + // rjf: try symbols + if(!ptr_data->did_prefix_content) + { + U64 vaddr = ptr_data->value_eval.value.u64; + E_Module *module = &e_module_nil; + U32 module_idx = 0; + for EachIndex(idx, e_base_ctx->modules_count) + { + if(contains_1u64(e_base_ctx->modules[idx].vaddr_range, vaddr)) + { + module = &e_base_ctx->modules[idx]; + module_idx = (U32)idx; + break; + } + } + RDI_Parsed *rdi = module->rdi; + U64 voff = vaddr - module->vaddr_range.min; + B32 good_symbol_match = 0; + + // NOTE(rjf): read-only -> generate non-parseable things, like type-info / inlines + if(params->flags & EV_StringFlag_ReadOnlyDisplayRules) + { + // rjf: voff -> scope + U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); + + // rjf: scope -> # of max possible inline depth + U64 inline_site_count = 0; + for(U64 s_idx = scope_idx, s_idx_next = 0; s_idx != 0; s_idx = s_idx_next) + { + RDI_Scope *s = rdi_element_from_name_idx(rdi, Scopes, s_idx); + s_idx_next = s->parent_scope_idx; + if(s->inline_site_idx != 0) + { + inline_site_count += 1; + } + else + { + break; + } + } + + // rjf: depth in [1, max]? -> form name from inline site + if(0 < ptr_data->type->depth && ptr_data->type->depth <= inline_site_count) + { + RDI_InlineSite *inline_site = 0; + U64 s_inline_depth = inline_site_count; + for(U64 s_idx = scope_idx, s_idx_next = 0; s_idx != 0; s_idx = s_idx_next) + { + RDI_Scope *s = rdi_element_from_name_idx(rdi, Scopes, s_idx); + s_idx_next = s->parent_scope_idx; + if(s_inline_depth == ptr_data->type->depth) + { + inline_site = rdi_element_from_name_idx(rdi, InlineSites, s->inline_site_idx); + break; + } + s_inline_depth -= 1; + if(s_inline_depth == 0) + { + break; + } + } + if(inline_site != 0) + { + E_TypeKey type = e_type_key_ext(E_TypeKind_Function, inline_site->type_idx, module_idx); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size); + if(inline_site->type_idx != 0) + { + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + str8_list_pushf(scratch.arena, &list, "[inlined] "); + e_type_lhs_string_from_key(scratch.arena, type, &list, 0, 0); + str8_list_push(scratch.arena, &list, name); + e_type_rhs_string_from_key(scratch.arena, type, &list, 0); + *out_string = str8_list_join(arena, &list, 0); + scratch_end(scratch); + } + else + { + *out_string = push_str8_copy(arena, name); + } + good_symbol_match = (name.size != 0); + } + } + + // rjf: depth == 0 or depth >= max? -> form name from scope procedure + else + { + Temp scratch = scratch_begin(&arena, 1); + RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, scope_idx); + U64 proc_idx = scope->proc_idx; + RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, proc_idx); + E_TypeKey type = e_type_key_ext(E_TypeKind_Function, procedure->type_idx, module_idx); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); + if(procedure->type_idx != 0) + { + String8List list = {0}; + e_type_lhs_string_from_key(scratch.arena, type, &list, 0, 0); + str8_list_push(scratch.arena, &list, name); + e_type_rhs_string_from_key(scratch.arena, type, &list, 0); + *out_string = str8_list_join(arena, &list, 0); + } + else + { + *out_string = push_str8_copy(arena, name); + } + + good_symbol_match = (out_string->size != 0); + scratch_end(scratch); + } + + // rjf: if we have a function type, but we did not generate any name, then just put a ??? + if(out_string->size == 0 && e_type_kind_from_key(ptr_data->type->direct_type_key) == E_TypeKind_Function) + { + *out_string = str8_lit("???"); + good_symbol_match = 1; + } + } + + // NOTE(rjf): non-read-only -> only generate thing which can be parsed, so just procedure name + else + { + // rjf: voff -> scope + U64 scope_idx = rdi_vmap_idx_from_section_kind_voff(rdi, RDI_SectionKind_ScopeVMap, voff); + RDI_Scope *scope = rdi_scope_from_voff(rdi, voff); + + // rjf: scope -> procedure / string + RDI_Procedure *procedure = rdi_procedure_from_scope(rdi, scope); + String8 procedure_name = {0}; + procedure_name.str = rdi_name_from_procedure(rdi, procedure, &procedure_name.size); + + *out_string = procedure_name; + good_symbol_match = (procedure_name.size != 0); + } + + ptr_data->did_prefix_content = good_symbol_match; + } + + // rjf: if this is an array, and we do not have a prefix, then we need to + // generate a new task which redirects array types -> sets and structs. + if(type_kind == E_TypeKind_Array && !ptr_data->did_prefix_content) + { + need_new_task = 1; + need_pop = 0; + new_task.params = *params; + new_task.eval = eval; + new_task.redirect_to_sets_and_structs = 1; + ptr_data->did_redirect = 1; + } + + // rjf: if this is an array, and we *did* prefix content, then we are + // just done. + else if(type_kind == E_TypeKind_Array && ptr_data->did_prefix_content) + { + // NOTE(rjf): no-op, task is done. + } + + // rjf: otherwise, keep going on this task + else + { + need_pop = 0; + } + }break; + + //- rjf: step 1 -> do pointer value + descend if needed + case 1: + { + Temp scratch = scratch_begin(&arena, 1); + String8 ptr_value_string = str8_from_u64(scratch.arena, ptr_data->value_eval.value.u64, 16, 0, 0); + // + // NOTE(rjf): currently, we are not using the string-generation radix parameter when + // generating a pointer value - it is weird to want to change pointer value visualization + // to anything other than hex, so it is just not supported right now... + // + + // rjf: [read only] if we did prefix content, do a parenthesized pointer value + if(!(params->flags & EV_StringFlag_DisableAddresses) && params->flags & EV_StringFlag_ReadOnlyDisplayRules && ptr_data->did_prefix_content) + { + *out_string = push_str8f(arena, " (%S)", ptr_value_string); + } + + // rjf: [read only] if we did *not* do any prefix content, but we have content, + // do " -> " then descend + else if(params->flags & EV_StringFlag_ReadOnlyDisplayRules && !ptr_data->did_prefix_content && ptr_data->ptee_has_content) + { + if(!(params->flags & EV_StringFlag_DisableAddresses)) + { + *out_string = push_str8f(arena, "%S -> ", ptr_value_string); + } + + // rjf: single-length pointers -> just gen new task for deref'd expr + if(ptr_data->type->count == 1) + { + E_Eval deref_eval = e_eval_wrapf(eval, "*$"); + need_new_task = 1; + need_pop = 0; + new_task.params = *params; + new_task.eval = deref_eval; + } + + // rjf: multi-length pointers -> expand like an array (try to dedup with array case) + else + { + // TODO(rjf) + } + } + + // rjf: [writeable, catchall] if we did *not* do any prefix content, do "" + else if(!ptr_data->did_prefix_content) + { + *out_string = push_str8_copy(arena, ptr_value_string); + } + + scratch_end(scratch); + }break; + } + }break; + + ////////////////////////// + //- rjf: non-string-arrays/structs, sets + // + case E_TypeKind_Struct: + case E_TypeKind_Union: + case E_TypeKind_Class: + case E_TypeKind_IncompleteStruct: + case E_TypeKind_IncompleteUnion: + case E_TypeKind_IncompleteClass: + case E_TypeKind_Set: + arrays_and_sets_and_structs: + { + typedef struct EV_ExpandedTypeData EV_ExpandedTypeData; + struct EV_ExpandedTypeData + { + E_Type *type; + E_TypeExpandRule *expand_rule; + E_TypeExpandInfo expand_info; + }; + EV_ExpandedTypeData *expand_data = (EV_ExpandedTypeData *)it->top_task->user_data; + if(expand_data == 0) + { + expand_data = it->top_task->user_data = push_array(arena, EV_ExpandedTypeData, 1); + expand_data->type = e_type_from_key(type_key); + } + switch(task_idx) + { + //- rjf: step 0 -> generate opener symbol + case 0: + { + if(expand_data->type->flags & E_TypeFlag_StubSingleLineExpansion) + { + *out_string = push_str8f(arena, "%S...%S", expansion_opener_symbol, expansion_closer_symbol); + } + else + { + need_pop = 0; + expand_data->expand_rule = e_expand_rule_from_type_key(type_key); + expand_data->expand_info = expand_data->expand_rule->info(arena, eval, params->filter); + *out_string = expansion_opener_symbol; + } + }break; + + default: + //- rjf: last step -> generate closer symbol + if(task_idx == expand_data->expand_info.expr_count+1) + { + *out_string = expansion_closer_symbol; + } + + //- rjf: middle step -> generate new task for next thing in expansion + else + { + E_Eval next_eval = e_eval_nil; + expand_data->expand_rule->range(arena, expand_data->expand_info.user_data, eval, params->filter, r1u64(task_idx-1, task_idx), &next_eval); + if(next_eval.expr != &e_expr_nil) + { + need_new_task = 1; + need_pop = 0; + new_task.params = *params; + new_task.eval = next_eval; + if(task_idx > 1) + { + *out_string = str8_lit(", "); + } + } + else + { + need_pop = 0; + } + }break; + } + }break; + } + } + + //- rjf: bump task counter + if(it->top_task != 0) + { + it->top_task->idx += 1; + } + + //- rjf: if result is good, and we want to pop? -> pop + if(result && need_pop) + { + EV_StringIterTask *task = it->top_task; + SLLStackPop(it->top_task); + SLLStackPush(it->free_task, task); + } + + //- rjf: if result is good, and we have a new task? -> push + if(result && need_new_task) + { + EV_StringIterTask *new_t = it->free_task; + if(new_t != 0) + { + SLLStackPop(it->free_task); + } + else + { + new_t = push_array(arena, EV_StringIterTask, 1); + } + MemoryCopyStruct(new_t, &new_task); + new_t->depth = top_task_depth + 1*(!need_pop); + SLLStackPush(it->top_task, new_t); + new_t->idx = 0; + } + + return result; +} diff --git a/src/eval_visualization/eval_visualization_core.h b/src/eval_visualization/eval_visualization_core.h index 41b9d403..5f5a8d9d 100644 --- a/src/eval_visualization/eval_visualization_core.h +++ b/src/eval_visualization/eval_visualization_core.h @@ -75,31 +75,7 @@ struct EV_View }; //////////////////////////////// -//~ rjf: View Rule Instance Types - -typedef struct EV_ViewRule EV_ViewRule; -struct EV_ViewRule -{ - MD_Node *root; -}; - -typedef struct EV_ViewRuleNode EV_ViewRuleNode; -struct EV_ViewRuleNode -{ - EV_ViewRuleNode *next; - EV_ViewRule v; -}; - -typedef struct EV_ViewRuleList EV_ViewRuleList; -struct EV_ViewRuleList -{ - EV_ViewRuleNode *first; - EV_ViewRuleNode *last; - U64 count; -}; - -//////////////////////////////// -//~ rjf: View Rule Info Types +//~ rjf: Expansion Rule Types typedef struct EV_ExpandInfo EV_ExpandInfo; struct EV_ExpandInfo @@ -111,82 +87,46 @@ struct EV_ExpandInfo B32 rows_default_expanded; }; -typedef struct EV_ExpandRangeInfo EV_ExpandRangeInfo; -struct EV_ExpandRangeInfo -{ - U64 row_exprs_count; - String8 *row_strings; - String8 *row_view_rules; - E_Expr **row_exprs; - E_Member **row_members; -}; +#define EV_EXPAND_RULE_INFO_FUNCTION_SIG(name) EV_ExpandInfo name(Arena *arena, EV_View *view, String8 filter, E_Expr *expr) +#define EV_EXPAND_RULE_INFO_FUNCTION_NAME(name) ev_expand_rule_info__##name +#define EV_EXPAND_RULE_INFO_FUNCTION_DEF(name) internal EV_EXPAND_RULE_INFO_FUNCTION_SIG(EV_EXPAND_RULE_INFO_FUNCTION_NAME(name)) +typedef EV_EXPAND_RULE_INFO_FUNCTION_SIG(EV_ExpandRuleInfoHookFunctionType); -#define EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_SIG(name) E_Expr *name(Arena *arena, E_Expr *expr, MD_Node *params) -#define EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(name) ev_view_rule_expr_resolution__##name -#define EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(name) internal EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_SIG(EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(name)) - -#define EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_SIG(name) EV_ExpandInfo name(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params) -#define EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(name) ev_view_rule_expr_expand_info__##name -#define EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(name) internal EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_SIG(EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(name)) - -#define EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_SIG(name) EV_ExpandRangeInfo name(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data) -#define EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(name) ev_view_rule_expr_expand_range_info__##name -#define EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(name) internal EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_SIG(EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(name)) - -#define EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_SIG(name) U64 name(U64 num, void *user_data) -#define EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name) ev_view_rule_expr_expand_id_from_num_##name -#define EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(name) internal EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_SIG(EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(name)) - -#define EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_SIG(name) U64 name(U64 id, void *user_data) -#define EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name) ev_view_rule_expr_expand_num_from_id_##name -#define EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(name) internal EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_SIG(EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(name)) - -typedef EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_SIG(EV_ViewRuleExprResolutionHookFunctionType); -typedef EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_SIG(EV_ViewRuleExprExpandInfoHookFunctionType); -typedef EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_SIG(EV_ViewRuleExprExpandRangeInfoHookFunctionType); -typedef EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_SIG(EV_ViewRuleExprExpandIDFromNumHookFunctionType); -typedef EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_SIG(EV_ViewRuleExprExpandNumFromIDHookFunctionType); - -typedef U32 EV_ViewRuleInfoFlags; // NOTE(rjf): see @view_rule_info -enum -{ - EV_ViewRuleInfoFlag_Inherited = (1<<0), - EV_ViewRuleInfoFlag_Expandable = (1<<1), -}; - -typedef struct EV_ViewRuleInfo EV_ViewRuleInfo; -struct EV_ViewRuleInfo +typedef struct EV_ExpandRule EV_ExpandRule; +struct EV_ExpandRule { String8 string; - EV_ViewRuleInfoFlags flags; - EV_ViewRuleExprResolutionHookFunctionType *expr_resolution; - EV_ViewRuleExprExpandInfoHookFunctionType *expr_expand_info; - EV_ViewRuleExprExpandRangeInfoHookFunctionType *expr_expand_range_info; - EV_ViewRuleExprExpandIDFromNumHookFunctionType *expr_expand_id_from_num; - EV_ViewRuleExprExpandIDFromNumHookFunctionType *expr_expand_num_from_id; + EV_ExpandRuleInfoHookFunctionType *info; }; -typedef struct EV_ViewRuleInfoNode EV_ViewRuleInfoNode; -struct EV_ViewRuleInfoNode +typedef struct EV_ExpandRuleNode EV_ExpandRuleNode; +struct EV_ExpandRuleNode { - EV_ViewRuleInfoNode *next; - EV_ViewRuleInfo v; + EV_ExpandRuleNode *next; + EV_ExpandRule v; }; -typedef struct EV_ViewRuleInfoSlot EV_ViewRuleInfoSlot; -struct EV_ViewRuleInfoSlot +typedef struct EV_ExpandRuleSlot EV_ExpandRuleSlot; +struct EV_ExpandRuleSlot { - EV_ViewRuleInfoNode *first; - EV_ViewRuleInfoNode *last; + EV_ExpandRuleNode *first; + EV_ExpandRuleNode *last; }; -typedef struct EV_ViewRuleInfoTable EV_ViewRuleInfoTable; -struct EV_ViewRuleInfoTable +typedef struct EV_ExpandRuleTable EV_ExpandRuleTable; +struct EV_ExpandRuleTable { - EV_ViewRuleInfoSlot *slots; + EV_ExpandRuleSlot *slots; U64 slots_count; }; +typedef struct EV_ExpandRuleTagPair EV_ExpandRuleTagPair; +struct EV_ExpandRuleTagPair +{ + EV_ExpandRule *rule; + E_Expr *tag; +}; + //////////////////////////////// //~ rjf: Blocks @@ -206,18 +146,17 @@ struct EV_Block // rjf: split index, relative to parent's space U64 split_relative_idx; - // rjf: expression / visualization info + // rjf: evaluation info String8 string; - E_Expr *expr; - EV_ViewRuleList *view_rules; - EV_ViewRuleInfo *expand_view_rule_info; - MD_Node *expand_view_rule_params; - void *expand_view_rule_info_user_data; + E_Eval eval; + String8 filter; + E_TypeExpandInfo type_expand_info; + E_TypeExpandRule *type_expand_rule; + EV_ExpandInfo viz_expand_info; + EV_ExpandRule *viz_expand_rule; // rjf: expansion info U64 row_count; - B32 single_item; - B32 rows_default_expanded; }; typedef struct EV_BlockTree EV_BlockTree; @@ -256,66 +195,32 @@ struct EV_BlockRangeList typedef struct EV_Row EV_Row; struct EV_Row { - EV_Row *next; - - // rjf: block hierarchy info EV_Block *block; EV_Key key; - - // rjf: row size/scroll info U64 visual_size; + String8 edit_string; + E_Eval eval; +}; + +typedef struct EV_WindowedRowNode EV_WindowedRowNode; +struct EV_WindowedRowNode +{ + EV_WindowedRowNode *next; U64 visual_size_skipped; U64 visual_size_chopped; - - // rjf: expression / visualization info - String8 string; - E_Expr *expr; - E_Member *member; - EV_ViewRuleList *view_rules; + EV_Row row; }; typedef struct EV_WindowedRowList EV_WindowedRowList; struct EV_WindowedRowList { - EV_Row *first; - EV_Row *last; + EV_WindowedRowNode *first; + EV_WindowedRowNode *last; U64 count; U64 count_before_visual; U64 count_before_semantic; }; -//////////////////////////////// -//~ rjf: Automatic Type -> View Rule Map Types - -typedef struct EV_AutoViewRuleNode EV_AutoViewRuleNode; -struct EV_AutoViewRuleNode -{ - EV_AutoViewRuleNode *next; - E_TypeKey key; - String8 view_rule; - B32 is_required; -}; - -typedef struct EV_AutoViewRuleSlot EV_AutoViewRuleSlot; -struct EV_AutoViewRuleSlot -{ - EV_AutoViewRuleNode *first; - EV_AutoViewRuleNode *last; - U64 count; -}; - -typedef struct EV_AutoViewRuleTable EV_AutoViewRuleTable; -struct EV_AutoViewRuleTable -{ - EV_AutoViewRuleSlot *slots; - U64 slots_count; -}; - -//////////////////////////////// -//~ rjf: Generated Code - -#include "generated/eval_visualization.meta.h" - //////////////////////////////// //~ rjf: String Generation Types @@ -324,34 +229,74 @@ enum { EV_StringFlag_ReadOnlyDisplayRules = (1<<0), EV_StringFlag_PrettyNames = (1<<1), + EV_StringFlag_DisableAddresses = (1<<2), + EV_StringFlag_DisableStrings = (1<<3), + EV_StringFlag_DisableChars = (1<<4), + EV_StringFlag_DisableStringQuotes = (1<<5), +}; + +typedef struct EV_StringParams EV_StringParams; +struct EV_StringParams +{ + EV_StringFlags flags; + U32 radix; + U32 min_digits; + U8 digit_group_separator; + String8 filter; + B32 limit_strings; + U64 limit_strings_size; +}; + +typedef struct EV_StringIterTask EV_StringIterTask; +struct EV_StringIterTask +{ + EV_StringIterTask *next; + EV_StringParams params; + E_Eval eval; + U64 idx; + S32 depth; + B32 redirect_to_sets_and_structs; + void *user_data; +}; + +typedef struct EV_StringIter EV_StringIter; +struct EV_StringIter +{ + EV_StringIterTask *top_task; + EV_StringIterTask *free_task; }; //////////////////////////////// //~ rjf: Nil/Identity View Rule Hooks -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(identity); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(nil); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(nil); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(identity); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(identity); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(nil); //////////////////////////////// //~ rjf: Globals -global read_only EV_ViewRuleInfo ev_nil_view_rule_info = +global read_only EV_ExpandRule ev_nil_expand_rule = { {0}, - 0, - EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), - EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), - EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), - EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), - EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), + EV_EXPAND_RULE_INFO_FUNCTION_NAME(nil), +}; +thread_static EV_ExpandRuleTable *ev_view_rule_info_table = 0; +global read_only EV_Block ev_nil_block = +{ + &ev_nil_block, + &ev_nil_block, + &ev_nil_block, + &ev_nil_block, + &ev_nil_block, + {0}, + 0, + {0}, + {{0}, {0}, {0}, &e_expr_nil, &e_irnode_nil}, + {0}, + {0}, + &e_type_expand_rule__default, + {0}, + &ev_nil_expand_rule, }; -thread_static EV_ViewRuleInfoTable *ev_view_rule_info_table = 0; -global read_only EV_ViewRuleList ev_nil_view_rule_list = {0}; -thread_static EV_AutoViewRuleTable *ev_auto_view_rule_table = 0; -global read_only EV_Block ev_nil_block = {&ev_nil_block, &ev_nil_block, &ev_nil_block, &ev_nil_block, &ev_nil_block, {0}, 0, {0}, &e_expr_nil, &ev_nil_view_rule_list, &ev_nil_view_rule_info}; //////////////////////////////// //~ rjf: Key Functions @@ -367,6 +312,7 @@ internal U64 ev_hash_from_key(EV_Key key); //~ rjf: Type Info Helpers //- rjf: type info -> expandability/editablity +internal E_TypeKey ev_expansion_type_from_key(E_TypeKey type_key); internal B32 ev_type_key_and_mode_is_expandable(E_TypeKey type_key, E_Mode mode); internal B32 ev_type_key_is_editable(E_TypeKey type_key); @@ -387,54 +333,37 @@ internal void ev_key_set_view_rule(EV_View *view, EV_Key key, String8 view_rule_ //////////////////////////////// //~ rjf: View Rule Info Table Building / Selection / Lookups -internal void ev_view_rule_info_table_push(Arena *arena, EV_ViewRuleInfoTable *table, EV_ViewRuleInfo *info); -internal void ev_view_rule_info_table_push_builtins(Arena *arena, EV_ViewRuleInfoTable *table); -internal void ev_select_view_rule_info_table(EV_ViewRuleInfoTable *table); -internal EV_ViewRuleInfo *ev_view_rule_info_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Automatic Type -> View Rule Table Building / Selection / Lookups - -internal void ev_auto_view_rule_table_push_new(Arena *arena, EV_AutoViewRuleTable *table, E_TypeKey type_key, String8 view_rule, B32 is_required); -internal void ev_select_auto_view_rule_table(EV_AutoViewRuleTable *table); -internal EV_ViewRuleList *ev_auto_view_rules_from_type_key(Arena *arena, E_TypeKey type_key, B32 gather_required, B32 gather_optional); - -//////////////////////////////// -//~ rjf: View Rule Instance List Building - -internal void ev_view_rule_list_push_tree(Arena *arena, EV_ViewRuleList *list, MD_Node *root); -internal void ev_view_rule_list_push_string(Arena *arena, EV_ViewRuleList *list, String8 string); -internal EV_ViewRuleList *ev_view_rule_list_from_string(Arena *arena, String8 string); -internal EV_ViewRuleList *ev_view_rule_list_from_expr_fastpaths(Arena *arena, String8 string); -internal EV_ViewRuleList *ev_view_rule_list_from_inheritance(Arena *arena, EV_ViewRuleList *src); -internal EV_ViewRuleList *ev_view_rule_list_copy(Arena *arena, EV_ViewRuleList *src); -internal void ev_view_rule_list_concat_in_place(EV_ViewRuleList *dst, EV_ViewRuleList **src); - -//////////////////////////////// -//~ rjf: Expression Resolution (Dynamic Overrides, View Rule Application) - -internal E_Expr *ev_resolved_from_expr(Arena *arena, E_Expr *expr, EV_ViewRuleList *view_rules); +internal void ev_expand_rule_table_push(Arena *arena, EV_ExpandRuleTable *table, EV_ExpandRule *info); +#define ev_expand_rule_table_push_new(arena, table, ...) ev_expand_rule_table_push((arena), (table), &(EV_ExpandRule){__VA_ARGS__}) +internal void ev_select_expand_rule_table(EV_ExpandRuleTable *table); +internal EV_ExpandRule *ev_expand_rule_from_string(String8 string); +internal EV_ExpandRule *ev_expand_rule_from_type_key(E_TypeKey type_key); //////////////////////////////// //~ rjf: Block Building -internal EV_BlockTree ev_block_tree_from_expr(Arena *arena, EV_View *view, String8 filter, String8 string, E_Expr *expr, EV_ViewRuleList *view_rules); -internal EV_BlockTree ev_block_tree_from_string(Arena *arena, EV_View *view, String8 filter, String8 string, EV_ViewRuleList *view_rules); +internal EV_BlockTree ev_block_tree_from_eval(Arena *arena, EV_View *view, String8 filter, E_Eval root_eval); internal U64 ev_depth_from_block(EV_Block *block); //////////////////////////////// //~ rjf: Block Coordinate Spaces +internal U64 ev_block_id_from_num(EV_Block *block, U64 num); +internal U64 ev_block_num_from_id(EV_Block *block, U64 id); internal EV_BlockRangeList ev_block_range_list_from_tree(Arena *arena, EV_BlockTree *block_tree); internal EV_BlockRange ev_block_range_from_num(EV_BlockRangeList *block_ranges, U64 num); internal EV_Key ev_key_from_num(EV_BlockRangeList *block_ranges, U64 num); internal U64 ev_num_from_key(EV_BlockRangeList *block_ranges, EV_Key key); +internal U64 ev_vnum_from_num(EV_BlockRangeList *block_ranges, U64 num); +internal U64 ev_num_from_vnum(EV_BlockRangeList *block_ranges, U64 vidx); //////////////////////////////// //~ rjf: Row Building -internal EV_WindowedRowList ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, String8 filter, EV_BlockRangeList *block_ranges, Rng1U64 visible_range); -internal String8 ev_expr_string_from_row(Arena *arena, EV_Row *row, EV_StringFlags flags); +internal EV_WindowedRowList ev_windowed_row_list_from_block_range_list(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, Rng1U64 vnum_range); +internal EV_Row *ev_row_from_num(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, U64 num); +internal EV_WindowedRowList ev_rows_from_num_range(Arena *arena, EV_View *view, EV_BlockRangeList *block_ranges, Rng1U64 num_range); +internal B32 ev_eval_is_expandable(E_Eval eval); internal B32 ev_row_is_expandable(EV_Row *row); internal B32 ev_row_is_editable(EV_Row *row); @@ -445,7 +374,11 @@ internal B32 ev_row_is_editable(EV_Row *row); internal String8 ev_string_from_ascii_value(Arena *arena, U8 val); internal String8 ev_string_from_hresult_facility_code(U32 code); internal String8 ev_string_from_hresult_code(U32 code); -internal String8 ev_string_from_simple_typed_eval(Arena *arena, EV_StringFlags flags, U32 radix, U32 min_digits, E_Eval eval); +internal String8 ev_string_from_simple_typed_eval(Arena *arena, EV_StringParams *params, E_Eval eval); internal String8 ev_escaped_from_raw_string(Arena *arena, String8 raw); +//- rjf: tree stringification iterator +internal EV_StringIter *ev_string_iter_begin(Arena *arena, E_Eval eval, EV_StringParams *params); +internal B32 ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string); + #endif // EVAL_VISUALIZATION_CORE_H diff --git a/src/eval_visualization/eval_visualization_inc.c b/src/eval_visualization/eval_visualization_inc.c index 44e7f6cb..d944d937 100644 --- a/src/eval_visualization/eval_visualization_inc.c +++ b/src/eval_visualization/eval_visualization_inc.c @@ -2,4 +2,3 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "eval_visualization_core.c" -#include "eval_visualization_builtin_view_rules.c" diff --git a/src/eval_visualization/eval_visualization_inc.h b/src/eval_visualization/eval_visualization_inc.h index 2e01e21a..11c9b212 100644 --- a/src/eval_visualization/eval_visualization_inc.h +++ b/src/eval_visualization/eval_visualization_inc.h @@ -5,6 +5,5 @@ #define EVAL_VISUALIZATION_INC_H #include "eval_visualization_core.h" -#include "eval_visualization_builtin_view_rules.h" #endif // EVAL_VISUALIZATION_INC_H diff --git a/src/eval_visualization/generated/eval_visualization.meta.c b/src/eval_visualization/generated/eval_visualization.meta.c deleted file mode 100644 index ad7776d0..00000000 --- a/src/eval_visualization/generated/eval_visualization.meta.c +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//- GENERATED CODE - -C_LINKAGE_BEGIN -EV_ViewRuleInfo ev_builtin_view_rule_info_table[14] = -{ -{str8_lit_comp("default"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(default) , EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(default) , EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("array"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(array) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("list"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(list) , EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(list) , EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("slice"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(slice) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("bswap"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(bswap) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("cast"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(cast) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("wrap"), (EV_ViewRuleInfoFlag_Inherited*0)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(wrap) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("only"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(only) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("omit"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(omit) , EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("bin"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("oct"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("dec"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("hex"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -{str8_lit_comp("no_addr"), (EV_ViewRuleInfoFlag_Inherited*1)|(EV_ViewRuleInfoFlag_Expandable*0), EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil), EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity) }, -}; - -C_LINKAGE_END - diff --git a/src/eval_visualization/generated/eval_visualization.meta.h b/src/eval_visualization/generated/eval_visualization.meta.h deleted file mode 100644 index da13d9b4..00000000 --- a/src/eval_visualization/generated/eval_visualization.meta.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//- GENERATED CODE - -#ifndef EVAL_VISUALIZATION_META_H -#define EVAL_VISUALIZATION_META_H - -typedef enum EV_ViewRuleKind -{ -EV_ViewRuleKind_Default, -EV_ViewRuleKind_Array, -EV_ViewRuleKind_List, -EV_ViewRuleKind_Slice, -EV_ViewRuleKind_ByteSwap, -EV_ViewRuleKind_Cast, -EV_ViewRuleKind_Wrap, -EV_ViewRuleKind_Only, -EV_ViewRuleKind_Omit, -EV_ViewRuleKind_Bin, -EV_ViewRuleKind_Oct, -EV_ViewRuleKind_Dec, -EV_ViewRuleKind_Hex, -EV_ViewRuleKind_NoAddress, -EV_ViewRuleKind_COUNT, -} EV_ViewRuleKind; - -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(array); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(slice); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(bswap); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(cast); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(wrap); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(only); -EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_DEF(omit); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(default); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(list); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(default); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(list); -#endif // EVAL_VISUALIZATION_META_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index cd161dd8..feb6d815 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xfffa00ff + //////////////////////////////// //~ rjf: Basic Helpers @@ -68,158 +71,158 @@ fs_change_gen(void) //////////////////////////////// //~ rjf: Cache Interaction -internal U128 -fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) +internal HS_Key +fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us) { Temp scratch = scratch_begin(0, 0); //- rjf: unpack args path = path_normalized_from_string(scratch.arena, path); - U128 key = fs_big_hash_from_string_range(path, range); + U64 path_little_hash = fs_little_hash_from_string(path); + U64 path_slot_idx = path_little_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: loop through key -> hash history; obtain most recent hash for this key - U128 result = {0}; - for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) + //- rjf: get root for this path + HS_Root root = {0}; + OS_MutexScopeR(path_stripe->rw_mutex) { - result = hs_hash_from_key(key, rewind_idx); - - //- rjf: nonzero hash -> got valid results, return - if(!u128_match(result, u128_zero())) + B32 node_found = 0; + for(FS_Node *n = path_slot->first; n != 0; n = n->next) { - break; - } - - //- rjf: zero hash, not rewound? -> send new stream request if needed - else if(u128_match(result, u128_zero()) && rewind_idx == 0) - { - // rjf: unpack path cache info - U64 path_little_hash = fs_little_hash_from_string(path); - U64 path_slot_idx = path_little_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: loop: request, check for results, return until we can't - OS_MutexScopeW(path_stripe->rw_mutex) for(;;) + if(str8_match(n->path, path, 0)) { - // rjf: path -> node - FS_Node *node = 0; - for(FS_Node *n = path_slot->first; n != 0; n = n->next) - { - if(str8_match(path, n->path, 0)) - { - node = n; - break; - } - } - - // rjf: node does not exist? -> create & store - 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); - } - - // rjf: range -> node - 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; - } - } - - // rjf: range node does not exist? create & store - 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; - } - - // rjf: try to send stream request - 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_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 - result = hs_hash_from_key(key, 0); - - // 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_w(path_stripe->cv, path_stripe->rw_mutex, endt_us); - } - else + node_found = 1; + root = n->root; + break; + } + } + if(!node_found) OS_MutexScopeRWPromote(path_stripe->rw_mutex) + { + B32 node_found = 0; + for(FS_Node *n = path_slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0)) { + node_found = 1; + root = n->root; break; } } + if(!node_found) + { + FS_Node *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->root = hs_root_alloc(); + node->slots_count = 64; + node->slots = push_array(path_stripe->arena, FS_RangeSlot, node->slots_count); + root = node->root; + } } } - scratch_end(scratch); - return result; -} - -internal U128 -fs_key_from_path_range(String8 path, Rng1U64 range) -{ - Temp scratch = scratch_begin(0, 0); - String8 path_normalized = path_normalized_from_string(scratch.arena, path); - U128 key = fs_big_hash_from_string_range(path_normalized, range); - fs_hash_from_path_range(path_normalized, range, 0); - scratch_end(scratch); - return key; -} - -internal U64 -fs_timestamp_from_path(String8 path) -{ - Temp scratch = scratch_begin(0, 0); - U64 result = 0; - path = path_normalized_from_string(scratch.arena, path); - U64 path_hash = fs_little_hash_from_string(path); - U64 slot_idx = path_hash%fs_shared->slots_count; - U64 stripe_idx = slot_idx%fs_shared->stripes_count; - FS_Slot *slot = &fs_shared->slots[slot_idx]; - FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + //- rjf: build a key for this path/range combo + HS_Key key = hs_key_make(root, hs_id_make(range.min, range.max)); + + //- rjf: if the most recent hash for this key is zero, then try to submit a new + // request to pull it in. + if(u128_match(hs_hash_from_key(key, 0), u128_zero())) { - for(FS_Node *n = slot->first; n != 0; n = n->next) + // rjf: loop: request, check for results, return until we can't + OS_MutexScopeW(path_stripe->rw_mutex) for(;;) { - if(str8_match(path, n->path, 0)) + // rjf: path -> node + FS_Node *node = 0; + for(FS_Node *n = path_slot->first; n != 0; n = n->next) + { + if(str8_match(path, n->path, 0)) + { + node = n; + break; + } + } + + // rjf: no node? -> weird case, node should've been made at this point. + if(node == 0) + { + break; + } + + // rjf: range -> node + U64 range_hash = fs_little_hash_from_string(str8_struct(&key.id)); + 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(hs_id_match(n->id, key.id)) + { + range_node = n; + break; + } + } + + // rjf: range node does not exist? create & store + 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->id = key.id; + } + + // rjf: try to send stream request + if(ins_atomic_u64_eval(&range_node->working_count) == 0 && + fs_u2s_enqueue_req(key, range, path, endt_us)) + { + ins_atomic_u64_inc_eval(&range_node->working_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, .working_counter = &range_node->working_count); + } + } + + // rjf: have time to wait? -> wait on this stripe; otherwise exit + B32 have_results = !u128_match(hs_hash_from_key(key, 0), u128_zero()); + if(!have_results && os_now_microseconds() < endt_us) + { + os_condition_variable_wait_rw_w(path_stripe->cv, path_stripe->rw_mutex, endt_us); + } + else { - result = n->timestamp; break; } } } + scratch_end(scratch); - return result; + return key; } -internal U64 -fs_size_from_path(String8 path) +internal U128 +fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us) +{ + U128 hash = {0}; + { + HS_Key key = fs_key_from_path_range(path, range, endt_us); + for EachIndex(rewind_idx, HS_KEY_HASH_HISTORY_COUNT) + { + hash = hs_hash_from_key(key, rewind_idx); + if(!u128_match(hash, u128_zero())) + { + break; + } + } + } + return hash; +} + +internal FileProperties +fs_properties_from_path(String8 path) { Temp scratch = scratch_begin(0, 0); - U64 result = 0; + FileProperties result = {0}; path = path_normalized_from_string(scratch.arena, path); U64 path_hash = fs_little_hash_from_string(path); U64 slot_idx = path_hash%fs_shared->slots_count; @@ -232,7 +235,7 @@ fs_size_from_path(String8 path) { if(str8_match(path, n->path, 0)) { - result = n->size; + result = n->props; break; } } @@ -245,7 +248,7 @@ fs_size_from_path(String8 path) //~ rjf: Streamer Threads internal B32 -fs_u2s_enqueue_req(Rng1U64 range, String8 path, U64 endt_us) +fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us) { B32 result = 0; path.size = Min(path.size, fs_shared->u2s_ring_size); @@ -253,10 +256,11 @@ 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; - U64 needed_size = sizeof(range.min) + sizeof(range.max) + sizeof(path.size) + path.size; + U64 needed_size = sizeof(key) + 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, &key); 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); @@ -273,13 +277,14 @@ 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) +fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out) { OS_MutexScope(fs_shared->u2s_ring_mutex) for(;;) { U64 unconsumed_size = fs_shared->u2s_ring_write_pos - fs_shared->u2s_ring_read_pos; - if(unconsumed_size >= sizeof(U64)) + if(unconsumed_size >= sizeof(*key_out) + sizeof(U64)*2 + sizeof(U64)) { + 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, key_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, &range_out->min); 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, &range_out->max); 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); @@ -298,12 +303,12 @@ ASYNC_WORK_DEF(fs_stream_work) Temp scratch = scratch_begin(0, 0); //- rjf: get next request + HS_Key key = {0}; Rng1U64 range = {0}; String8 path = {0}; - fs_u2s_dequeue_req(scratch.arena, &range, &path); + fs_u2s_dequeue_req(scratch.arena, &key, &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; @@ -314,8 +319,9 @@ ASYNC_WORK_DEF(fs_stream_work) 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); + U64 read_size = Min(pre_props.size - range.min, range_size); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); + B32 file_handle_is_valid = !os_handle_match(os_handle_zero(), file); U64 data_arena_size = read_size+ARENA_HEADER_SIZE; data_arena_size += KB(4)-1; data_arena_size -= data_arena_size%KB(4); @@ -328,8 +334,12 @@ ASYNC_WORK_DEF(fs_stream_work) 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) + //- rjf: abort if modification timestamps or sizes differ - we did not successfully read the file + B32 read_good = (pre_props.modified == post_props.modified && + pre_props.size == post_props.size && + read_size == data.size && + (file_handle_is_valid || pre_props.flags & FilePropertyFlag_IsFolder)); + if(!read_good) { ProfScope("abort") { @@ -360,29 +370,13 @@ ASYNC_WORK_DEF(fs_stream_work) break; } } - if(node != 0) + if(node != 0 && read_good) { - if(node->timestamp != 0) + if(node->props.modified != 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; - } - } + node->props = post_props; } } os_condition_variable_broadcast(path_stripe->cv); @@ -413,7 +407,7 @@ fs_detector_thread__entry_point(void *p) for(FS_Node *n = slot->first; n != 0; n = n->next) { FileProperties props = os_properties_from_file_path(n->path); - if(props.modified != n->timestamp) + if(props.modified != n->props.modified) { for(U64 range_slot_idx = 0; range_slot_idx < n->slots_count; range_slot_idx += 1) { @@ -421,12 +415,12 @@ fs_detector_thread__entry_point(void *p) range_n != 0; range_n = range_n->next) { - 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)) + HS_Key key = hs_key_make(n->root, range_n->id); + if(ins_atomic_u64_eval(&range_n->working_count) == 0 && + fs_u2s_enqueue_req(key, r1u64(key.id.u128[0].u64[0], key.id.u128[0].u64[1]), n->path, os_now_microseconds()+100000)) { - 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); + ins_atomic_u64_inc_eval(&range_n->working_count); + async_push_work(fs_stream_work, .working_counter = &range_n->working_count); } } } diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 80b1e34a..a0ede57c 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -11,10 +11,8 @@ typedef struct FS_RangeNode FS_RangeNode; struct FS_RangeNode { FS_RangeNode *next; - Rng1U64 range; - U64 request_count; - U64 completion_count; - U64 last_time_requested_us; + HS_ID id; + U64 working_count; }; typedef struct FS_RangeSlot FS_RangeSlot; @@ -31,8 +29,10 @@ struct FS_Node // rjf: file metadata String8 path; - U64 timestamp; - U64 size; + FileProperties props; + + // rjf: hash store root + HS_Root root; // rjf: sub-table of per-requested-file-range info U64 slots_count; @@ -105,17 +105,15 @@ internal U64 fs_change_gen(void); //////////////////////////////// //~ rjf: Cache Interaction +internal HS_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us); internal U128 fs_hash_from_path_range(String8 path, Rng1U64 range, U64 endt_us); -internal U128 fs_key_from_path_range(String8 path, Rng1U64 range); - -internal U64 fs_timestamp_from_path(String8 path); -internal U64 fs_size_from_path(String8 path); +internal FileProperties fs_properties_from_path(String8 path); //////////////////////////////// //~ 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 B32 fs_u2s_enqueue_req(HS_Key key, Rng1U64 range, String8 path, U64 endt_us); +internal void fs_u2s_dequeue_req(Arena *arena, HS_Key *key_out, Rng1U64 *range_out, String8 *path_out); ASYNC_WORK_DEF(fs_stream_work); //////////////////////////////// diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index f302dd22..44fea4d1 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -24,9 +24,9 @@ fnt_hash_from_string(String8 string) } internal U64 -fnt_little_hash_from_string(String8 string) +fnt_little_hash_from_string(U64 seed, String8 string) { - U64 result = XXH3_64bits(string.str, string.size); + U64 result = XXH3_64bits_withSeed(string.str, string.size, seed); return result; } @@ -65,10 +65,10 @@ internal FP_Handle fnt_handle_from_tag(FNT_Tag tag) { ProfBeginFunction(); - U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + U64 slot_idx = tag.u64[1] % fnt_state->font_hash_table_size; FNT_FontHashNode *existing_node = 0; { - for(FNT_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + for(FNT_FontHashNode *n = fnt_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) { if(MemoryMatchStruct(&tag, &n->tag)) { @@ -90,10 +90,10 @@ internal FP_Metrics fnt_fp_metrics_from_tag(FNT_Tag tag) { ProfBeginFunction(); - U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + U64 slot_idx = tag.u64[1] % fnt_state->font_hash_table_size; FNT_FontHashNode *existing_node = 0; { - for(FNT_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + for(FNT_FontHashNode *n = fnt_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) { if(MemoryMatchStruct(&tag, &n->tag)) { @@ -125,12 +125,12 @@ fnt_tag_from_path(String8 path) } //- rjf: tag -> slot index - U64 slot_idx = result.u64[1] % f_state->font_hash_table_size; + U64 slot_idx = result.u64[1] % fnt_state->font_hash_table_size; //- rjf: slot * tag -> existing node FNT_FontHashNode *existing_node = 0; { - for(FNT_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + for(FNT_FontHashNode *n = fnt_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) { if(MemoryMatchStruct(&result, &n->tag)) { @@ -141,16 +141,22 @@ fnt_tag_from_path(String8 path) } //- rjf: allocate & push new node if we don't have an existing one - FNT_FontHashNode *new_node = 0; if(existing_node == 0) { - FNT_FontHashSlot *slot = &f_state->font_hash_table[slot_idx]; - new_node = push_array(f_state->permanent_arena, FNT_FontHashNode, 1); - new_node->tag = result; - new_node->handle = fp_font_open(path); - new_node->metrics = fp_metrics_from_font(new_node->handle); - new_node->path = push_str8_copy(f_state->permanent_arena, path); - SLLQueuePush_N(slot->first, slot->last, new_node, hash_next); + FP_Handle handle = fp_font_open(path); + FNT_FontHashSlot *slot = &fnt_state->font_hash_table[slot_idx]; + existing_node = push_array(fnt_state->permanent_arena, FNT_FontHashNode, 1); + existing_node->tag = result; + existing_node->handle = handle; + existing_node->metrics = fp_metrics_from_font(existing_node->handle); + existing_node->path = push_str8_copy(fnt_state->permanent_arena, path); + SLLQueuePush_N(slot->first, slot->last, existing_node, hash_next); + } + + //- rjf: tag result must be zero if this is not a valid font + if(fp_handle_match(existing_node->handle, fp_handle_zero())) + { + MemoryZeroStruct(&result); } //- rjf: return @@ -172,12 +178,12 @@ fnt_tag_from_static_data_string(String8 *data_ptr) } //- rjf: tag -> slot index - U64 slot_idx = result.u64[1] % f_state->font_hash_table_size; + U64 slot_idx = result.u64[1] % fnt_state->font_hash_table_size; //- rjf: slot * tag -> existing node FNT_FontHashNode *existing_node = 0; { - for(FNT_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + for(FNT_FontHashNode *n = fnt_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) { if(MemoryMatchStruct(&result, &n->tag)) { @@ -191,8 +197,8 @@ fnt_tag_from_static_data_string(String8 *data_ptr) FNT_FontHashNode *new_node = 0; if(existing_node == 0) { - FNT_FontHashSlot *slot = &f_state->font_hash_table[slot_idx]; - new_node = push_array(f_state->permanent_arena, FNT_FontHashNode, 1); + FNT_FontHashSlot *slot = &fnt_state->font_hash_table[slot_idx]; + new_node = push_array(fnt_state->permanent_arena, FNT_FontHashNode, 1); new_node->tag = result; new_node->handle = fp_font_open_from_static_data_string(data_ptr); new_node->metrics = fp_metrics_from_font(new_node->handle); @@ -209,12 +215,12 @@ internal String8 fnt_path_from_tag(FNT_Tag tag) { //- rjf: tag -> slot index - U64 slot_idx = tag.u64[1] % f_state->font_hash_table_size; + U64 slot_idx = tag.u64[1] % fnt_state->font_hash_table_size; //- rjf: slot * tag -> existing node FNT_FontHashNode *existing_node = 0; { - for(FNT_FontHashNode *n = f_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) + for(FNT_FontHashNode *n = fnt_state->font_hash_table[slot_idx].first; n != 0 ; n = n->hash_next) { if(MemoryMatchStruct(&tag, &n->tag)) { @@ -514,7 +520,7 @@ fnt_piece_array_copy(Arena *arena, FNT_PieceArray *src) } //////////////////////////////// -//~ rjf: Rasterization Cache +//~ rjf: Cache Usage internal FNT_Hash2StyleRasterCacheNode * fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) @@ -530,15 +536,15 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) *(U64 *)(&size_f64), (U64)flags, }; - style_hash = fnt_little_hash_from_string(str8((U8 *)buffer, sizeof(buffer))); + style_hash = fnt_little_hash_from_string(5381, str8((U8 *)buffer, sizeof(buffer))); } //- rjf: style hash -> style node FNT_Hash2StyleRasterCacheNode *hash2style_node = 0; { ProfBegin("style hash -> style node"); - U64 slot_idx = style_hash%f_state->hash2style_slots_count; - FNT_Hash2StyleRasterCacheSlot *slot = &f_state->hash2style_slots[slot_idx]; + U64 slot_idx = style_hash%fnt_state->hash2style_slots_count; + FNT_Hash2StyleRasterCacheSlot *slot = &fnt_state->hash2style_slots[slot_idx]; for(FNT_Hash2StyleRasterCacheNode *n = slot->first; n != 0; n = n->hash_next) @@ -552,14 +558,14 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) if(Unlikely(hash2style_node == 0)) { FNT_Metrics metrics = fnt_metrics_from_tag_size(tag, size); - hash2style_node = push_array(f_state->raster_arena, FNT_Hash2StyleRasterCacheNode, 1); + hash2style_node = push_array(fnt_state->raster_arena, FNT_Hash2StyleRasterCacheNode, 1); DLLPushBack_NP(slot->first, slot->last, hash2style_node, hash_next, hash_prev); hash2style_node->style_hash = style_hash; - hash2style_node->ascent = metrics.ascent; - hash2style_node->descent= metrics.descent; - hash2style_node->utf8_class1_direct_map = push_array_no_zero(f_state->raster_arena, F_RasterCacheInfo, 256); + hash2style_node->ascent = metrics.ascent; + hash2style_node->descent = metrics.descent; + hash2style_node->utf8_class1_direct_map = push_array_no_zero(fnt_state->raster_arena, FNT_RasterCacheInfo, 256); hash2style_node->hash2info_slots_count = 1024; - hash2style_node->hash2info_slots = push_array(f_state->raster_arena, FNT_Hash2InfoRasterCacheSlot, hash2style_node->hash2info_slots_count); + hash2style_node->hash2info_slots = push_array(fnt_state->raster_arena, FNT_Hash2InfoRasterCacheSlot, hash2style_node->hash2info_slots_count); } ProfEnd(); } @@ -568,281 +574,328 @@ fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags) } internal FNT_Run -fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, String8 string) +fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, String8 string) { ProfBeginFunction(); //- rjf: map tag/size to style node FNT_Hash2StyleRasterCacheNode *hash2style_node = fnt_hash2style_from_tag_size_flags(tag, size, flags); - //- rjf: decode string & produce run pieces - 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; - U64 piece_substring_end_idx = 0; - for(U64 idx = 0; idx <= string.size;) + //- rjf: set up this style's run cache if needed + if(hash2style_node->run_slots_frame_index != fnt_state->frame_index) { - //- rjf: decode next codepoint & get piece substring, or continuation rule - U8 byte = (idx < string.size ? string.str[idx] : 0); - B32 need_another_codepoint = 0; - if(byte == 0) + hash2style_node->run_slots_count = 1024; + hash2style_node->run_slots = push_array(fnt_state->frame_arena, FNT_RunCacheSlot, hash2style_node->run_slots_count); + hash2style_node->run_slots_frame_index = fnt_state->frame_index; + } + + //- rjf: unpack run params + U64 run_hash = fnt_little_hash_from_string(5381, string); + U64 run_slot_idx = run_hash%hash2style_node->run_slots_count; + FNT_RunCacheSlot *run_slot = &hash2style_node->run_slots[run_slot_idx]; + + //- rjf: find existing run node for this string + FNT_RunCacheNode *run_node = 0; + { + for(FNT_RunCacheNode *n = run_slot->first; n != 0; n = n->next) { - idx += 1; - } - else switch(utf8_class[byte>>3]) - { - case 1: + if(str8_match(n->string, string, 0)) { - 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; - piece_substring_end_idx += decode.inc; - need_another_codepoint = 0; - }break; - } - - //- 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? -> 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'); - if(is_tab) - { - piece_substring = str8_lit(" "); - } - - //- rjf: piece substring -> raster cache info - F_RasterCacheInfo *info = 0; - U64 piece_hash = 0; - { - // rjf: fast path for utf8 class 1 -> direct map - if(piece_substring.size == 1 && hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] & (1ull<<(piece_substring.str[0]%64))) - { - info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; - } - - // rjf: more general, slower path for other glyphs - if(piece_substring.size > 1) - { - piece_hash = fnt_little_hash_from_string(piece_substring); - U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; - FNT_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; - for(F_Hash2InfoRasterCacheNode *node = slot->first; node != 0; node = node->hash_next) - { - if(node->hash == piece_hash) - { - info = &node->info; - break; - } - } - } - } - - //- rjf: no info found -> miss... fill this hash in the cache - if(info == 0) - { - ProfBegin("no info found -> miss... fill this hash in the cache"); - Temp scratch = scratch_begin(&arena, 1); - - // rjf: grab font handle for this tag if we don't have one already - if(font_handle_mapped_on_miss == 0) - { - font_handle_mapped_on_miss = 1; - - // rjf: tag -> font slot index - U64 font_slot_idx = tag.u64[1] % f_state->font_hash_table_size; - - // rjf: tag * slot -> existing node - FNT_FontHashNode *existing_node = 0; - { - for(FNT_FontHashNode *n = f_state->font_hash_table[font_slot_idx].first; n != 0 ; n = n->hash_next) - { - if(MemoryMatchStruct(&n->tag, &tag)) - { - existing_node = n; - break; - } - } - } - - // rjf: existing node -> font handle - if(existing_node != 0) - { - font_handle = existing_node->handle; - } - } - - // rjf: call into font provider to rasterize this substring - FP_RasterResult raster = {0}; - if(size > 0) - { - FP_RasterFlags fp_flags = 0; - if(flags & FNT_RasterFlag_Smooth) { fp_flags |= FP_RasterFlag_Smooth; } - if(flags & FNT_RasterFlag_Hinted) { fp_flags |= FP_RasterFlag_Hinted; } - raster = fp_raster(scratch.arena, font_handle, floor_f32(size), flags, piece_substring); - } - - // rjf: allocate portion of an atlas to upload the rasterization - S16 chosen_atlas_num = 0; - FNT_Atlas *chosen_atlas = 0; - Rng2S16 chosen_atlas_region = {0}; - if(raster.atlas_dim.x != 0 && raster.atlas_dim.y != 0) - { - U64 num_atlases = 0; - for(FNT_Atlas *atlas = f_state->first_atlas;; atlas = atlas->next, num_atlases += 1) - { - // rjf: create atlas if needed - if(atlas == 0 && num_atlases < 64) - { - atlas = push_array(f_state->raster_arena, FNT_Atlas, 1); - DLLPushBack(f_state->first_atlas, f_state->last_atlas, atlas); - atlas->root_dim = v2s16(1024, 1024); - atlas->root = push_array(f_state->raster_arena, FNT_AtlasRegionNode, 1); - atlas->root->max_free_size[Corner_00] = - atlas->root->max_free_size[Corner_01] = - atlas->root->max_free_size[Corner_10] = - atlas->root->max_free_size[Corner_11] = v2s16(atlas->root_dim.x/2, atlas->root_dim.y/2); - atlas->texture = r_tex2d_alloc(R_ResourceKind_Dynamic, v2s32((S32)atlas->root_dim.x, (S32)atlas->root_dim.y), R_Tex2DFormat_RGBA8, 0); - } - - // rjf: allocate from atlas - if(atlas != 0) - { - Vec2S16 needed_dimensions = v2s16(raster.atlas_dim.x + 2, raster.atlas_dim.y + 2); - chosen_atlas_region = fnt_atlas_region_alloc(f_state->raster_arena, atlas, needed_dimensions); - if(chosen_atlas_region.x1 != chosen_atlas_region.x0) - { - chosen_atlas = atlas; - chosen_atlas_num = (S32)num_atlases; - break; - } - } - else - { - break; - } - } - } - - // rjf: upload rasterization to allocated region of atlas texture memory - if(chosen_atlas != 0) - { - Rng2S32 subregion = - { - chosen_atlas_region.x0, - chosen_atlas_region.y0, - chosen_atlas_region.x0 + raster.atlas_dim.x, - chosen_atlas_region.y0 + raster.atlas_dim.y - }; - r_fill_tex2d_region(chosen_atlas->texture, subregion, raster.atlas); - } - - // rjf: allocate & fill & push node - { - if(piece_substring.size == 1) - { - info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; - hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] |= (1ull<<(piece_substring.str[0]%64)); - } - else - { - U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; - FNT_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; - F_Hash2InfoRasterCacheNode *node = push_array_no_zero(f_state->raster_arena, F_Hash2InfoRasterCacheNode, 1); - DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); - node->hash = piece_hash; - info = &node->info; - } - if(info != 0) - { - info->subrect = chosen_atlas_region; - info->atlas_num = chosen_atlas_num; - info->raster_dim = raster.atlas_dim; - info->advance = raster.advance; - } - } - - scratch_end(scratch); - ProfEnd(); - } - - //- rjf: push piece for this raster portion - if(info != 0) - { - // rjf: find atlas - FNT_Atlas *atlas = 0; - { - if(info->subrect.x1 != 0 && info->subrect.y1 != 0) - { - S32 num = 0; - for(FNT_Atlas *a = f_state->first_atlas; a != 0; a = a->next, num += 1) - { - if(info->atlas_num == num) - { - atlas = a; - break; - } - } - } - } - - // rjf: on tabs -> expand advance - F32 advance = info->advance; - if(is_tab) - { - advance = floor_f32(tab_size_px) - mod_f32(floor_f32(base_align_px), floor_f32(tab_size_px)); - } - - // rjf: push piece - { - FNT_Piece *piece = fnt_piece_chunk_list_push_new(arena, &piece_chunks, string.size); - { - piece->texture = atlas ? atlas->texture : r_handle_zero(); - piece->subrect = r2s16p(info->subrect.x0, - info->subrect.y0, - info->subrect.x0 + info->raster_dim.x, - info->subrect.y0 + info->raster_dim.y); - piece->advance = advance; - piece->decode_size = piece_substring.size; - piece->offset = v2s16(0, -(hash2style_node->ascent + hash2style_node->descent)); - } - base_align_px += advance; - dim.x += piece->advance; - dim.y = Max(dim.y, info->raster_dim.y); + run_node = n; + break; } } } - //- rjf: tighten & return + //- rjf: no run node? -> cache miss - compute & build & fill node if possible + B32 run_is_cacheable = 1; FNT_Run run = {0}; + if(run_node) { - if(piece_chunks.node_count == 1) + run = run_node->run; + } + else + ProfScope("no run node? -> cache miss") + ProfScope("compute & build & fill node for '%.*s'", str8_varg(string)) + { + //- rjf: decode string & produce run pieces + 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; + U64 piece_substring_end_idx = 0; + for(U64 idx = 0; idx <= string.size;) { - run.pieces.v = piece_chunks.first->v; - run.pieces.count = piece_chunks.first->count; + //- rjf: decode next codepoint & get piece substring, or continuation rule + U8 byte = (idx < string.size ? string.str[idx] : 0); + B32 need_another_codepoint = 0; + if(byte == 0) + { + idx += 1; + } + else switch(utf8_class[byte>>3]) + { + case 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; + piece_substring_end_idx += decode.inc; + need_another_codepoint = 0; + }break; + } + + //- 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? -> 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'); + if(is_tab) + { + run_is_cacheable = 0; + piece_substring = str8_lit(" "); + } + + //- rjf: piece substring -> raster cache info + FNT_RasterCacheInfo *info = 0; + U64 piece_hash = 0; + { + // rjf: fast path for utf8 class 1 -> direct map + if(piece_substring.size == 1 && hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] & (1ull<<(piece_substring.str[0]%64))) + { + info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; + } + + // rjf: more general, slower path for other glyphs + if(piece_substring.size > 1) + { + piece_hash = fnt_little_hash_from_string(5381, piece_substring); + U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; + FNT_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; + for(FNT_Hash2InfoRasterCacheNode *node = slot->first; node != 0; node = node->hash_next) + { + if(node->hash == piece_hash) + { + info = &node->info; + break; + } + } + } + } + + //- rjf: no info found -> miss... fill this hash in the cache + if(info == 0) + { + ProfBegin("no info found -> miss... fill this hash in the cache"); + Temp scratch = scratch_begin(0, 0); + + // rjf: grab font handle for this tag if we don't have one already + if(font_handle_mapped_on_miss == 0) + { + font_handle_mapped_on_miss = 1; + + // rjf: tag -> font slot index + U64 font_slot_idx = tag.u64[1] % fnt_state->font_hash_table_size; + + // rjf: tag * slot -> existing node + FNT_FontHashNode *existing_node = 0; + { + for(FNT_FontHashNode *n = fnt_state->font_hash_table[font_slot_idx].first; n != 0 ; n = n->hash_next) + { + if(MemoryMatchStruct(&n->tag, &tag)) + { + existing_node = n; + break; + } + } + } + + // rjf: existing node -> font handle + if(existing_node != 0) + { + font_handle = existing_node->handle; + } + } + + // rjf: call into font provider to rasterize this substring + FP_RasterResult raster = {0}; + if(size > 0) + { + FP_RasterFlags fp_flags = 0; + if(flags & FNT_RasterFlag_Smooth) { fp_flags |= FP_RasterFlag_Smooth; } + if(flags & FNT_RasterFlag_Hinted) { fp_flags |= FP_RasterFlag_Hinted; } + raster = fp_raster(scratch.arena, font_handle, floor_f32(size), flags, piece_substring); + } + + // rjf: allocate portion of an atlas to upload the rasterization + S16 chosen_atlas_num = 0; + FNT_Atlas *chosen_atlas = 0; + Rng2S16 chosen_atlas_region = {0}; + if(raster.atlas_dim.x != 0 && raster.atlas_dim.y != 0) + { + U64 num_atlases = 0; + for(FNT_Atlas *atlas = fnt_state->first_atlas;; atlas = atlas->next, num_atlases += 1) + { + // rjf: create atlas if needed + if(atlas == 0 && num_atlases < 64) + { + atlas = push_array(fnt_state->raster_arena, FNT_Atlas, 1); + DLLPushBack(fnt_state->first_atlas, fnt_state->last_atlas, atlas); + atlas->root_dim = v2s16(1024, 1024); + atlas->root = push_array(fnt_state->raster_arena, FNT_AtlasRegionNode, 1); + atlas->root->max_free_size[Corner_00] = + atlas->root->max_free_size[Corner_01] = + atlas->root->max_free_size[Corner_10] = + atlas->root->max_free_size[Corner_11] = v2s16(atlas->root_dim.x/2, atlas->root_dim.y/2); + atlas->texture = r_tex2d_alloc(R_ResourceKind_Dynamic, v2s32((S32)atlas->root_dim.x, (S32)atlas->root_dim.y), R_Tex2DFormat_RGBA8, 0); + } + + // rjf: allocate from atlas + if(atlas != 0) + { + Vec2S16 needed_dimensions = v2s16(raster.atlas_dim.x + 2, raster.atlas_dim.y + 2); + chosen_atlas_region = fnt_atlas_region_alloc(fnt_state->raster_arena, atlas, needed_dimensions); + if(chosen_atlas_region.x1 != chosen_atlas_region.x0) + { + chosen_atlas = atlas; + chosen_atlas_num = (S32)num_atlases; + break; + } + } + else + { + break; + } + } + } + + // rjf: upload rasterization to allocated region of atlas texture memory + if(chosen_atlas != 0) + { + Rng2S32 subregion = + { + chosen_atlas_region.x0, + chosen_atlas_region.y0, + chosen_atlas_region.x0 + raster.atlas_dim.x, + chosen_atlas_region.y0 + raster.atlas_dim.y + }; + r_fill_tex2d_region(chosen_atlas->texture, subregion, raster.atlas); + } + + // rjf: allocate & fill & push node + { + if(piece_substring.size == 1) + { + info = &hash2style_node->utf8_class1_direct_map[piece_substring.str[0]]; + hash2style_node->utf8_class1_direct_map_mask[piece_substring.str[0]/64] |= (1ull<<(piece_substring.str[0]%64)); + } + else + { + U64 slot_idx = piece_hash%hash2style_node->hash2info_slots_count; + FNT_Hash2InfoRasterCacheSlot *slot = &hash2style_node->hash2info_slots[slot_idx]; + FNT_Hash2InfoRasterCacheNode *node = push_array_no_zero(fnt_state->raster_arena, FNT_Hash2InfoRasterCacheNode, 1); + DLLPushBack_NP(slot->first, slot->last, node, hash_next, hash_prev); + node->hash = piece_hash; + info = &node->info; + } + if(info != 0) + { + info->subrect = chosen_atlas_region; + info->atlas_num = chosen_atlas_num; + info->raster_dim = raster.atlas_dim; + info->advance = raster.advance; + } + } + + scratch_end(scratch); + ProfEnd(); + } + + //- rjf: push piece for this raster portion + if(info != 0) + { + // rjf: find atlas + FNT_Atlas *atlas = 0; + { + if(info->subrect.x1 != 0 && info->subrect.y1 != 0) + { + S32 num = 0; + for(FNT_Atlas *a = fnt_state->first_atlas; a != 0; a = a->next, num += 1) + { + if(info->atlas_num == num) + { + atlas = a; + break; + } + } + } + } + + // rjf: on tabs -> expand advance + F32 advance = info->advance; + if(is_tab) + { + advance = floor_f32(tab_size_px) - mod_f32(floor_f32(base_align_px), floor_f32(tab_size_px)); + } + + // rjf: push piece + { + FNT_Piece *piece = fnt_piece_chunk_list_push_new(fnt_state->frame_arena, &piece_chunks, string.size); + { + piece->texture = atlas ? atlas->texture : r_handle_zero(); + piece->subrect = r2s16p(info->subrect.x0, + info->subrect.y0, + info->subrect.x0 + info->raster_dim.x, + info->subrect.y0 + info->raster_dim.y); + piece->advance = advance; + piece->decode_size = piece_substring.size; + piece->offset = v2s16(0, -(hash2style_node->ascent + hash2style_node->descent)); + } + base_align_px += advance; + dim.x += piece->advance; + dim.y = Max(dim.y, info->raster_dim.y); + } + } } - else + + //- rjf: tighten & fill { - run.pieces = fnt_piece_array_from_chunk_list(arena, &piece_chunks); + if(piece_chunks.node_count == 1) + { + run.pieces.v = piece_chunks.first->v; + run.pieces.count = piece_chunks.first->count; + } + else + { + run.pieces = fnt_piece_array_from_chunk_list(fnt_state->frame_arena, &piece_chunks); + } + run.dim = dim; + run.ascent = hash2style_node->ascent; + run.descent = hash2style_node->descent; } - run.dim = dim; - run.ascent = hash2style_node->ascent; - run.descent = hash2style_node->descent; + } + + //- rjf: build node for cacheable runs + if(run_is_cacheable) + { + run_node = push_array(fnt_state->frame_arena, FNT_RunCacheNode, 1); + SLLQueuePush(run_slot->first, run_slot->last, run_node); + run_node->string = push_str8_copy(fnt_state->frame_arena, string); + run_node->run = run; } ProfEnd(); @@ -855,7 +908,7 @@ fnt_wrapped_string_lines_from_font_size_string_max(Arena *arena, FNT_Tag font, F String8List list = {0}; { Temp scratch = scratch_begin(&arena, 1); - FNT_Run run = fnt_push_run_from_string(scratch.arena, font, size, base_align_px, tab_size_px, 0, string); + FNT_Run run = fnt_run_from_string(font, size, base_align_px, tab_size_px, 0, string); F32 off_px = 0; U64 off_bytes = 0; U64 line_start_off_bytes = 0; @@ -968,7 +1021,7 @@ fnt_dim_from_tag_size_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_s ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); Vec2F32 result = {0}; - FNT_Run run = fnt_push_run_from_string(scratch.arena, tag, size, base_align_px, tab_size_px, 0, string); + FNT_Run run = fnt_run_from_string(tag, size, base_align_px, tab_size_px, 0, string); result = run.dim; scratch_end(scratch); ProfEnd(); @@ -1005,7 +1058,7 @@ fnt_char_pos_from_tag_size_string_p(FNT_Tag tag, F32 size, F32 base_align_px, F3 F32 best_offset_px = inf32(); U64 offset_bytes = 0; F32 offset_px = 0.f; - FNT_Run run = fnt_push_run_from_string(scratch.arena, tag, size, base_align_px, tab_size_px, 0, string); + FNT_Run run = fnt_run_from_string(tag, size, base_align_px, tab_size_px, 0, string); for(U64 idx = 0; idx <= run.pieces.count; idx += 1) { F32 this_piece_offset_px = abs_f32(offset_px - p); @@ -1057,23 +1110,31 @@ internal void fnt_init(void) { Arena *arena = arena_alloc(); - f_state = push_array(arena, FNT_State, 1); - f_state->permanent_arena = arena; - f_state->raster_arena = arena_alloc(); - f_state->font_hash_table_size = 64; - f_state->font_hash_table = push_array(f_state->permanent_arena, FNT_FontHashSlot, f_state->font_hash_table_size); + fnt_state = push_array(arena, FNT_State, 1); + fnt_state->permanent_arena = arena; + fnt_state->raster_arena = arena_alloc(); + fnt_state->frame_arena = arena_alloc(); + fnt_state->font_hash_table_size = 64; + fnt_state->font_hash_table = push_array(fnt_state->permanent_arena, FNT_FontHashSlot, fnt_state->font_hash_table_size); fnt_reset(); } internal void fnt_reset(void) { - for(FNT_Atlas *a = f_state->first_atlas; a != 0; a = a->next) + for(FNT_Atlas *a = fnt_state->first_atlas; a != 0; a = a->next) { r_tex2d_release(a->texture); } - f_state->first_atlas = f_state->last_atlas = 0; - arena_clear(f_state->raster_arena); - f_state->hash2style_slots_count = 1024; - f_state->hash2style_slots = push_array(f_state->raster_arena, FNT_Hash2StyleRasterCacheSlot, f_state->hash2style_slots_count); + fnt_state->first_atlas = fnt_state->last_atlas = 0; + arena_clear(fnt_state->raster_arena); + fnt_state->hash2style_slots_count = 1024; + fnt_state->hash2style_slots = push_array(fnt_state->raster_arena, FNT_Hash2StyleRasterCacheSlot, fnt_state->hash2style_slots_count); +} + +internal void +fnt_frame(void) +{ + fnt_state->frame_index += 1; + arena_clear(fnt_state->frame_arena); } diff --git a/src/font_cache/font_cache.h b/src/font_cache/font_cache.h index 9f343eca..4bc6b0b7 100644 --- a/src/font_cache/font_cache.h +++ b/src/font_cache/font_cache.h @@ -93,8 +93,10 @@ struct FNT_FontHashSlot //////////////////////////////// //~ rjf: Rasterization Cache Types -typedef struct F_RasterCacheInfo F_RasterCacheInfo; -struct F_RasterCacheInfo +//- rjf: base glyph rasterization / dimensions cache + +typedef struct FNT_RasterCacheInfo FNT_RasterCacheInfo; +struct FNT_RasterCacheInfo { Rng2S16 subrect; Vec2S16 raster_dim; @@ -102,22 +104,41 @@ struct F_RasterCacheInfo F32 advance; }; -typedef struct F_Hash2InfoRasterCacheNode F_Hash2InfoRasterCacheNode; -struct F_Hash2InfoRasterCacheNode +typedef struct FNT_Hash2InfoRasterCacheNode FNT_Hash2InfoRasterCacheNode; +struct FNT_Hash2InfoRasterCacheNode { - F_Hash2InfoRasterCacheNode *hash_next; - F_Hash2InfoRasterCacheNode *hash_prev; + FNT_Hash2InfoRasterCacheNode *hash_next; + FNT_Hash2InfoRasterCacheNode *hash_prev; U64 hash; - F_RasterCacheInfo info; + FNT_RasterCacheInfo info; }; typedef struct FNT_Hash2InfoRasterCacheSlot FNT_Hash2InfoRasterCacheSlot; struct FNT_Hash2InfoRasterCacheSlot { - F_Hash2InfoRasterCacheNode *first; - F_Hash2InfoRasterCacheNode *last; + FNT_Hash2InfoRasterCacheNode *first; + FNT_Hash2InfoRasterCacheNode *last; }; +//- rjf: run cache (arrangements of many glyphs to represent a full string) + +typedef struct FNT_RunCacheNode FNT_RunCacheNode; +struct FNT_RunCacheNode +{ + FNT_RunCacheNode *next; + String8 string; + FNT_Run run; +}; + +typedef struct FNT_RunCacheSlot FNT_RunCacheSlot; +struct FNT_RunCacheSlot +{ + FNT_RunCacheNode *first; + FNT_RunCacheNode *last; +}; + +//- rjf: style hash -> artifacts/metrics cache + typedef struct FNT_Hash2StyleRasterCacheNode FNT_Hash2StyleRasterCacheNode; struct FNT_Hash2StyleRasterCacheNode { @@ -127,10 +148,13 @@ struct FNT_Hash2StyleRasterCacheNode F32 ascent; F32 descent; F32 column_width; - F_RasterCacheInfo *utf8_class1_direct_map; + FNT_RasterCacheInfo *utf8_class1_direct_map; U64 utf8_class1_direct_map_mask[4]; U64 hash2info_slots_count; FNT_Hash2InfoRasterCacheSlot *hash2info_slots; + U64 run_slots_count; + FNT_RunCacheSlot *run_slots; + U64 run_slots_frame_index; }; typedef struct FNT_Hash2StyleRasterCacheSlot FNT_Hash2StyleRasterCacheSlot; @@ -189,6 +213,8 @@ struct FNT_State { Arena *permanent_arena; Arena *raster_arena; + Arena *frame_arena; + U64 frame_index; // rjf: font table U64 font_hash_table_size; @@ -206,13 +232,13 @@ struct FNT_State //////////////////////////////// //~ rjf: Globals -global FNT_State *f_state = 0; +global FNT_State *fnt_state = 0; //////////////////////////////// //~ rjf: Basic Functions internal U128 fnt_hash_from_string(String8 string); -internal U64 fnt_little_hash_from_string(String8 string); +internal U64 fnt_little_hash_from_string(U64 seed, String8 string); internal Vec2S32 fnt_vertex_from_corner(Corner corner); //////////////////////////////// @@ -241,10 +267,13 @@ internal FNT_PieceArray fnt_piece_array_from_chunk_list(Arena *arena, FNT_PieceC internal FNT_PieceArray fnt_piece_array_copy(Arena *arena, FNT_PieceArray *src); //////////////////////////////// -//~ rjf: Rasterization Cache +//~ rjf: Cache Usage +//- rjf: base cache lookups internal FNT_Hash2StyleRasterCacheNode *fnt_hash2style_from_tag_size_flags(FNT_Tag tag, F32 size, FNT_RasterFlags flags); -internal FNT_Run fnt_push_run_from_string(Arena *arena, FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, String8 string); +internal FNT_Run fnt_run_from_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, FNT_RasterFlags flags, String8 string); + +//- rjf: helpers internal String8List fnt_wrapped_string_lines_from_font_size_string_max(Arena *arena, FNT_Tag font, F32 size, F32 base_align_px, F32 tab_size_px, String8 string, F32 max); internal Vec2F32 fnt_dim_from_tag_size_string(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8 string); internal Vec2F32 fnt_dim_from_tag_size_string_list(FNT_Tag tag, F32 size, F32 base_align_px, F32 tab_size_px, String8List list); @@ -262,5 +291,6 @@ internal F32 fnt_line_height_from_metrics(FNT_Metrics *metrics); internal void fnt_init(void); internal void fnt_reset(void); +internal void fnt_frame(void); #endif // FONT_CACHE_H diff --git a/src/font_provider/dwrite/font_provider_dwrite.c b/src/font_provider/dwrite/font_provider_dwrite.c index 4bfbddb2..003fd299 100644 --- a/src/font_provider/dwrite/font_provider_dwrite.c +++ b/src/font_provider/dwrite/font_provider_dwrite.c @@ -191,6 +191,7 @@ fp_init(void) //- rjf: make sharp-hinted rendering params { FLOAT gamma = IDWriteRenderingParams_GetGamma(fp_dwrite_state->base_rendering_params); + gamma = 1.f; FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(fp_dwrite_state->base_rendering_params); if(fp_dwrite_state->dwrite2_is_supported) { @@ -219,6 +220,7 @@ fp_init(void) //- rjf: make sharp-unhinted rendering params { FLOAT gamma = IDWriteRenderingParams_GetGamma(fp_dwrite_state->base_rendering_params); + gamma = 1.f; FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(fp_dwrite_state->base_rendering_params); if(fp_dwrite_state->dwrite2_is_supported) { @@ -247,6 +249,7 @@ fp_init(void) //- rjf: make smooth-hinted rendering params { FLOAT gamma = IDWriteRenderingParams_GetGamma(fp_dwrite_state->base_rendering_params); + gamma = 1.f; FLOAT enhanced_contrast = IDWriteRenderingParams_GetEnhancedContrast(fp_dwrite_state->base_rendering_params); if(fp_dwrite_state->dwrite2_is_supported) { @@ -284,7 +287,7 @@ fp_init(void) enhanced_contrast, 0.f, DWRITE_PIXEL_GEOMETRY_FLAT, - DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, + DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, DWRITE_GRID_FIT_MODE_DISABLED, (IDWriteRenderingParams2 **)&fp_dwrite_state->rendering_params_smooth_unhinted); } @@ -315,18 +318,71 @@ fp_font_open(String8 path) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - String16 path16 = str16_from_8(scratch.arena, path); FP_DWrite_Font font = {0}; HRESULT error = 0; - //- rjf: open font file reference - error = IDWriteFactory_CreateFontFileReference(fp_dwrite_state->factory, (WCHAR *)path16.str, 0, &font.file); + //- rjf: build initial path task + typedef struct PathTask PathTask; + struct PathTask + { + PathTask *next; + String8 path; + }; + PathTask start_task = {0, path}; + PathTask *first_task = &start_task; + PathTask *last_task = first_task; - //- rjf: open font face - error = IDWriteFactory_CreateFontFace(fp_dwrite_state->factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + //- rjf: try to open font + for(PathTask *t = first_task; t != 0 && font.file == 0; t = t->next) + { + B32 file_exists = (os_properties_from_file_path(t->path).created != 0); + String16 path16 = str16_from_8(scratch.arena, t->path); + if(file_exists) + { + error = IDWriteFactory_CreateFontFileReference(fp_dwrite_state->factory, (WCHAR *)path16.str, 0, &font.file); + } + if(font.file != 0) + { + error = IDWriteFactory_CreateFontFace(fp_dwrite_state->factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + } + + // rjf: failure trying just the normal path? -> generate new tasks that search in system folders + if(t == first_task && font.file == 0 && t->path.size != 0) + { + // rjf: generate task for user-installed fonts + { + HKEY reg_key = 0; + LSTATUS status = 0; + char name[256] = {0}; + char data[256] = {0}; + DWORD name_size = sizeof(name); + DWORD data_size = sizeof(data); + DWORD type = 0; + status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Fonts", 0, KEY_QUERY_VALUE, ®_key); + status = RegEnumValueA(reg_key, 0, name, &name_size, 0, &type, (unsigned char *)data, &data_size); + String8 user_fonts_path = str8_cstring(data); + PathTask *task = push_array(scratch.arena, PathTask, 1); + task->path = push_str8f(scratch.arena, "%s/%S", user_fonts_path, path); + SLLQueuePush(first_task, last_task, task); + } + + // rjf: generate task for windows directory (C:/Windows/Fonts, generally) + { + char windows_path[256] = {0}; + GetWindowsDirectoryA(windows_path, sizeof(windows_path)); + PathTask *task = push_array(scratch.arena, PathTask, 1); + task->path = push_str8f(scratch.arena, "%s/Fonts/%S", windows_path, path); + SLLQueuePush(first_task, last_task, task); + } + } + } //- rjf: handlify & return - FP_Handle handle = fp_dwrite_handle_from_font(font); + FP_Handle handle = {0}; + if(font.file != 0) + { + handle = fp_dwrite_handle_from_font(font); + } scratch_end(scratch); ProfEnd(); return handle; @@ -432,7 +488,7 @@ fp_raster(Arena *arena, FP_Handle font_handle, F32 size, FP_RasterFlags flags, S F32 right_side_bearing = 0; if(font.face != 0) { - atlas_dim.y = (S16)ceil_f32((96.f/72.f) * size * (font_metrics.ascent + font_metrics.descent) / design_units_per_em) + 1; + atlas_dim.y = (S16)round_f32((96.f/72.f) * size * (font_metrics.ascent + font_metrics.descent + font_metrics.lineGap) / design_units_per_em) + 1; for(U64 idx = 0; idx < glyphs_count; idx += 1) { DWRITE_GLYPH_METRICS *glyph_metrics = glyphs_metrics + idx; @@ -480,7 +536,9 @@ fp_raster(Arena *arena, FP_Handle font_handle, F32 size, FP_RasterFlags flags, S if(font.face != 0) { F32 descent = round_f32((96.f/72.f)*size * font_metrics.descent / design_units_per_em); + F32 line_gap = round_f32((96.f/72.f)*size * font_metrics.lineGap / design_units_per_em); draw_p.y -= descent; + draw_p.y -= line_gap; } DWRITE_GLYPH_RUN glyph_run = {0}; if(font.face != 0) diff --git a/src/font_provider/font_provider_inc.c b/src/font_provider/font_provider_inc.c index d5c7665b..c589b27a 100644 --- a/src/font_provider/font_provider_inc.c +++ b/src/font_provider/font_provider_inc.c @@ -5,6 +5,8 @@ #if FP_BACKEND == FP_BACKEND_DWRITE # include "dwrite/font_provider_dwrite.c" +#elif FP_BACKEND == FP_BACKEND_FREETYPE +# include "freetype/font_provider_freetype.c" #else # error Font provider backend not specified. #endif diff --git a/src/font_provider/freetype/font_provider_freetype.c b/src/font_provider/freetype/font_provider_freetype.c index 8ac6bce5..b98735b8 100644 --- a/src/font_provider/freetype/font_provider_freetype.c +++ b/src/font_provider/freetype/font_provider_freetype.c @@ -1,2 +1,147 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal FP_FT_Font +fp_ft_font_from_handle(FP_Handle handle) +{ + FP_FT_Font result = {(FT_Face)handle.u64[0]}; + return result; +} + +internal FP_Handle +fp_ft_handle_from_font(FP_FT_Font font) +{ + FP_Handle result = {(U64)font.face}; + return result; +} + +//////////////////////////////// +//~ rjf: Backend Implementations + +fp_hook void +fp_init(void) +{ + Arena *arena = arena_alloc(); + fp_ft_state = push_array(arena, FP_FT_State, 1); + fp_ft_state->arena = arena; + FT_Init_FreeType(&fp_ft_state->library); +} + +fp_hook FP_Handle +fp_font_open(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + String8 path_copy = push_str8_copy(scratch.arena, path); + FP_FT_Font font = {0}; + FT_New_Face(fp_ft_state->library, (char *)path_copy.str, 0, &font.face); + FP_Handle handle = fp_ft_handle_from_font(font); + scratch_end(scratch); + return handle; +} + +fp_hook FP_Handle +fp_font_open_from_static_data_string(String8 *data_ptr) +{ + FP_FT_Font font = {0}; + FT_New_Memory_Face(fp_ft_state->library, data_ptr->str, (FT_Long)data_ptr->size, 0, &font.face); + FP_Handle handle = fp_ft_handle_from_font(font); + return handle; +} + +fp_hook void +fp_font_close(FP_Handle handle) +{ + FP_FT_Font font = fp_ft_font_from_handle(handle); + if(font.face != 0) + { + FT_Done_Face(font.face); + } +} + +fp_hook FP_Metrics +fp_metrics_from_font(FP_Handle handle) +{ + FP_FT_Font font = fp_ft_font_from_handle(handle); + FP_Metrics result = {0}; + if(font.face != 0) + { + result.design_units_per_em = (F32)(font.face->units_per_EM * 72.f/96.f); + result.ascent = (F32)font.face->ascender; + result.descent = (F32)font.face->descender; + result.line_gap = (F32)(font.face->height - font.face->ascender + font.face->descender); + result.capital_height = (F32)(font.face->ascender); + } + return result; +} + +fp_hook FP_RasterResult +fp_raster(Arena *arena, FP_Handle handle, F32 size, FP_RasterFlags flags, String8 string) +{ + ProfBeginFunction(); + FP_FT_Font font = fp_ft_font_from_handle(handle); + FP_RasterResult result = {0}; + if(font.face != 0) + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: unpack font + FT_Face face = font.face; + FT_Set_Pixel_Sizes(face, 0, (FT_UInt)((96.f/72.f) * size)); + S64 ascent = face->size->metrics.ascender >> 6; + S64 descent = abs_s64(face->size->metrics.descender >> 6); + S64 height = face->size->metrics.height >> 6; + + //- rjf: unpack string + String32 string32 = str32_from_8(scratch.arena, string); + + //- rjf: measure + S32 total_width = 0; + for EachIndex(idx, string32.size) + { + FT_Load_Char(face, string32.str[idx], FT_LOAD_RENDER); + total_width += (face->glyph->advance.x >> 6); + } + + //- rjf: allocate & fill atlas w/ rasterization + Vec2S16 dim = {(S16)total_width+1, height+1}; + U64 atlas_size = dim.x * dim.y * 4; + U8 *atlas = push_array(arena, U8, atlas_size); + S32 baseline = ascent; + S32 atlas_write_x = 0; + for EachIndex(idx, string32.size) + { + FT_Load_Char(face, string32.str[idx], FT_LOAD_RENDER); + FT_Bitmap *bmp = &face->glyph->bitmap; + S32 top = face->glyph->bitmap_top; + S32 left = face->glyph->bitmap_left; + for(S32 row = 0; row < (S32)bmp->rows; row += 1) + { + S32 y = baseline - top + row; + for(S32 col = 0; col < (S32)bmp->width; col += 1) + { + S32 x = atlas_write_x + left + col; + U64 off = (y*dim.x + x)*4; + if(off+4 <= atlas_size) + { + atlas[off+0] = 255; + atlas[off+1] = 255; + atlas[off+2] = 255; + atlas[off+3] = bmp->buffer[row*bmp->pitch + col]; + } + } + } + atlas_write_x += (face->glyph->advance.x >> 6); + } + + //- rjf: fill result + result.atlas_dim = dim; + result.advance = (F32)total_width; + result.atlas = atlas; + scratch_end(scratch); + } + ProfEnd(); + return result; +} diff --git a/src/font_provider/freetype/font_provider_freetype.h b/src/font_provider/freetype/font_provider_freetype.h index 2efe2a50..b1e37c2f 100644 --- a/src/font_provider/freetype/font_provider_freetype.h +++ b/src/font_provider/freetype/font_provider_freetype.h @@ -4,4 +4,40 @@ #ifndef FONT_PROVIDER_FREETYPE_H #define FONT_PROVIDER_FREETYPE_H +//////////////////////////////// +//~ rjf: Freetype Includes + +#undef internal +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#define internal static + +//////////////////////////////// +//~ rjf: State Types + +typedef struct FP_FT_Font FP_FT_Font; +struct FP_FT_Font +{ + FT_Face face; +}; + +typedef struct FP_FT_State FP_FT_State; +struct FP_FT_State +{ + Arena *arena; + FT_Library library; +}; + +//////////////////////////////// +//~ rjf: Globals + +global FP_FT_State *fp_ft_state = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal FP_FT_Font fp_ft_font_from_handle(FP_Handle handle); +internal FP_Handle fp_ft_handle_from_font(FP_FT_Font font); + #endif // FONT_PROVIDER_FREETYPE_H diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 530e6f7a..dd7fa2e0 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xe34cd4ff + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -178,7 +181,7 @@ geo_buffer_from_hash(GEO_Scope *scope, U128 hash) } internal R_Handle -geo_buffer_from_key(GEO_Scope *scope, U128 key) +geo_buffer_from_key(GEO_Scope *scope, HS_Key key) { R_Handle handle = {0}; for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index 230d059e..d343be8e 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -118,7 +118,7 @@ internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node //~ rjf: Cache Lookups internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash); -internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key); +internal R_Handle geo_buffer_from_key(GEO_Scope *scope, HS_Key key); //////////////////////////////// //~ rjf: Transfer Threads diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index 82e84617..f7b819e9 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0x684123ff + //////////////////////////////// //~ rjf: Basic Helpers @@ -10,6 +13,13 @@ # include "third_party/xxHash/xxhash.h" #endif +internal U64 +hs_little_hash_from_data(String8 data) +{ + U64 result = XXH3_64bits(data.str, data.size); + return result; +} + internal U128 hs_hash_from_data(String8 data) { @@ -19,6 +29,35 @@ hs_hash_from_data(String8 data) return u128; } +internal HS_ID +hs_id_make(U64 u64_0, U64 u64_1) +{ + HS_ID id; + id.u128[0].u64[0] = u64_0; + id.u128[0].u64[1] = u64_1; + return id; +} + +internal B32 +hs_id_match(HS_ID a, HS_ID b) +{ + B32 result = MemoryMatchStruct(&a, &b); + return result; +} + +internal HS_Key +hs_key_make(HS_Root root, HS_ID id) +{ + HS_Key key = {root, 0, id}; + return key; +} + +internal B32 +hs_key_match(HS_Key a, HS_Key b) +{ + return (MemoryMatchStruct(&a.root, &b.root) && hs_id_match(a.id, b.id)); +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -44,6 +83,7 @@ hs_init(void) hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_get_system_info()->logical_processor_count); hs_shared->key_slots = push_array(arena, HS_KeySlot, hs_shared->key_slots_count); hs_shared->key_stripes = push_array(arena, HS_Stripe, hs_shared->key_stripes_count); + hs_shared->key_stripes_free_nodes = push_array(arena, HS_KeyNode *, hs_shared->key_stripes_count); for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1) { HS_Stripe *stripe = &hs_shared->key_stripes[idx]; @@ -51,20 +91,125 @@ hs_init(void) stripe->rw_mutex = os_rw_mutex_alloc(); stripe->cv = os_condition_variable_alloc(); } + hs_shared->root_slots_count = 4096; + hs_shared->root_stripes_count = Min(hs_shared->root_slots_count, os_get_system_info()->logical_processor_count); + hs_shared->root_slots = push_array(arena, HS_RootSlot, hs_shared->root_slots_count); + hs_shared->root_stripes = push_array(arena, HS_Stripe, hs_shared->root_stripes_count); + hs_shared->root_stripes_free_nodes = push_array(arena, HS_RootNode *, hs_shared->root_stripes_count); + for(U64 idx = 0; idx < hs_shared->root_stripes_count; idx += 1) + { + HS_Stripe *stripe = &hs_shared->root_stripes[idx]; + stripe->arena = arena_alloc(); + stripe->rw_mutex = os_rw_mutex_alloc(); + stripe->cv = os_condition_variable_alloc(); + } hs_shared->evictor_thread = os_thread_launch(hs_evictor_thread__entry_point, 0, 0); } //////////////////////////////// -//~ rjf: Thread Context Initialization +//~ rjf: Root Allocation/Deallocation + +internal HS_Root +hs_root_alloc(void) +{ + HS_Root root = {0}; + root.u64[0] = ins_atomic_u64_inc_eval(&hs_shared->root_id_gen); + U64 slot_idx = root.u64[1]%hs_shared->root_slots_count; + U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; + HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + HS_RootNode *node = hs_shared->root_stripes_free_nodes[stripe_idx]; + if(node != 0) + { + SLLStackPop(hs_shared->root_stripes_free_nodes[stripe_idx]); + } + else + { + node = push_array(stripe->arena, HS_RootNode, 1); + } + DLLPushBack(slot->first, slot->last, node); + node->root = root; + node->arena = arena_alloc(); + } + return root; +} internal void -hs_tctx_ensure_inited(void) +hs_root_release(HS_Root root) { - if(hs_tctx == 0) + //- rjf: unpack root + U64 slot_idx = root.u64[1]%hs_shared->root_slots_count; + U64 stripe_idx = slot_idx%hs_shared->root_stripes_count; + HS_RootSlot *slot = &hs_shared->root_slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->root_stripes[stripe_idx]; + + //- rjf: release root node, grab its arena / ID list + Arena *root_arena = 0; + HS_RootIDChunkList root_ids = {0}; + OS_MutexScopeW(stripe->rw_mutex) { - Arena *arena = arena_alloc(); - hs_tctx = push_array(arena, HS_TCTX, 1); - hs_tctx->arena = arena; + for(HS_RootNode *n = slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&root, &n->root)) + { + DLLRemove(slot->first, slot->last, n); + root_arena = n->arena; + root_ids = n->ids; + SLLStackPush(hs_shared->root_stripes_free_nodes[stripe_idx], n); + break; + } + } + } + + //- rjf: release all IDs + for(HS_RootIDChunkNode *id_chunk_n = root_ids.first; id_chunk_n != 0; id_chunk_n = id_chunk_n->next) + { + for EachIndex(chunk_idx, id_chunk_n->count) + { + HS_ID id = id_chunk_n->v[chunk_idx]; + HS_Key key = hs_key_make(root, id); + U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%hs_shared->key_slots_count; + U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; + HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; + HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; + OS_MutexScopeW(key_stripe->rw_mutex) + { + for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) + { + if(hs_key_match(n->key, key)) + { + // rjf: release reference to all hashes + for(U64 history_idx = 0; history_idx < HS_KEY_HASH_HISTORY_STRONG_REF_COUNT && history_idx < n->hash_history_gen; history_idx += 1) + { + U128 hash = n->hash_history[(n->hash_history_gen+history_idx)%ArrayCount(n->hash_history)]; + U64 hash_slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 hash_stripe_idx = hash_slot_idx%hs_shared->stripes_count; + HS_Slot *hash_slot = &hs_shared->slots[hash_slot_idx]; + HS_Stripe *hash_stripe = &hs_shared->stripes[hash_stripe_idx]; + OS_MutexScopeR(hash_stripe->rw_mutex) + { + for(HS_Node *n = hash_slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash)) + { + ins_atomic_u64_dec_eval(&n->key_ref_count); + break; + } + } + } + } + + // rjf: release key node + DLLRemove(key_slot->first, key_slot->last, n); + SLLStackPush(hs_shared->key_stripes_free_nodes[key_stripe_idx], n); + break; + } + } + } + } } } @@ -72,9 +217,10 @@ hs_tctx_ensure_inited(void) //~ rjf: Cache Submission internal U128 -hs_submit_data(U128 key, Arena **data_arena, String8 data) +hs_submit_data(HS_Key key, Arena **data_arena, String8 data) { - U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; + U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%hs_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; @@ -108,7 +254,10 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) node = push_array(stripe->arena, HS_Node, 1); } node->hash = hash; - node->arena = *data_arena; + if(data_arena != 0) + { + node->arena = *data_arena; + } node->data = data; node->scope_ref_count = 0; node->key_ref_count = 1; @@ -117,43 +266,96 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) else { existing_node->key_ref_count += 1; - arena_release(*data_arena); + if(data_arena != 0) + { + arena_release(*data_arena); + } + } + if(data_arena != 0) + { + *data_arena = 0; } - *data_arena = 0; } //- rjf: commit this hash to key cache U128 key_expired_hash = {0}; ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex) { + // rjf: find existing key + B32 key_is_new = 0; HS_KeyNode *key_node = 0; for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) { - if(u128_match(n->key, key)) + if(hs_key_match(n->key, key)) { key_node = n; break; } } + + // rjf: create key node if it doesn't exist if(!key_node) { - key_node = push_array(key_stripe->arena, HS_KeyNode, 1); + key_is_new = 1; + key_node = hs_shared->key_stripes_free_nodes[key_stripe_idx]; + if(key_node) + { + SLLStackPop(hs_shared->key_stripes_free_nodes[key_stripe_idx]); + } + else + { + key_node = push_array(key_stripe->arena, HS_KeyNode, 1); + } key_node->key = key; - SLLQueuePush(key_slot->first, key_slot->last, key_node); + DLLPushBack(key_slot->first, key_slot->last, key_node); } + + // rjf: push hash into key's history if(key_node) { - if(key_node->hash_history_gen >= ArrayCount(key_node->hash_history)) + if(key_node->hash_history_gen >= HS_KEY_HASH_HISTORY_STRONG_REF_COUNT) { - key_expired_hash = key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)]; + key_expired_hash = key_node->hash_history[(key_node->hash_history_gen-HS_KEY_HASH_HISTORY_STRONG_REF_COUNT)%ArrayCount(key_node->hash_history)]; } key_node->hash_history[key_node->hash_history_gen%ArrayCount(key_node->hash_history)] = hash; key_node->hash_history_gen += 1; } + + // rjf: key is new -> add this key to the associated root + if(key_is_new) + { + U64 root_hash = hs_little_hash_from_data(str8_struct(&key.root)); + U64 root_slot_idx = root_hash%hs_shared->root_slots_count; + U64 root_stripe_idx = root_slot_idx%hs_shared->root_stripes_count; + HS_RootSlot *root_slot = &hs_shared->root_slots[root_slot_idx]; + HS_Stripe *root_stripe = &hs_shared->root_stripes[root_stripe_idx]; + OS_MutexScopeW(root_stripe->rw_mutex) + { + for(HS_RootNode *n = root_slot->first; n != 0; n = n->next) + { + if(MemoryMatchStruct(&n->root, &key.root)) + { + HS_RootIDChunkNode *chunk = n->ids.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(n->arena, HS_RootIDChunkNode, 1); + SLLQueuePush(n->ids.first, n->ids.last, chunk); + n->ids.chunk_count += 1; + chunk->cap = 1024; + chunk->v = push_array_no_zero(n->arena, HS_ID, chunk->cap); + } + chunk->v[chunk->count] = key.id; + chunk->count += 1; + n->ids.total_count += 1; + break; + } + } + } + } } - //- rjf: if this key's history cache was full, dec key ref count of oldest hash - ProfScope("if this key's history cache was full, dec key ref count of oldest hash") + //- rjf: decrement key ref count of expired hash + ProfScope("decrement key ref count of expired hash") if(!u128_match(key_expired_hash, u128_zero())) { U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count; @@ -182,7 +384,12 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) internal HS_Scope * hs_scope_open(void) { - hs_tctx_ensure_inited(); + if(hs_tctx == 0) + { + Arena *arena = arena_alloc(); + hs_tctx = push_array(arena, HS_TCTX, 1); + hs_tctx->arena = arena; + } HS_Scope *scope = hs_tctx->free_scope; if(scope) { @@ -241,14 +448,58 @@ hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node) SLLStackPush(scope->top_touch, touch); } +//////////////////////////////// +//~ rjf: Downstream Accesses + +internal void +hs_hash_downstream_inc(U128 hash) +{ + U64 slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_inc_eval(&n->downstream_ref_count); + break; + } + } + } +} + +internal void +hs_hash_downstream_dec(U128 hash) +{ + U64 slot_idx = hash.u64[1]%hs_shared->slots_count; + U64 stripe_idx = slot_idx%hs_shared->stripes_count; + HS_Slot *slot = &hs_shared->slots[slot_idx]; + HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(HS_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash)) + { + ins_atomic_u64_dec_eval(&n->downstream_ref_count); + break; + } + } + } +} + //////////////////////////////// //~ rjf: Cache Lookup internal U128 -hs_hash_from_key(U128 key, U64 rewind_count) +hs_hash_from_key(HS_Key key, U64 rewind_count) { U128 result = {0}; - U64 key_slot_idx = key.u64[1]%hs_shared->key_slots_count; + U64 key_hash = hs_little_hash_from_data(str8_struct(&key)); + U64 key_slot_idx = key_hash%hs_shared->key_slots_count; U64 key_stripe_idx = key_slot_idx%hs_shared->key_stripes_count; HS_KeySlot *key_slot = &hs_shared->key_slots[key_slot_idx]; HS_Stripe *key_stripe = &hs_shared->key_stripes[key_stripe_idx]; @@ -256,7 +507,7 @@ hs_hash_from_key(U128 key, U64 rewind_count) { for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) { - if(u128_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count) + if(hs_key_match(n->key, key) && n->hash_history_gen > 0 && n->hash_history_gen-1 >= rewind_count) { result = n->hash_history[(n->hash_history_gen-1-rewind_count)%ArrayCount(n->hash_history)]; break; @@ -312,7 +563,8 @@ hs_evictor_thread__entry_point(void *p) { U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0) + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) { slot_has_work = 1; break; @@ -326,11 +578,15 @@ hs_evictor_thread__entry_point(void *p) next = n->next; U64 key_ref_count = ins_atomic_u64_eval(&n->key_ref_count); U64 scope_ref_count = ins_atomic_u64_eval(&n->scope_ref_count); - if(key_ref_count == 0 && scope_ref_count == 0) + U64 downstream_ref_count = ins_atomic_u64_eval(&n->downstream_ref_count); + if(key_ref_count == 0 && scope_ref_count == 0 && downstream_ref_count == 0) { DLLRemove(slot->first, slot->last, n); SLLStackPush(hs_shared->stripes_free_nodes[stripe_idx], n); - arena_release(n->arena); + if(n->arena != 0) + { + arena_release(n->arena); + } } } } diff --git a/src/hash_store/hash_store.h b/src/hash_store/hash_store.h index ff886e79..8141eeb9 100644 --- a/src/hash_store/hash_store.h +++ b/src/hash_store/hash_store.h @@ -4,16 +4,112 @@ #ifndef HASH_STORE_H #define HASH_STORE_H +//////////////////////////////// +//~ NOTE(rjf): Hash Store Notes (2025/05/18) +// +// The hash store is a general-purpose data cache. It offers three layers of +// caching: (a) content (hash of data), (b) key (unique identity correllated +// with history of hashes), and (c) root (bucket for many keys, manually +// allocated / deallocated). +// +// (a) The "content" level of cache access is a simply hash(data) -> data +// mapping. This bypasses all identity/key/root mechanisms and provides a +// way to just talk about unique (and deduplicated) blobs of data. +// +// (b) The "key" level of cache access is used to encode a history of hashes +// for some unique "identity", where the "identity" is a concept managed +// by the user. One example of an identity would be a particular address +// range inside of some process to which the debugger is attached. Another +// might be a range inside of some file. +// +// (c) The "root" level is to provide a top-level allocation/deallocation +// mechanism for a large set of keys. It also provides an extra level of +// key uniqueness. For instance, each process to which the debugger is +// attached might have its own root, and each key might correspond to a +// particular address range within that process. This way, when the +// process ends, all of its keys can be easily destroyed using a single +// deallocation of the root. +// +// The way this might be generally used inside of the debugger would be that +// some evaluation - let's say it's some variable `x` - is mapped (via debug +// info) to some address range. If `x` is a `char[4096]`, then it might map +// to some address range [&x, &x + 4096). This, together with the process +// within which `x` is evaluated, forms both a `root` (for the process) and +// a `key` (for the address range). Some asynchronous memory streaming system +// can then, together with the root and key, read memory for that range, then +// submit that data to the hash store, correllating with the root and key +// combo. + +//////////////////////////////// +//~ rjf: Key Types + +typedef struct HS_Root HS_Root; +struct HS_Root +{ + U64 u64[1]; +}; + +typedef struct HS_ID HS_ID; +struct HS_ID +{ + U128 u128[1]; +}; + +typedef struct HS_Key HS_Key; +struct HS_Key +{ + HS_Root root; + U64 _padding_; + HS_ID id; +}; + //////////////////////////////// //~ rjf: Cache Types +typedef struct HS_RootIDChunkNode HS_RootIDChunkNode; +struct HS_RootIDChunkNode +{ + HS_RootIDChunkNode *next; + HS_ID *v; + U64 count; + U64 cap; +}; + +typedef struct HS_RootIDChunkList HS_RootIDChunkList; +struct HS_RootIDChunkList +{ + HS_RootIDChunkNode *first; + HS_RootIDChunkNode *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct HS_RootNode HS_RootNode; +struct HS_RootNode +{ + HS_RootNode *next; + HS_RootNode *prev; + Arena *arena; + HS_Root root; + HS_RootIDChunkList ids; +}; + +typedef struct HS_RootSlot HS_RootSlot; +struct HS_RootSlot +{ + HS_RootNode *first; + HS_RootNode *last; +}; + #define HS_KEY_HASH_HISTORY_COUNT 64 +#define HS_KEY_HASH_HISTORY_STRONG_REF_COUNT 2 typedef struct HS_KeyNode HS_KeyNode; struct HS_KeyNode { HS_KeyNode *next; - U128 key; + HS_KeyNode *prev; + HS_Key key; U128 hash_history[HS_KEY_HASH_HISTORY_COUNT]; U64 hash_history_gen; }; @@ -35,6 +131,7 @@ struct HS_Node String8 data; U64 scope_ref_count; U64 key_ref_count; + U64 downstream_ref_count; }; typedef struct HS_Slot HS_Slot; @@ -100,6 +197,15 @@ struct HS_Shared U64 key_stripes_count; HS_KeySlot *key_slots; HS_Stripe *key_stripes; + HS_KeyNode **key_stripes_free_nodes; + + // rjf: root cache + U64 root_slots_count; + U64 root_stripes_count; + HS_RootSlot *root_slots; + HS_Stripe *root_stripes; + HS_RootNode **root_stripes_free_nodes; + U64 root_id_gen; // rjf: evictor thread OS_Handle evictor_thread; @@ -114,7 +220,12 @@ global HS_Shared *hs_shared = 0; //////////////////////////////// //~ rjf: Basic Helpers +internal U64 hs_little_hash_from_data(String8 data); internal U128 hs_hash_from_data(String8 data); +internal HS_ID hs_id_make(U64 u64_0, U64 u64_1); +internal B32 hs_id_match(HS_ID a, HS_ID b); +internal HS_Key hs_key_make(HS_Root root, HS_ID id); +internal B32 hs_key_match(HS_Key a, HS_Key b); //////////////////////////////// //~ rjf: Main Layer Initialization @@ -122,14 +233,15 @@ internal U128 hs_hash_from_data(String8 data); internal void hs_init(void); //////////////////////////////// -//~ rjf: Thread Context Initialization +//~ rjf: Root Allocation/Deallocation -internal void hs_tctx_ensure_inited(void); +internal HS_Root hs_root_alloc(void); +internal void hs_root_release(HS_Root root); //////////////////////////////// -//~ rjf: Cache Submission/Derefs +//~ rjf: Cache Submission -internal U128 hs_submit_data(U128 key, Arena **data_arena, String8 data); +internal U128 hs_submit_data(HS_Key key, Arena **data_arena, String8 data); //////////////////////////////// //~ rjf: Scoped Access @@ -138,10 +250,16 @@ internal HS_Scope *hs_scope_open(void); internal void hs_scope_close(HS_Scope *scope); internal void hs_scope_touch_node__stripe_r_guarded(HS_Scope *scope, HS_Node *node); +//////////////////////////////// +//~ rjf: Downstream Accesses + +internal void hs_hash_downstream_inc(U128 hash); +internal void hs_hash_downstream_dec(U128 hash); + //////////////////////////////// //~ rjf: Cache Lookups -internal U128 hs_hash_from_key(U128 key, U64 rewind_count); +internal U128 hs_hash_from_key(HS_Key key, U64 rewind_count); internal String8 hs_data_from_hash(HS_Scope *scope, U128 hash); //////////////////////////////// diff --git a/src/lib_raddbg_markup/raddbg_markup.c b/src/lib_raddbg_markup/raddbg_markup.c deleted file mode 100644 index 7e220eca..00000000 --- a/src/lib_raddbg_markup/raddbg_markup.c +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ Win32 Implementations - -#if defined(_WIN32) - -//- types - -typedef int BOOL; -typedef long LONG; -typedef unsigned long ULONG; -typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; -typedef unsigned long DWORD; -typedef wchar_t WCHAR; -typedef char const *LPCSTR; -typedef const WCHAR *LPCWSTR, *PCWSTR; -typedef LONG HRESULT; -typedef void *HANDLE; -struct HINSTANCE__; -typedef struct HINSTANCE__ *HMODULE; -typedef __int64 INT_PTR; -typedef INT_PTR (*FARPROC)(); - -//- prototypes - -#include - -#if defined(__cplusplus) -extern "C" -{ -#endif - __declspec(dllimport) HMODULE LoadLibraryA(LPCSTR name); - __declspec(dllimport) FARPROC GetProcAddress(HMODULE module, LPCSTR name); - __declspec(dllimport) BOOL FreeLibrary(HMODULE mod); - __declspec(dllimport) HANDLE GetCurrentThread(void); - __declspec(dllimport) DWORD GetCurrentThreadId(void); - __declspec(dllimport) void RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments); - long long _InterlockedCompareExchange64(long long volatile*, long long, long long); - long long _InterlockedExchangeAdd64(long long volatile*, long long); -#pragma intrinsic(_InterlockedCompareExchange64) -#pragma intrinsic(_InterlockedExchangeAdd64) - int raddbg_markup_vsnprintf(char * const, unsigned long long const, const char * const, va_list); -#if defined(__cplusplus) -} -#endif - -//- helpers - -typedef struct RADDBG_MARKUP_UnicodeDecode RADDBG_MARKUP_UnicodeDecode; -struct RADDBG_MARKUP_UnicodeDecode -{ - unsigned __int32 inc; - unsigned __int32 codepoint; -}; -static __int8 raddbg_utf8_class[32] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5}; - -static inline RADDBG_MARKUP_UnicodeDecode -raddbg_decode_utf8(char *str, unsigned __int64 max) -{ - RADDBG_MARKUP_UnicodeDecode result = {1, 0xffffffff}; - unsigned __int8 byte = str[0]; - unsigned __int8 byte_class = raddbg_utf8_class[byte >> 3]; - switch(byte_class) - { - case 1: - { - result.codepoint = byte; - }break; - case 2: - if(2 < max) - { - char cont_byte = str[1]; - if(raddbg_utf8_class[cont_byte >> 3] == 0) - { - result.codepoint = (byte & 0x0000001f) << 6; - result.codepoint |= (cont_byte & 0x0000003f); - result.inc = 2; - } - }break; - case 3: - if(2 < max) - { - char cont_byte[2] = {str[1], str[2]}; - if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && - raddbg_utf8_class[cont_byte[1] >> 3] == 0) - { - result.codepoint = (byte & 0x0000000f) << 12; - result.codepoint |= ((cont_byte[0] & 0x0000003f) << 6); - result.codepoint |= (cont_byte[1] & 0x0000003f); - result.inc = 3; - } - }break; - case 4: - if(3 < max) - { - char cont_byte[3] = {str[1], str[2], str[3]}; - if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && - raddbg_utf8_class[cont_byte[1] >> 3] == 0 && - raddbg_utf8_class[cont_byte[2] >> 3] == 0) - { - result.codepoint = (byte & 0x00000007) << 18; - result.codepoint |= ((cont_byte[0] & 0x0000003f) << 12); - result.codepoint |= ((cont_byte[1] & 0x0000003f) << 6); - result.codepoint |= (cont_byte[2] & 0x0000003f); - result.inc = 4; - } - } - } - return result; -} - -static inline unsigned __int32 -raddbg_encode_utf16(wchar_t *str, unsigned __int32 codepoint) -{ - unsigned __int32 inc = 1; - if(codepoint == 0xffffffff) - { - str[0] = (wchar_t)'?'; - } - else if(codepoint < 0x10000) - { - str[0] = (wchar_t)codepoint; - } - else - { - U32 v = codepoint - 0x10000; - str[0] = (wchar_t)(0xD800 + (v >> 10)); - str[1] = (wchar_t)(0xDC00 + (v & 0x000003ff)); - inc = 2; - } - return inc; -} - -//- implementations - -static inline int -raddbg_is_attached__impl(void) -{ - // TODO(rjf) - return 0; -} - -static inline void -raddbg_thread_name__impl(char *fmt, ...) -{ - // rjf: resolve variadic arguments - char buffer[512] = {0}; - char *name = buffer; - { - va_list args; - va_start(args, fmt); - raddbg_markup_vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - } - - // rjf: get windows 10 style procedure - HRESULT (*SetThreadDescription_function)(HANDLE hThread, PCWSTR lpThreadDescription) = 0; - { - static HRESULT (*global_SetThreadDescription_function)(HANDLE hThread, PCWSTR lpThreadDescription); - static volatile __int64 global_SetThreadDescription_init_started; - static volatile __int64 global_SetThreadDescription_init_done; - __int64 do_init = !_InterlockedCompareExchange64(&global_SetThreadDescription_init_started, 1, 0); - if(do_init) - { - HMODULE module = LoadLibraryA("kernel32.dll"); - global_SetThreadDescription_function = (HRESULT (*)(HANDLE, PCWSTR))GetProcAddress(module, "SetThreadDescription"); - FreeLibrary(module); - _InterlockedExchangeAdd64(&global_SetThreadDescription_init_done, 1); - } - for(;_InterlockedExchangeAdd64(&global_SetThreadDescription_init_done, 0) == 0;) - { - // NOTE(rjf): busy-loop, until init is done - } - SetThreadDescription_function = global_SetThreadDescription_function; - } - - // rjf: set thread name, windows 10 style - if(SetThreadDescription_function) - { - WCHAR buffer16[1024] = {0}; - int name_length = 0; - for(;name[name_length]; name_length += 1); - int write_offset = 0; - for(int idx = 0; idx < name_length;) - { - RADDBG_MARKUP_UnicodeDecode decode = raddbg_decode_utf8(name+idx, name_length-idx); - write_offset += raddbg_encode_utf16(buffer16 + write_offset, decode.codepoint); - idx += decode.inc; - } - SetThreadDescription_function(GetCurrentThread(), buffer16); - } - - // rjf: set thread name, raise-exception style - { -#pragma pack(push, 8) - typedef struct THREADNAME_INFO THREADNAME_INFO; - struct THREADNAME_INFO - { - DWORD dwType; - LPCSTR szName; - DWORD dwThreadID; - DWORD dwFlags; - }; -#pragma pack(pop) - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name; - info.dwThreadID = GetCurrentThreadId(); - info.dwFlags = 0; -#pragma warning(push) -#pragma warning(disable: 6320 6322) - __try - { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); - } - __except(1) - { - } -#pragma warning(pop) - } -} - -static inline void -raddbg_thread_color__impl(unsigned int hexcode) -{ - // TODO(rjf) -} - -#define raddbg_break__impl() (__debugbreak()) - -static inline void -raddbg_watch__impl(char *fmt, ...) -{ - // TODO(rjf) -} - -static inline void -raddbg_log__impl(char *fmt, ...) -{ - // TODO(rjf) -} - -#endif // defined(_WIN32) diff --git a/src/lib_raddbg_markup/raddbg_markup.h b/src/lib_raddbg_markup/raddbg_markup.h index 390f50d9..e1257cf4 100644 --- a/src/lib_raddbg_markup/raddbg_markup.h +++ b/src/lib_raddbg_markup/raddbg_markup.h @@ -7,21 +7,417 @@ //////////////////////////////// //~ Implementation Overrides -#if !defined(raddbg_markup_vsnprintf) -# define raddbg_markup_vsnprintf vsnprintf +#if !defined(RADDBG_MARKUP_VSNPRINTF) +# define RADDBG_MARKUP_DEFAULT_VSNPRINTF 1 +# define RADDBG_MARKUP_VSNPRINTF vsnprintf +#endif + +#if !defined(RADDBG_MARKUP_STL_TYPE_VIEWS) +# define RADDBG_MARKUP_STL_TYPE_VIEWS 1 #endif //////////////////////////////// //~ Usage Macros -#define raddbg_is_attached(...) raddbg_is_attached__impl() -#define raddbg_thread_name(fmt, ...) raddbg_thread_name__impl((fmt), __VA_ARGS__) -#define raddbg_thread_color_hex(hexcode) raddbg_thread_color__impl((hexcode)) -#define raddbg_thread_color_rgba(r, g, b, a) raddbg_thread_color__impl((unsigned int)(((r)*255) << 24) | (unsigned int)(((g)*255) << 16) | (unsigned int)(((b)*255) << 8) | (unsigned int)((a)*255)) -#define raddbg_break(...) raddbg_break__impl() -#define raddbg_break_if(expr, ...) ((expr) ? raddbg_break__impl() : (void)0) -#define raddbg_watch(fmt, ...) raddbg_watch__impl((fmt), __VA_ARGS__) -#define raddbg_pin(expr, ...) /* NOTE(rjf): inspected by debugger ui - does not change program execution */ -#define raddbg_log(fmt, ...) raddbg_log__impl((fmt), __VA_ARGS__) +#if !defined(RADDBG_MARKUP_STUBS) +# define raddbg_is_attached(...) raddbg_is_attached__impl() +# define raddbg_thread_id(...) raddbg_thread_id__impl() +# define raddbg_thread_name(fmt, ...) raddbg_thread_name__impl(raddbg_thread_id(), (fmt), __VA_ARGS__) +# define raddbg_thread_id_name(id, fmt, ...) raddbg_thread_name__impl((id), (fmt), __VA_ARGS__) +# define raddbg_thread_color_u32(u32) raddbg_thread_color__impl(raddbg_thread_id(), (u32)) +# define raddbg_thread_color_rgba(r, g, b, a) raddbg_thread_color__impl(raddbg_thread_id(), ((unsigned int)((r)*255) << 24) | ((unsigned int)((g)*255) << 16) | ((unsigned int)((b)*255) << 8) | ((unsigned int)(a)*255)) +# define raddbg_thread_id_color_u32(id, u32) raddbg_thread_color__impl((id), (u32)) +# define raddbg_thread_id_color_rgba(id, r, g, b, a) raddbg_thread_color__impl((id), ((unsigned int)((r)*255) << 24) | ((unsigned int)((g)*255) << 16) | ((unsigned int)((b)*255) << 8) | ((unsigned int)(a)*255)) +# define raddbg_break(...) raddbg_break__impl() +# define raddbg_break_if(expr, ...) ((expr) ? raddbg_break__impl() : (void)0) +# define raddbg_watch(fmt, ...) raddbg_watch__impl((fmt), __VA_ARGS__) +# define raddbg_pin(expr, ...) /* NOTE(rjf): inspected by debugger ui - does not change program execution */ +# define raddbg_log(fmt, ...) raddbg_log__impl((fmt), __VA_ARGS__) +# define raddbg_entry_point(...) raddbg_exe_data char raddbg_gen_data_id()[] = ("entry_point: \"" #__VA_ARGS__ "\"") +# define raddbg_type_view(type, ...) raddbg_exe_data char raddbg_gen_data_id()[] = ("type_view: {type: ```" #type "```, expr: ```" #__VA_ARGS__ "```}") +# define raddbg_add_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (1), (size), (r), (w), (x)) +# define raddbg_remove_breakpoint(ptr, size, r, w, x) raddbg_add_or_remove_breakpoint__impl((ptr), (0), (size), (r), (w), (x)) +#else +# define raddbg_is_attached(...) (0) +# define raddbg_thread_id(...) ((void)0) +# define raddbg_thread_name(fmt, ...) ((void)0) +# define raddbg_thread_id_name(id, fmt, ...) ((void)0) +# define raddbg_thread_color_u32(u32) ((void)0) +# define raddbg_thread_color_rgba(r, g, b, a) ((void)0) +# define raddbg_thread_id_color_u32(id, u32) ((void)0) +# define raddbg_thread_id_color_rgba(id, r, g, b, a) ((void)0) +# define raddbg_break(...) ((void)0) +# define raddbg_break_if(expr, ...) ((void)expr) +# define raddbg_watch(fmt, ...) ((void)0) +# define raddbg_pin(expr, ...) +# define raddbg_log(fmt, ...) ((void)0) +# define raddbg_entry_point(...) struct raddbg_gen_data_id(){int __unused__;} +# define raddbg_type_view(type, ...) struct raddbg_gen_data_id(){int __unused__;} +# define raddbg_add_breakpoint(ptr, size, r, w, x) ((void)0) +# define raddbg_remove_breakpoint(ptr, size, r, w, x) ((void)0) +#endif + +//////////////////////////////// +//~ Helpers + +#define raddbg_glue_(a, b) a##b +#define raddbg_glue(a, b) raddbg_glue_(a, b) +#define raddbg_gen_data_id() raddbg_glue(raddbg_data__, __COUNTER__) + +//////////////////////////////// +//~ Win32 Implementations + +#if defined(RADDBG_MARKUP_IMPLEMENTATION) && !defined(RADDBG_MARKUP_STUBS) +#if defined(_WIN32) + +//- default includes +#if RADDBG_MARKUP_DEFAULT_VSNPRINTF +#include +#endif + +//- section allocating +#pragma section(".raddbg", read, write) +#define raddbg_exe_data __declspec(allocate(".raddbg")) + +//- first byte of exe data section -> is attached +raddbg_exe_data unsigned char raddbg_is_attached_byte_marker[1]; + +//- types + +typedef int BOOL; +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; +typedef unsigned long DWORD; +typedef wchar_t WCHAR; +typedef char const *LPCSTR; +typedef const WCHAR *LPCWSTR, *PCWSTR; +typedef LONG HRESULT; +typedef void *HANDLE; +struct HINSTANCE__; +typedef struct HINSTANCE__ *HMODULE; +typedef __int64 INT_PTR; +typedef INT_PTR (*FARPROC)(); + +//- prototypes + +#include + +#if defined(__cplusplus) +extern "C" +{ +#endif + __declspec(dllimport) HMODULE LoadLibraryA(LPCSTR name); + __declspec(dllimport) FARPROC GetProcAddress(HMODULE module, LPCSTR name); + __declspec(dllimport) BOOL FreeLibrary(HMODULE mod); + __declspec(dllimport) HANDLE GetCurrentThread(void); + __declspec(dllimport) DWORD GetCurrentThreadId(void); + __declspec(dllimport) void RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments); + __declspec(dllimport) void OutputDebugStringA(LPCSTR buffer); + long long _InterlockedCompareExchange64(long long volatile*, long long, long long); + long long _InterlockedExchangeAdd64(long long volatile*, long long); +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedExchangeAdd64) +#if RADDBG_MARKUP_DEFAULT_VSNPRINTF + int RADDBG_MARKUP_VSNPRINTF(char * const, unsigned long long const, const char * const, va_list); +#endif +#if defined(__cplusplus) +} +#endif + +//- helpers + +typedef struct RADDBG_MARKUP_UnicodeDecode RADDBG_MARKUP_UnicodeDecode; +struct RADDBG_MARKUP_UnicodeDecode +{ + unsigned __int32 inc; + unsigned __int32 codepoint; +}; +static __int8 raddbg_utf8_class[32] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5}; + +static inline RADDBG_MARKUP_UnicodeDecode +raddbg_decode_utf8(char *str, unsigned __int64 max) +{ + RADDBG_MARKUP_UnicodeDecode result = {1, 0xffffffff}; + unsigned __int8 byte = str[0]; + unsigned __int8 byte_class = raddbg_utf8_class[byte >> 3]; + switch(byte_class) + { + case 1: + { + result.codepoint = byte; + }break; + case 2: + if(2 < max) + { + char cont_byte = str[1]; + if(raddbg_utf8_class[cont_byte >> 3] == 0) + { + result.codepoint = (byte & 0x0000001f) << 6; + result.codepoint |= (cont_byte & 0x0000003f); + result.inc = 2; + } + }break; + case 3: + if(2 < max) + { + char cont_byte[2] = {str[1], str[2]}; + if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && + raddbg_utf8_class[cont_byte[1] >> 3] == 0) + { + result.codepoint = (byte & 0x0000000f) << 12; + result.codepoint |= ((cont_byte[0] & 0x0000003f) << 6); + result.codepoint |= (cont_byte[1] & 0x0000003f); + result.inc = 3; + } + }break; + case 4: + if(3 < max) + { + char cont_byte[3] = {str[1], str[2], str[3]}; + if(raddbg_utf8_class[cont_byte[0] >> 3] == 0 && + raddbg_utf8_class[cont_byte[1] >> 3] == 0 && + raddbg_utf8_class[cont_byte[2] >> 3] == 0) + { + result.codepoint = (byte & 0x00000007) << 18; + result.codepoint |= ((cont_byte[0] & 0x0000003f) << 12); + result.codepoint |= ((cont_byte[1] & 0x0000003f) << 6); + result.codepoint |= (cont_byte[2] & 0x0000003f); + result.inc = 4; + } + } + } + return result; +} + +static inline unsigned __int32 +raddbg_encode_utf16(wchar_t *str, unsigned __int32 codepoint) +{ + unsigned __int32 inc = 1; + if(codepoint == 0xffffffff) + { + str[0] = (wchar_t)'?'; + } + else if(codepoint < 0x10000) + { + str[0] = (wchar_t)codepoint; + } + else + { + unsigned __int32 v = codepoint - 0x10000; + str[0] = (wchar_t)(0xD800 + (v >> 10)); + str[1] = (wchar_t)(0xDC00 + (v & 0x000003ff)); + inc = 2; + } + return inc; +} + +//- implementations + +static inline int +raddbg_is_attached__impl(void) +{ + return !!raddbg_is_attached_byte_marker[0]; +} + +static inline int +raddbg_thread_id__impl(void) +{ + DWORD result = GetCurrentThreadId(); + return result; +} + +static inline void +raddbg_thread_name__impl(int id, char *fmt, ...) +{ + // rjf: resolve variadic arguments + char buffer[512] = {0}; + char *name = buffer; + { + va_list args; + va_start(args, fmt); + RADDBG_MARKUP_VSNPRINTF(buffer, sizeof(buffer), fmt, args); + va_end(args); + } + + // rjf: get windows 10 style procedure + HRESULT (*SetThreadDescription_function)(HANDLE hThread, PCWSTR lpThreadDescription) = 0; + { + static HRESULT (*global_SetThreadDescription_function)(HANDLE hThread, PCWSTR lpThreadDescription); + static volatile __int64 global_SetThreadDescription_init_started; + static volatile __int64 global_SetThreadDescription_init_done; + __int64 do_init = !_InterlockedCompareExchange64(&global_SetThreadDescription_init_started, 1, 0); + if(do_init) + { + HMODULE module = LoadLibraryA("kernel32.dll"); + global_SetThreadDescription_function = (HRESULT (*)(HANDLE, PCWSTR))GetProcAddress(module, "SetThreadDescription"); + FreeLibrary(module); + _InterlockedExchangeAdd64(&global_SetThreadDescription_init_done, 1); + } + for(;_InterlockedExchangeAdd64(&global_SetThreadDescription_init_done, 0) == 0;) + { + // NOTE(rjf): busy-loop, until init is done + } + SetThreadDescription_function = global_SetThreadDescription_function; + } + + // rjf: set thread name, windows 10 style + if(SetThreadDescription_function && id == GetCurrentThreadId()) + { + WCHAR buffer16[1024] = {0}; + int name_length = 0; + for(;name[name_length]; name_length += 1); + int write_offset = 0; + for(int idx = 0; idx < name_length;) + { + RADDBG_MARKUP_UnicodeDecode decode = raddbg_decode_utf8(name+idx, name_length-idx); + write_offset += raddbg_encode_utf16(buffer16 + write_offset, decode.codepoint); + idx += decode.inc; + } + SetThreadDescription_function(GetCurrentThread(), buffer16); + } + + // rjf: set thread name, raise-exception style + { +#pragma pack(push, 8) + typedef struct THREADNAME_INFO THREADNAME_INFO; + struct THREADNAME_INFO + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + }; +#pragma pack(pop) + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = id; + info.dwFlags = 0; +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); + } + __except(1) + { + } +#pragma warning(pop) + } +} + +static inline void +raddbg_thread_color__impl(int id, unsigned int hexcode) +{ + if(raddbg_is_attached()) + { +#pragma pack(push, 8) + typedef struct RADDBG_ThreadColorInfo RADDBG_ThreadColorInfo; + struct RADDBG_ThreadColorInfo + { + DWORD dwThreadID; + DWORD _pad_0; + DWORD rgba; + DWORD _pad_1; + }; +#pragma pack(pop) + RADDBG_ThreadColorInfo info; + info.dwThreadID = id; + info.rgba = hexcode; +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try + { + RaiseException(0x00524144u, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); + } + __except(1) + { + } +#pragma warning(pop) + } +} + +#define raddbg_break__impl() (__debugbreak()) + +static inline void +raddbg_watch__impl(char *fmt, ...) +{ + // TODO(rjf) +} + +static inline void +raddbg_log__impl(char *fmt, ...) +{ + // rjf: resolve variadic arguments + char buffer[4096]; + { + va_list args; + va_start(args, fmt); + RADDBG_MARKUP_VSNPRINTF(buffer, sizeof(buffer), fmt, args); + va_end(args); + } + + // rjf: output debug string + OutputDebugStringA(buffer); +} + +static inline void +raddbg_add_or_remove_breakpoint__impl(void *ptr, int set, int size, int r, int w, int x) +{ + if(raddbg_is_attached()) + { +#pragma pack(push, 8) + typedef struct RADDBG_AddBreakpointInfo RADDBG_AddBreakpointInfo; + struct RADDBG_AddBreakpointInfo + { + unsigned __int64 vaddr; + unsigned __int64 size; + unsigned __int64 r; + unsigned __int64 w; + unsigned __int64 x; + unsigned __int64 add; + }; +#pragma pack(pop) + RADDBG_AddBreakpointInfo info; + info.vaddr = (unsigned __int64)ptr; + info.size = size; + info.r = r; + info.w = w; + info.x = x; + info.add = set; +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try + { + RaiseException(0x00524145u, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); + } + __except(1) + { + } +#pragma warning(pop) + } +} + +#endif // defined(_WIN32) +#endif // defined(RADDBG_MARKUP_IMPLEMENTATION) + +//////////////////////////////// +//~ Win32 STL Type Views + +#if defined(_WIN32) && defined(RADDBG_MARKUP_IMPLEMENTATION) && RADDBG_MARKUP_STL_TYPE_VIEWS +# if defined(_VECTOR_) +raddbg_type_view(std::vector, slice(_Mypair._Myval2)); +# endif +# if defined(_MEMORY_) +raddbg_type_view(std::unique_ptr, _Mypair._Myval2); +# endif +# if defined(_STRING_) +raddbg_type_view(std::basic_string, _Mypair._Myval2._Myres <= 15 ? _Mypair._Myval2._Bx._Buf : array(_Mypair._Myval2._Bx._Ptr, _Mypair._Myval2._Mysize)); +# endif +# if defined(_STRING_VIEW_) +raddbg_type_view(std::basic_string_view, array(_Mydata, _Mysize)); +# endif +#endif // defined(_WIN32) && defined(RADDBG_MARKUP_IMPLEMENTATION) && RADDBG_MARKUP_STL_TYPE_VIEWS #endif // RADDBG_MARKUP_H diff --git a/src/lib_rdi_format/rdi_format.c b/src/lib_rdi_format/rdi_format.c index 4e79ae5e..57f02162 100644 --- a/src/lib_rdi_format/rdi_format.c +++ b/src/lib_rdi_format/rdi_format.c @@ -92,7 +92,7 @@ RDI_U8 rdi_section_is_required_table[37] = 0, }; -RDI_U16 rdi_eval_op_ctrlbits_table[49] = +RDI_U16 rdi_eval_op_ctrlbits_table[52] = { RDI_EVAL_CTRLBITS(0, 0, 0), RDI_EVAL_CTRLBITS(0, 0, 0), @@ -101,7 +101,7 @@ RDI_EVAL_CTRLBITS(2, 0, 0), RDI_EVAL_CTRLBITS(1, 1, 1), RDI_EVAL_CTRLBITS(4, 0, 1), RDI_EVAL_CTRLBITS(0, 1, 1), -RDI_EVAL_CTRLBITS(1, 0, 1), +RDI_EVAL_CTRLBITS(8, 0, 1), RDI_EVAL_CTRLBITS(4, 0, 1), RDI_EVAL_CTRLBITS(4, 0, 1), RDI_EVAL_CTRLBITS(0, 0, 0), @@ -142,6 +142,9 @@ RDI_EVAL_CTRLBITS(0, 1, 0), RDI_EVAL_CTRLBITS(1, 0, 0), RDI_EVAL_CTRLBITS(1, 2, 1), RDI_EVAL_CTRLBITS(1, 1, 1), +RDI_EVAL_CTRLBITS(4, 0, 0), +RDI_EVAL_CTRLBITS(4, 0, 0), +RDI_EVAL_CTRLBITS(8, 0, 0), RDI_EVAL_CTRLBITS(0, 0, 0), }; @@ -157,12 +160,12 @@ struct {RDI_EvalConversionKind dst_typegroups[RDI_EvalTypeGroup_COUNT];} rdi_eva struct {RDI_U8 *str; RDI_U64 size;} rdi_eval_conversion_kind_message_string_table[6] = { -{(RDI_U8 *)"Other", sizeof("Other")}, -{(RDI_U8 *)"U", sizeof("U")}, -{(RDI_U8 *)"S", sizeof("S")}, -{(RDI_U8 *)"F32", sizeof("F32")}, -{(RDI_U8 *)"F64", sizeof("F64")}, -{(RDI_U8 *)"COUNT", sizeof("COUNT")}, +{(RDI_U8 *)"", sizeof("")}, +{(RDI_U8 *)"", sizeof("")}, +{(RDI_U8 *)"Cannot convert between these types.", sizeof("Cannot convert between these types.")}, +{(RDI_U8 *)"Cannot convert to this type.", sizeof("Cannot convert to this type.")}, +{(RDI_U8 *)"Cannot convert this type.", sizeof("Cannot convert this type.")}, +{(RDI_U8 *)"", sizeof("")}, }; RDI_PROC RDI_U64 @@ -177,6 +180,74 @@ rdi_hash(RDI_U8 *ptr, RDI_U64 size) return result; } +RDI_PROC RDI_U8 * +rdi_string_from_type_kind(RDI_TypeKind kind, RDI_U64 *size_out) +{ +RDI_U8 *result = 0; +*size_out = 0; +switch (kind) +{ +default:{}break; +case RDI_TypeKind_NULL: {result = (RDI_U8*)"NULL"; *size_out = sizeof("NULL")-1;}break; +case RDI_TypeKind_Void: {result = (RDI_U8*)"Void"; *size_out = sizeof("Void")-1;}break; +case RDI_TypeKind_Handle: {result = (RDI_U8*)"Handle"; *size_out = sizeof("Handle")-1;}break; +case RDI_TypeKind_HResult: {result = (RDI_U8*)"HResult"; *size_out = sizeof("HResult")-1;}break; +case RDI_TypeKind_Char8: {result = (RDI_U8*)"Char8"; *size_out = sizeof("Char8")-1;}break; +case RDI_TypeKind_Char16: {result = (RDI_U8*)"Char16"; *size_out = sizeof("Char16")-1;}break; +case RDI_TypeKind_Char32: {result = (RDI_U8*)"Char32"; *size_out = sizeof("Char32")-1;}break; +case RDI_TypeKind_UChar8: {result = (RDI_U8*)"UChar8"; *size_out = sizeof("UChar8")-1;}break; +case RDI_TypeKind_UChar16: {result = (RDI_U8*)"UChar16"; *size_out = sizeof("UChar16")-1;}break; +case RDI_TypeKind_UChar32: {result = (RDI_U8*)"UChar32"; *size_out = sizeof("UChar32")-1;}break; +case RDI_TypeKind_U8: {result = (RDI_U8*)"U8"; *size_out = sizeof("U8")-1;}break; +case RDI_TypeKind_U16: {result = (RDI_U8*)"U16"; *size_out = sizeof("U16")-1;}break; +case RDI_TypeKind_U32: {result = (RDI_U8*)"U32"; *size_out = sizeof("U32")-1;}break; +case RDI_TypeKind_U64: {result = (RDI_U8*)"U64"; *size_out = sizeof("U64")-1;}break; +case RDI_TypeKind_U128: {result = (RDI_U8*)"U128"; *size_out = sizeof("U128")-1;}break; +case RDI_TypeKind_U256: {result = (RDI_U8*)"U256"; *size_out = sizeof("U256")-1;}break; +case RDI_TypeKind_U512: {result = (RDI_U8*)"U512"; *size_out = sizeof("U512")-1;}break; +case RDI_TypeKind_S8: {result = (RDI_U8*)"S8"; *size_out = sizeof("S8")-1;}break; +case RDI_TypeKind_S16: {result = (RDI_U8*)"S16"; *size_out = sizeof("S16")-1;}break; +case RDI_TypeKind_S32: {result = (RDI_U8*)"S32"; *size_out = sizeof("S32")-1;}break; +case RDI_TypeKind_S64: {result = (RDI_U8*)"S64"; *size_out = sizeof("S64")-1;}break; +case RDI_TypeKind_S128: {result = (RDI_U8*)"S128"; *size_out = sizeof("S128")-1;}break; +case RDI_TypeKind_S256: {result = (RDI_U8*)"S256"; *size_out = sizeof("S256")-1;}break; +case RDI_TypeKind_S512: {result = (RDI_U8*)"S512"; *size_out = sizeof("S512")-1;}break; +case RDI_TypeKind_Bool: {result = (RDI_U8*)"Bool"; *size_out = sizeof("Bool")-1;}break; +case RDI_TypeKind_F16: {result = (RDI_U8*)"F16"; *size_out = sizeof("F16")-1;}break; +case RDI_TypeKind_F32: {result = (RDI_U8*)"F32"; *size_out = sizeof("F32")-1;}break; +case RDI_TypeKind_F32PP: {result = (RDI_U8*)"F32PP"; *size_out = sizeof("F32PP")-1;}break; +case RDI_TypeKind_F48: {result = (RDI_U8*)"F48"; *size_out = sizeof("F48")-1;}break; +case RDI_TypeKind_F64: {result = (RDI_U8*)"F64"; *size_out = sizeof("F64")-1;}break; +case RDI_TypeKind_F80: {result = (RDI_U8*)"F80"; *size_out = sizeof("F80")-1;}break; +case RDI_TypeKind_F128: {result = (RDI_U8*)"F128"; *size_out = sizeof("F128")-1;}break; +case RDI_TypeKind_ComplexF32: {result = (RDI_U8*)"ComplexF32"; *size_out = sizeof("ComplexF32")-1;}break; +case RDI_TypeKind_ComplexF64: {result = (RDI_U8*)"ComplexF64"; *size_out = sizeof("ComplexF64")-1;}break; +case RDI_TypeKind_ComplexF80: {result = (RDI_U8*)"ComplexF80"; *size_out = sizeof("ComplexF80")-1;}break; +case RDI_TypeKind_ComplexF128: {result = (RDI_U8*)"ComplexF128"; *size_out = sizeof("ComplexF128")-1;}break; +case RDI_TypeKind_Modifier: {result = (RDI_U8*)"Modifier"; *size_out = sizeof("Modifier")-1;}break; +case RDI_TypeKind_Ptr: {result = (RDI_U8*)"Ptr"; *size_out = sizeof("Ptr")-1;}break; +case RDI_TypeKind_LRef: {result = (RDI_U8*)"LRef"; *size_out = sizeof("LRef")-1;}break; +case RDI_TypeKind_RRef: {result = (RDI_U8*)"RRef"; *size_out = sizeof("RRef")-1;}break; +case RDI_TypeKind_Array: {result = (RDI_U8*)"Array"; *size_out = sizeof("Array")-1;}break; +case RDI_TypeKind_Function: {result = (RDI_U8*)"Function"; *size_out = sizeof("Function")-1;}break; +case RDI_TypeKind_Method: {result = (RDI_U8*)"Method"; *size_out = sizeof("Method")-1;}break; +case RDI_TypeKind_MemberPtr: {result = (RDI_U8*)"MemberPtr"; *size_out = sizeof("MemberPtr")-1;}break; +case RDI_TypeKind_Struct: {result = (RDI_U8*)"Struct"; *size_out = sizeof("Struct")-1;}break; +case RDI_TypeKind_Class: {result = (RDI_U8*)"Class"; *size_out = sizeof("Class")-1;}break; +case RDI_TypeKind_Union: {result = (RDI_U8*)"Union"; *size_out = sizeof("Union")-1;}break; +case RDI_TypeKind_Enum: {result = (RDI_U8*)"Enum"; *size_out = sizeof("Enum")-1;}break; +case RDI_TypeKind_Alias: {result = (RDI_U8*)"Alias"; *size_out = sizeof("Alias")-1;}break; +case RDI_TypeKind_IncompleteStruct: {result = (RDI_U8*)"IncompleteStruct"; *size_out = sizeof("IncompleteStruct")-1;}break; +case RDI_TypeKind_IncompleteUnion: {result = (RDI_U8*)"IncompleteUnion"; *size_out = sizeof("IncompleteUnion")-1;}break; +case RDI_TypeKind_IncompleteClass: {result = (RDI_U8*)"IncompleteClass"; *size_out = sizeof("IncompleteClass")-1;}break; +case RDI_TypeKind_IncompleteEnum: {result = (RDI_U8*)"IncompleteEnum"; *size_out = sizeof("IncompleteEnum")-1;}break; +case RDI_TypeKind_Bitfield: {result = (RDI_U8*)"Bitfield"; *size_out = sizeof("Bitfield")-1;}break; +case RDI_TypeKind_Variadic: {result = (RDI_U8*)"Variadic"; *size_out = sizeof("Variadic")-1;}break; +case RDI_TypeKind_Count: {result = (RDI_U8*)"Count"; *size_out = sizeof("Count")-1;}break; +} +return result; +} + RDI_PROC RDI_U32 rdi_size_from_basic_type_kind(RDI_TypeKind kind) { diff --git a/src/lib_rdi_format/rdi_format.h b/src/lib_rdi_format/rdi_format.h index f440f03c..23149735 100644 --- a/src/lib_rdi_format/rdi_format.h +++ b/src/lib_rdi_format/rdi_format.h @@ -50,9 +50,9 @@ typedef int64_t RDI_S64; //////////////////////////////////////////////////////////////// //~ Format Constants -// \"raddbg\0\0\" +// "raddbg\0\0" #define RDI_MAGIC_CONSTANT 0x0000676264646172 -#define RDI_ENCODING_VERSION 10 +#define RDI_ENCODING_VERSION 11 //////////////////////////////////////////////////////////////// //~ Format Types & Functions @@ -386,6 +386,7 @@ typedef enum RDI_TypeModifierFlagsEnum { RDI_TypeModifierFlag_Const = 1<<0, RDI_TypeModifierFlag_Volatile = 1<<1, +RDI_TypeModifierFlag_Restrict = 1<<2, } RDI_TypeModifierFlagsEnum; typedef RDI_U32 RDI_UDTFlags; @@ -487,7 +488,10 @@ RDI_EvalOp_Pop = 44, RDI_EvalOp_Insert = 45, RDI_EvalOp_ValueRead = 46, RDI_EvalOp_ByteSwap = 47, -RDI_EvalOp_COUNT = 48, +RDI_EvalOp_CallSiteValue = 48, +RDI_EvalOp_PartialValue = 49, +RDI_EvalOp_PartialValueBit = 50, +RDI_EvalOp_COUNT = 51, } RDI_EvalOpEnum; typedef RDI_U8 RDI_EvalTypeGroup; @@ -887,6 +891,7 @@ X(Count)\ #define RDI_TypeModifierFlags_XList \ X(Const)\ X(Volatile)\ +X(Restrict)\ #define RDI_TypeNode_XList \ X(RDI_TypeKind, kind)\ @@ -968,6 +973,8 @@ X(RDI_LinkFlags, link_flags)\ X(RDI_U32, type_idx)\ X(RDI_U32, root_scope_idx)\ X(RDI_U32, container_idx)\ +X(RDI_U32, frame_base_location_first)\ +X(RDI_U32, frame_base_location_opl)\ #define RDI_Scope_XList \ X(RDI_U32, proc_idx)\ @@ -1062,6 +1069,9 @@ X(Pop)\ X(Insert)\ X(ValueRead)\ X(ByteSwap)\ +X(CallSiteValue)\ +X(PartialValue)\ +X(PartialValueBit)\ #define RDI_EvalTypeGroup_XList \ X(Other)\ @@ -1395,6 +1405,8 @@ RDI_LinkFlags link_flags; RDI_U32 type_idx; RDI_U32 root_scope_idx; RDI_U32 container_idx; +RDI_U32 frame_base_location_first; +RDI_U32 frame_base_location_opl; }; typedef struct RDI_Scope RDI_Scope; @@ -1528,9 +1540,10 @@ RDI_PROC RDI_U32 rdi_addr_size_from_arch(RDI_Arch arch); RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_kind_from_typegroups(RDI_EvalTypeGroup in, RDI_EvalTypeGroup out); RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); +RDI_PROC RDI_U8 *rdi_string_from_type_kind(RDI_TypeKind kind, RDI_U64 *size_out); extern RDI_U16 rdi_section_element_size_table[37]; extern RDI_U8 rdi_section_is_required_table[37]; -extern RDI_U16 rdi_eval_op_ctrlbits_table[49]; +extern RDI_U16 rdi_eval_op_ctrlbits_table[52]; #endif // RDI_FORMAT_H diff --git a/src/lib_rdi_format/rdi_format_parse.c b/src/lib_rdi_format/rdi_format_parse.c index b396f76a..3439589e 100644 --- a/src/lib_rdi_format/rdi_format_parse.c +++ b/src/lib_rdi_format/rdi_format_parse.c @@ -586,6 +586,30 @@ rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) return scope; } +RDI_PROC RDI_UDT * +rdi_container_udt_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) +{ + RDI_U64 idx = 0; + if(procedure->link_flags & RDI_LinkFlag_TypeScoped) + { + idx = procedure->container_idx; + } + RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, idx); + return udt; +} + +RDI_PROC RDI_Procedure * +rdi_container_procedure_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) +{ + RDI_U64 idx = 0; + if(procedure->link_flags & RDI_LinkFlag_ProcScoped) + { + idx = procedure->container_idx; + } + RDI_Procedure *container_procedure = rdi_element_from_name_idx(rdi, Procedures, idx); + return container_procedure; +} + RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure) { @@ -813,3 +837,24 @@ rdi_cstring_length(char *cstr) for(;cstr[result] != 0; result += 1){} return result; } + +RDI_PROC RDI_U64 +rdi_size_from_bytecode_stream(RDI_U8 *ptr, RDI_U8 *opl) +{ + RDI_U64 bytecode_size = 0; + RDI_U8 *off_first = ptr + sizeof(RDI_LocationKind); + for(RDI_U8 *off = off_first, *next_off = opl; off < opl; off = next_off) + { + RDI_U8 op = *off; + if(op == 0) + { + break; + } + + RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; + RDI_U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + bytecode_size += (1 + p_size); + next_off = (off + 1 + p_size); + } + return bytecode_size; +} diff --git a/src/lib_rdi_format/rdi_format_parse.h b/src/lib_rdi_format/rdi_format_parse.h index dc948f70..4d3e40b4 100644 --- a/src/lib_rdi_format/rdi_format_parse.h +++ b/src/lib_rdi_format/rdi_format_parse.h @@ -132,6 +132,7 @@ static union RDI_Local local; } rdi_nil_element_union = {0}; +static RDI_Parsed rdi_parsed_nil = {0}; //////////////////////////////// //~ Top-Level Parsing API @@ -181,6 +182,8 @@ RDI_PROC RDI_Procedure *rdi_procedure_from_name(RDI_Parsed *rdi, RDI_U8 *name, R RDI_PROC RDI_Procedure *rdi_procedure_from_name_cstr(RDI_Parsed *rdi, char *cstr); RDI_PROC RDI_U8 *rdi_name_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure, RDI_U64 *len_out); RDI_PROC RDI_Scope *rdi_root_scope_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); +RDI_PROC RDI_UDT *rdi_container_udt_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); +RDI_PROC RDI_Procedure *rdi_container_procedure_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); RDI_PROC RDI_U64 rdi_first_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); RDI_PROC RDI_U64 rdi_opl_voff_from_procedure(RDI_Parsed *rdi, RDI_Procedure *procedure); RDI_PROC RDI_Procedure *rdi_procedure_from_voff(RDI_Parsed *rdi, RDI_U64 voff); @@ -225,5 +228,6 @@ RDI_PROC RDI_U8 *rdi_name_from_file_path_node(RDI_Parsed *rdi, RDI_FilePathNode #define rdi_parse__min(a,b) (((a)<(b))?(a):(b)) RDI_PROC RDI_U64 rdi_cstring_length(char *cstr); +RDI_PROC RDI_U64 rdi_size_from_bytecode_stream(RDI_U8 *ptr, RDI_U8 *opl); #endif // RDI_FORMAT_PARSE_H diff --git a/src/lib_rdi_make/rdi_make.c b/src/lib_rdi_make/rdi_make.c index 3f37b9f5..afc1ef9f 100644 --- a/src/lib_rdi_make/rdi_make.c +++ b/src/lib_rdi_make/rdi_make.c @@ -438,6 +438,153 @@ rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r } } +//////////////////////////////// +//~ Data Model + +RDI_PROC RDI_TypeKind +rdim_short_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_S16; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_S16; + case RDIM_DataModel_LP64 : return RDI_TypeKind_S16; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_S16; + case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_unsigned_short_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_U16; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_U16; + case RDIM_DataModel_LP64 : return RDI_TypeKind_U16; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_U16; + case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_int_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_S32; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_S32; + case RDIM_DataModel_LP64 : return RDI_TypeKind_S32; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_U32; + case RDIM_DataModel_LP64 : return RDI_TypeKind_U32; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_long_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_S32; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_S32; + case RDIM_DataModel_LP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_unsigned_long_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_U32; + case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_long_long_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_S64; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_LP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_S64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_S64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_unsigned_long_long_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_U64; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + +RDI_PROC RDI_TypeKind +rdim_pointer_size_t_type_from_data_model(RDIM_DataModel data_model) +{ + switch(data_model) + { + case RDIM_DataModel_Null : break; + case RDIM_DataModel_ILP32 : return RDI_TypeKind_U32; + case RDIM_DataModel_LLP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_LP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_ILP64 : return RDI_TypeKind_U64; + case RDIM_DataModel_SILP64: return RDI_TypeKind_U64; + default: InvalidPath; + } + return RDI_TypeKind_NULL; +} + //////////////////////////////// //~ rjf: [Building] Binary Section List Building @@ -652,6 +799,28 @@ rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList //////////////////////////////// //~ rjf: [Building] Type Info Building +RDI_PROC RDIM_Type ** +rdim_array_from_type_list(RDIM_Arena *arena, RDIM_TypeList list) +{ + RDIM_Type **arr = push_array(arena, RDIM_Type *, list.count); + U64 i = 0; + for(RDIM_TypeNode *n = list.first; n != 0; n = n->next, ++i) + { + arr[i] = n->v; + } + return arr; +} + +RDI_PROC RDIM_TypeNode * +rdim_type_list_push(RDIM_Arena *arena, RDIM_TypeList *list, RDIM_Type *v) +{ + RDIM_TypeNode *n = push_array(arena, RDIM_TypeNode, 1); + n->v = v; + SLLQueuePush(list->first, list->last, n); + list->count += 1; + return n; +} + RDI_PROC RDIM_Type * rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap) { @@ -1039,9 +1208,10 @@ rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *ri } else { - left_dst->last_op = right_destroyed->last_op; - left_dst->op_count += right_destroyed->op_count; - left_dst->encoded_size += right_destroyed->encoded_size; + left_dst->last_op->next = right_destroyed->first_op; + left_dst->last_op = right_destroyed->last_op; + left_dst->op_count += right_destroyed->op_count; + left_dst->encoded_size += right_destroyed->encoded_size; } rdim_memzero_struct(right_destroyed); } @@ -1109,6 +1279,59 @@ rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM scopes->location_count +=1; } +//- location block chunk list + +RDI_PROC RDI_LocationBlock * +rdim_location_block_chunk_list_push_array(RDIM_Arena *arena, RDIM_String8List *list, RDI_U32 count) +{ + RDI_LocationBlock *result = rdim_push_array(arena, RDI_LocationBlock, count); + RDIM_String8 string = rdim_str8((RDI_U8*)result, sizeof(result[0]) * count); + rdim_str8_list_push(arena, list, string); + return result; +} + +RDI_PROC RDI_U32 +rdim_count_from_location_block_chunk_list(RDIM_String8List *list) +{ + RDI_U32 count = list->total_size / sizeof(RDI_LocationBlock); + return count; +} + +//////////////////////////////// + +RDI_PROC RDIM_Type * +rdim_builtin_type_from_kind(RDIM_TypeChunkList list, RDI_TypeKind type_kind) +{ + return &list.first->v[type_kind]; +} + +RDI_PROC RDIM_TypeChunkList +rdim_init_type_chunk_list(RDIM_Arena *arena, RDI_Arch arch) +{ + RDIM_TypeChunkList list = {0}; + + RDI_U64 type_cap = (RDI_TypeKind_LastBuiltIn - RDI_TypeKind_FirstBuiltIn) + 2; + + // RDI_TypeKind_NULL + rdim_type_chunk_list_push(arena, &list, type_cap); + + for(RDI_TypeKind type_kind = RDI_TypeKind_FirstBuiltIn; type_kind <= RDI_TypeKind_LastBuiltIn; type_kind += 1) + { + RDIM_Type *type = rdim_type_chunk_list_push(arena, &list, type_cap); + type->name.str = rdi_string_from_type_kind(type_kind, &type->name.size); + type->kind = type_kind; + type->byte_size = rdi_size_from_basic_type_kind(type_kind); + } + + RDIM_Type *void_type = rdim_builtin_type_from_kind(list, RDI_TypeKind_Void); + void_type->byte_size = rdi_addr_size_from_arch(arch); + + RDIM_Type *handle_type = rdim_builtin_type_from_kind(list, RDI_TypeKind_Handle); + handle_type->byte_size = rdi_addr_size_from_arch(arch); + + return list; +} + //////////////////////////////// //~ rjf: [Baking Helpers] Baked VMap Building @@ -1698,6 +1921,25 @@ rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) } } + // rjf: .. -> go up + if(sub_dir.RDIM_String8_SizeMember == 2 && + sub_dir.RDIM_String8_BaseMember[0] == '.' && + sub_dir.RDIM_String8_BaseMember[1] == '.') + { + sub_dir_node = node->parent; + if(sub_dir_node == 0) + { + sub_dir_node = &tree->root; + } + } + + // rjf: . -> stay here + else if(sub_dir.RDIM_String8_SizeMember == 1 && + sub_dir.RDIM_String8_BaseMember[0] == '.') + { + sub_dir_node = node; + } + // rjf: descend to child node = sub_dir_node; } @@ -1752,8 +1994,27 @@ rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_Stri } } + // rjf: .. -> go up + if(sub_dir.RDIM_String8_SizeMember == 2 && + sub_dir.RDIM_String8_BaseMember[0] == '.' && + sub_dir.RDIM_String8_BaseMember[1] == '.') + { + sub_dir_node = node->parent; + if(sub_dir_node == 0) + { + sub_dir_node = &tree->root; + } + } + + // rjf: . -> stay here + else if(sub_dir.RDIM_String8_SizeMember == 1 && + sub_dir.RDIM_String8_BaseMember[0] == '.') + { + sub_dir_node = node; + } + // rjf: no child -> make one - if(sub_dir_node == 0) + else if(sub_dir_node == 0) { sub_dir_node = rdim_push_array(arena, RDIM_BakePathNode, 1); RDIM_SLLQueuePush_N(tree->first, tree->last, sub_dir_node, next_order); @@ -2102,6 +2363,7 @@ rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDI for(RDI_U64 idx = 0; idx < n->count; idx += 1) { RDI_U32 type_idx = (RDI_U32)rdim_idx_from_type(&n->v[idx]); // TODO(rjf): @u64_to_u32 + if(type_idx == 0) {continue;} rdim_bake_name_map_push(arena, map, n->v[idx].name, type_idx); } } @@ -2939,13 +3201,13 @@ RDI_PROC RDIM_TypeNodeBakeResult rdim_bake_types(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_TypeChunkList *src) { RDI_TypeNode *type_nodes = push_array(arena, RDI_TypeNode, src->total_count+1); - RDI_U32 dst_idx = 1; for(RDIM_TypeChunkNode *n = src->first; n != 0; n = n->next) { - for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) { - RDIM_Type *src = &n->v[chunk_idx]; - RDI_TypeNode *dst = &type_nodes[dst_idx]; + RDIM_Type *src = &n->v[chunk_idx]; + U64 dst_idx = rdim_idx_from_type(src); + RDI_TypeNode *dst = &type_nodes[dst_idx]; //- rjf: fill shared type node info dst->kind = src->kind; @@ -2958,6 +3220,17 @@ rdim_bake_types(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeId dst->built_in.name_string_idx = rdim_bake_idx_from_string(strings, src->name); } + else if(dst->kind == RDI_TypeKind_Array) + { + U64 direct_byte_size = 1; + if(src->direct_type && src->direct_type->byte_size > 0) + { + direct_byte_size = src->direct_type->byte_size; + } + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); + dst->constructed.count = src->byte_size / direct_byte_size; + } + //- rjf: fill constructed type node info else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) { @@ -3224,8 +3497,103 @@ rdim_bake_thread_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, return result; } +RDI_PROC U64 +rdim_bake_location(RDIM_Arena *arena, RDIM_String8List *location_data_blobs, RDIM_Location *src_location) +{ + U64 location_data_off = location_data_blobs->total_size; + + // rjf: nil location + if(src_location == 0) + { + rdim_str8_list_push_align(arena, location_data_blobs, 8); + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_lit("\0")); + } + + // rjf: valid location + else switch(src_location->kind) + { + // rjf: catchall unsupported case + default: + { + rdim_str8_list_push_align(arena, location_data_blobs, 8); + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_lit("\0")); + }break; + + // rjf: bytecode streams + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: + { + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&src_location->kind))); + for(RDIM_EvalBytecodeOp *op_node = src_location->bytecode.first_op; + op_node != 0; + op_node = op_node->next) + { + RDI_U8 op_data[9]; + op_data[0] = op_node->op; + rdim_memcpy(op_data + 1, &op_node->p, op_node->p_size); + RDIM_String8 op_data_str = rdim_str8(op_data, 1 + op_node->p_size); + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, op_data_str)); + } + { + RDI_U64 data = 0; + RDIM_String8 data_str = rdim_str8((RDI_U8 *)&data, 1); + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, data_str)); + } + }break; + + // rjf: simple addr+off cases + case RDI_LocationKind_AddrRegPlusU16: + case RDI_LocationKind_AddrAddrRegPlusU16: + { + RDI_LocationRegPlusU16 loc = {0}; + loc.kind = src_location->kind; + loc.reg_code = src_location->reg_code; + loc.offset = src_location->offset; + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&loc))); + }break; + + // rjf: register cases + case RDI_LocationKind_ValReg: + { + RDI_LocationReg loc = {0}; + loc.kind = src_location->kind; + loc.reg_code = src_location->reg_code; + rdim_str8_list_push(arena, location_data_blobs, rdim_str8_copy(arena, rdim_str8_struct(&loc))); + }break; + } + + return location_data_off; +} + +RDI_PROC RDI_U32 +rdim_bake_locset(RDIM_Arena *arena, + RDIM_String8List *location_blocks, + RDIM_String8List *location_data_blobs, + RDIM_LocationSet locset) +{ + RDI_U32 locset_idx = 0; + if(locset.location_case_count > 0) + { + locset_idx = rdim_count_from_location_block_chunk_list(location_blocks); + + RDI_LocationBlock *dst_arr = rdim_location_block_chunk_list_push_array(arena, location_blocks, locset.location_case_count); + RDI_LocationBlock *dst = dst_arr; + for(RDIM_LocationCase *src = locset.first_location_case; src != 0; src = src->next, ++dst) + { + dst->scope_off_first = src->voff_range.min; + dst->scope_off_opl = src->voff_range.max; + dst->location_data_off = rdim_bake_location(arena, location_data_blobs, src->location); + } + } + return locset_idx; +} + RDI_PROC RDIM_ProcedureBakeResult -rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src) +rdim_bake_procedures(RDIM_Arena *arena, + RDIM_BakeStringMapTight *strings, + RDIM_String8List *location_blocks, + RDIM_String8List *location_data_blobs, + RDIM_SymbolChunkList *src) { RDI_Procedure *procedures = push_array(arena, RDI_Procedure, src->total_count+1); RDI_U32 dst_idx = 1; @@ -3233,8 +3601,12 @@ rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_S { for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) { - RDIM_Symbol *src = &n->v[chunk_idx]; + RDIM_Symbol *src = &n->v[chunk_idx]; RDI_Procedure *dst = &procedures[dst_idx]; + + RDI_U32 frame_base_location_first = rdim_bake_locset(arena, location_blocks, location_data_blobs, src->frame_base); + RDI_U32 frame_base_location_opl = frame_base_location_first + src->frame_base.location_case_count; + dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); dst->link_name_string_idx = rdim_bake_idx_from_string(strings, src->link_name); if(src->is_extern) @@ -3251,8 +3623,10 @@ rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_S dst->link_flags |= RDI_LinkFlag_ProcScoped; dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 } - dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 - dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + dst->root_scope_idx = (RDI_U32)rdim_idx_from_scope(src->root_scope); // TODO(rjf): @u64_to_u32 + dst->frame_base_location_first = frame_base_location_first; + dst->frame_base_location_opl = frame_base_location_opl; } } RDIM_ProcedureBakeResult result = {0}; @@ -3262,30 +3636,32 @@ rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_S } RDI_PROC RDIM_ScopeBakeResult -rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_ScopeChunkList *src) +rdim_bake_scopes(RDIM_Arena *arena, + RDIM_BakeStringMapTight *strings, + RDIM_String8List *location_blocks, + RDIM_String8List *location_data_blobs, + RDIM_ScopeChunkList *src) { RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); //////////////////////////// //- rjf: build all scopes, scope voffs, locals, and location blocks // - RDI_Scope * scopes = rdim_push_array(arena, RDI_Scope, src->total_count+1); - RDI_U64 * scope_voffs = rdim_push_array(arena, RDI_U64, src->scope_voff_count+1); - RDI_Local * locals = rdim_push_array(arena, RDI_Local, src->local_count+1); - RDI_LocationBlock * location_blocks = rdim_push_array(arena, RDI_LocationBlock, src->location_count+1); - RDIM_String8List location_data_blobs = {0}; + RDI_Scope *scopes = rdim_push_array(arena, RDI_Scope, src->total_count+1); + RDI_U64 *scope_voffs = rdim_push_array(arena, RDI_U64, src->scope_voff_count+1); + RDI_Local *locals = rdim_push_array(arena, RDI_Local, src->local_count+1); + RDIM_ProfScope("build all scopes, scope voffs, locals, and location blocks") { - RDI_U64 dst_scope_idx = 1; + RDI_U64 dst_scope_idx = 1; RDI_U64 dst_scope_voff_idx = 1; - RDI_U64 dst_local_idx = 1; - RDI_U64 dst_location_block_idx = 1; + RDI_U64 dst_local_idx = 1; for(RDIM_ScopeChunkNode *chunk_n = src->first; chunk_n != 0; chunk_n = chunk_n->next) { for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1, dst_scope_idx += 1) { RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; - RDI_Scope *dst_scope = &scopes[dst_scope_idx]; + RDI_Scope *dst_scope = &scopes[dst_scope_idx]; //- rjf: push scope's voffs RDI_U64 voff_idx_first = dst_scope_voff_idx; @@ -3306,91 +3682,17 @@ rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_Scope src_local != 0; src_local = src_local->next, dst_local_idx += 1) { - //- rjf: push local's locations - RDI_U64 location_block_idx_first = dst_location_block_idx; - for(RDIM_LocationCase *loccase = src_local->locset.first_location_case; - loccase != 0; - loccase = loccase->next, dst_location_block_idx += 1) - { - // rjf: fill location block - RDI_LocationBlock *dst_locblock = &location_blocks[dst_location_block_idx]; - dst_locblock->scope_off_first = loccase->voff_range.min; - dst_locblock->scope_off_opl = loccase->voff_range.max; - dst_locblock->location_data_off = location_data_blobs.total_size; - - // rjf: serialize location into location data - RDIM_Location *src_location = loccase->location; - { - // rjf: nil location - if(src_location == 0) - { - rdim_str8_list_push_align(scratch.arena, &location_data_blobs, 8); - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_lit("\0")); - } - - // rjf: valid location - else switch(src_location->kind) - { - // rjf: catchall unsupported case - default: - { - rdim_str8_list_push_align(scratch.arena, &location_data_blobs, 8); - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_lit("\0")); - }break; - - // rjf: bytecode streams - case RDI_LocationKind_AddrBytecodeStream: - case RDI_LocationKind_ValBytecodeStream: - { - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_copy(scratch.arena, rdim_str8_struct(&src_location->kind))); - for(RDIM_EvalBytecodeOp *op_node = src_location->bytecode.first_op; - op_node != 0; - op_node = op_node->next) - { - RDI_U8 op_data[9]; - op_data[0] = op_node->op; - rdim_memcpy(op_data + 1, &op_node->p, op_node->p_size); - RDIM_String8 op_data_str = rdim_str8(op_data, 1 + op_node->p_size); - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_copy(scratch.arena, op_data_str)); - } - { - RDI_U64 data = 0; - RDIM_String8 data_str = rdim_str8((RDI_U8 *)&data, 1); - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_copy(scratch.arena, data_str)); - } - }break; - - // rjf: simple addr+off cases - case RDI_LocationKind_AddrRegPlusU16: - case RDI_LocationKind_AddrAddrRegPlusU16: - { - RDI_LocationRegPlusU16 loc = {0}; - loc.kind = src_location->kind; - loc.reg_code = src_location->reg_code; - loc.offset = src_location->offset; - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_copy(scratch.arena, rdim_str8_struct(&loc))); - }break; - - // rjf: register cases - case RDI_LocationKind_ValReg: - { - RDI_LocationReg loc = {0}; - loc.kind = src_location->kind; - loc.reg_code = src_location->reg_code; - rdim_str8_list_push(scratch.arena, &location_data_blobs, rdim_str8_copy(scratch.arena, rdim_str8_struct(&loc))); - }break; - } - } - } - RDI_U64 location_block_idx_opl = dst_location_block_idx; + // bake location sets + RDI_U32 location_block_idx_first = rdim_bake_locset(arena, location_blocks, location_data_blobs, src_local->locset); + RDI_U32 location_block_idx_opl = location_block_idx_first + src_local->locset.location_case_count; //- rjf: fill local - RDI_Local *dst_local = &locals[dst_local_idx]; + RDI_Local *dst_local = &locals[dst_local_idx]; dst_local->kind = src_local->kind; dst_local->name_string_idx = rdim_bake_idx_from_string(strings, src_local->name); dst_local->type_idx = (RDI_U32)rdim_idx_from_type(src_local->type); // TODO(rjf): @u64_to_u32 - dst_local->location_first = (RDI_U32)location_block_idx_first; // TODO(rjf): @u64_to_u32 - dst_local->location_opl = (RDI_U32)location_block_idx_opl; // TODO(rjf): @u64_to_u32 + dst_local->location_first = location_block_idx_first; + dst_local->location_opl = location_block_idx_opl; } RDI_U64 local_idx_opl = dst_local_idx; @@ -3408,29 +3710,16 @@ rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_Scope } } - //////////////////////////// - //- rjf: build flattened location data - // - RDIM_String8 location_data_blob = {0}; - RDIM_ProfScope("build flattened location data") - { - location_data_blob = rdim_str8_list_join(arena, &location_data_blobs, rdim_str8_lit("")); - } - //////////////////////////// //- rjf: fill result // RDIM_ScopeBakeResult result = {0}; - result.scopes = scopes; - result.scopes_count = src->total_count+1; - result.scope_voffs = scope_voffs; - result.scope_voffs_count = src->scope_voff_count+1; - result.locals = locals; - result.locals_count = src->local_count+1; - result.location_blocks = location_blocks; - result.location_blocks_count = src->location_count+1; - result.location_data = location_data_blob.str; - result.location_data_size = location_data_blob.size; + result.scopes = scopes; + result.scopes_count = src->total_count+1; + result.scope_voffs = scope_voffs; + result.scope_voffs_count = src->scope_voff_count+1; + result.locals = locals; + result.locals_count = src->local_count+1; rdim_scratch_end(scratch); return result; } @@ -3687,8 +3976,8 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results) bundle.sections[RDI_SectionKind_ScopeVMap] = rdim_serialized_section_make_unpacked_array(results->scope_vmap.vmap.vmap, results->scope_vmap.vmap.count+1); bundle.sections[RDI_SectionKind_InlineSites] = rdim_serialized_section_make_unpacked_array(results->inline_sites.inline_sites, results->inline_sites.inline_sites_count); bundle.sections[RDI_SectionKind_Locals] = rdim_serialized_section_make_unpacked_array(results->scopes.locals, results->scopes.locals_count); - bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->scopes.location_blocks, results->scopes.location_blocks_count); - bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->scopes.location_data, results->scopes.location_data_size); + bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.str, results->location_blocks.size); + bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->location_data.str, results->location_data.size); bundle.sections[RDI_SectionKind_NameMaps] = rdim_serialized_section_make_unpacked_array(results->top_level_name_maps.name_maps, results->top_level_name_maps.name_maps_count); bundle.sections[RDI_SectionKind_NameMapBuckets] = rdim_serialized_section_make_unpacked_array(results->name_maps.buckets, results->name_maps.buckets_count); bundle.sections[RDI_SectionKind_NameMapNodes] = rdim_serialized_section_make_unpacked_array(results->name_maps.nodes, results->name_maps.nodes_count); diff --git a/src/lib_rdi_make/rdi_make.h b/src/lib_rdi_make/rdi_make.h index 47ff5ade..74024ff2 100644 --- a/src/lib_rdi_make/rdi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -595,6 +595,17 @@ struct RDIM_UnitChunkList //////////////////////////////// //~ rjf: Type System Node Types +typedef RDI_U32 RDIM_DataModel; +enum RDIM_DataModelEnum +{ + RDIM_DataModel_Null, + RDIM_DataModel_ILP32, + RDIM_DataModel_LLP64, + RDIM_DataModel_LP64, + RDIM_DataModel_ILP64, + RDIM_DataModel_SILP64 +}; + typedef struct RDIM_Type RDIM_Type; struct RDIM_Type { @@ -605,11 +616,27 @@ struct RDIM_Type RDI_U32 off; RDI_U32 count; RDIM_String8 name; + RDIM_String8 link_name; RDIM_Type *direct_type; RDIM_Type **param_types; struct RDIM_UDT *udt; }; +typedef struct RDIM_TypeNode RDIM_TypeNode; +struct RDIM_TypeNode +{ + struct RDIM_TypeNode *next; + RDIM_Type *v; +}; + +typedef struct RDIM_TypeList RDIM_TypeList; +struct RDIM_TypeList +{ + U64 count; + RDIM_TypeNode *first; + RDIM_TypeNode *last; +}; + typedef struct RDIM_TypeChunkNode RDIM_TypeChunkNode; struct RDIM_TypeChunkNode { @@ -758,6 +785,7 @@ struct RDIM_Symbol RDIM_Symbol *container_symbol; RDIM_Type *container_type; struct RDIM_Scope *root_scope; + RDIM_LocationSet frame_base; }; typedef struct RDIM_SymbolChunkNode RDIM_SymbolChunkNode; @@ -1180,10 +1208,6 @@ struct RDIM_ScopeBakeResult RDI_U64 scope_voffs_count; RDI_Local *locals; RDI_U64 locals_count; - RDI_LocationBlock *location_blocks; - RDI_U64 location_blocks_count; - RDI_U8 *location_data; - RDI_U64 location_data_size; }; typedef struct RDIM_ScopeVMapBakeResult RDIM_ScopeVMapBakeResult; @@ -1261,6 +1285,8 @@ struct RDIM_BakeResults RDIM_FilePathBakeResult file_paths; RDIM_StringBakeResult strings; RDIM_IndexRunBakeResult idx_runs; + RDIM_String8 location_blocks; + RDIM_String8 location_data; }; //////////////////////////////// @@ -1334,6 +1360,19 @@ RDI_PROC RDIM_SortKey *rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys //- rjf: rng1u64 list RDI_PROC void rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r); +//////////////////////////////// +//~ Data Model + +RDI_PROC RDI_TypeKind rdim_short_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_unsigned_short_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_int_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_unsigned_int_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_long_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_unsigned_long_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_long_long_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_unsigned_long_long_type_from_data_model(RDIM_DataModel data_model); +RDI_PROC RDI_TypeKind rdim_pointer_size_t_type_from_data_model(RDIM_DataModel data_model); + //////////////////////////////// //~ rjf: [Building] Binary Section Info Building @@ -1414,6 +1453,16 @@ RDI_PROC RDIM_Location *rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg //- rjf: location sets RDI_PROC void rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location); +//- location block chunk list + +RDI_PROC RDI_LocationBlock * rdim_location_block_chunk_list_push_array(RDIM_Arena *arena, RDIM_String8List *list, RDI_U32 count); +RDI_PROC RDI_U32 rdim_count_from_location_block_chunk_list(RDIM_String8List *list); + +//////////////////////////////// + +RDI_PROC RDIM_TypeChunkList rdim_init_type_chunk_list(RDIM_Arena *arena, RDI_Arch arch); +RDI_PROC RDIM_Type * rdim_builtin_type_from_kind(RDIM_TypeChunkList list, RDI_TypeKind type_kind); + //////////////////////////////// //~ rjf: [Baking Helpers] Baked VMap Building @@ -1513,8 +1562,8 @@ RDI_PROC RDIM_UDTBakeResult rdim_bake_udts(RDIM_Arena *arena, RDIM_B RDI_PROC RDIM_GlobalVariableBakeResult rdim_bake_global_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); RDI_PROC RDIM_GlobalVMapBakeResult rdim_bake_global_vmap(RDIM_Arena *arena, RDIM_SymbolChunkList *src); RDI_PROC RDIM_ThreadVariableBakeResult rdim_bake_thread_variables(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ProcedureBakeResult rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_SymbolChunkList *src); -RDI_PROC RDIM_ScopeBakeResult rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_ScopeChunkList *src); +RDI_PROC RDIM_ProcedureBakeResult rdim_bake_procedures(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_String8List *location_blocks, RDIM_String8List *location_data_blobs, RDIM_SymbolChunkList *src); +RDI_PROC RDIM_ScopeBakeResult rdim_bake_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_String8List *location_blocks, RDIM_String8List *location_data_blobs, RDIM_ScopeChunkList *src); RDI_PROC RDIM_ScopeVMapBakeResult rdim_bake_scope_vmap(RDIM_Arena *arena, RDIM_ScopeChunkList *src); RDI_PROC RDIM_InlineSiteBakeResult rdim_bake_inline_sites(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_InlineSiteChunkList *src); RDI_PROC RDIM_TopLevelNameMapBakeResult rdim_bake_name_maps_top_level(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT]); diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index 4566eb67..1f1ed5ec 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -4,7 +4,16 @@ internal void bucket_list_concat_in_place(BucketList *list, BucketList *to_concat) { - SLLConcatInPlaceNoCount(list, to_concat); + if (to_concat->first) { + if (list->first) { + list->last->next = to_concat->first; + list->last = to_concat->last; + } else { + list->first = to_concat->first; + list->last = to_concat->last; + } + MemoryZeroStruct(to_concat); + } } internal BucketNode * @@ -120,17 +129,28 @@ hash_table_push_u64_u64(Arena *arena, HashTable *ht, U64 key, U64 value) return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_u64 = key, .value_u64 = value }); } +internal String8 +hash_table_normalize_path_string(Arena *arena, String8 path) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 result; + result = lower_from_str8(scratch.arena, path); + result = path_convert_slashes(arena, result, PathStyle_UnixAbsolute); + scratch_end(scratch); + return result; +} + internal BucketNode * hash_table_push_path_string(Arena *arena, HashTable *ht, String8 path, String8 value) { - String8 path_canon = path_canon_from_regular_path(arena, path); + String8 path_canon = hash_table_normalize_path_string(arena, path); return hash_table_push_string_string(arena, ht, path_canon, value); } internal BucketNode * hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value) { - String8 path_canon = path_canon_from_regular_path(arena, path); + String8 path_canon = hash_table_normalize_path_string(arena, path); U64 hash = hash_table_hasher(path_canon); return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_u64 = value }); } @@ -138,7 +158,7 @@ hash_table_push_path_u64(Arena *arena, HashTable *ht, String8 path, U64 value) internal BucketNode * hash_table_push_path_raw(Arena *arena, HashTable *ht, String8 path, void *value) { - String8 path_canon = path_canon_from_regular_path(arena, path); + String8 path_canon = hash_table_normalize_path_string(arena, path); U64 hash = hash_table_hasher(path_canon); return hash_table_push(arena, ht, hash, (KeyValuePair){ .key_string = path_canon, .value_raw = value }); } @@ -187,6 +207,13 @@ hash_table_search_u64(HashTable *ht, U64 key_u64) return 0; } +internal void * +hash_table_search_u64_raw(HashTable *ht, U64 key_u64) +{ + KeyValuePair *kv = hash_table_search_u64(ht, key_u64); + return kv ? kv->value_raw : 0; +} + internal KeyValuePair * hash_table_search_path(HashTable *ht, String8 path) { @@ -199,6 +226,20 @@ hash_table_search_path(HashTable *ht, String8 path) return result; } +internal void * +hash_table_search_path_raw(HashTable *ht, String8 path) +{ + KeyValuePair *kv = hash_table_search_path(ht, path); + return kv ? kv->value_raw : 0; +} + +internal void * +hash_table_(HashTable *ht, String8 path) +{ + KeyValuePair *result = hash_table_search_path(ht, path); + return result ? result->value_raw : 0; +} + internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) { @@ -315,3 +356,23 @@ remove_duplicates_u64_array(Arena *arena, U64Array arr) scratch_end(scratch); return result; } + +internal String8List +remove_duplicates_str8_list(Arena *arena, String8List list) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List result = {0}; + HashTable *ht = hash_table_init(scratch.arena, list.node_count); + + for (String8Node *node = list.first; node != 0; node = node->next) { + KeyValuePair *is_present = hash_table_search_string(ht, node->string); + if (!is_present) { + hash_table_push_string_raw(scratch.arena, ht, node->string, 0); + str8_list_push(arena, &result, node->string); + } + } + + scratch_end(scratch); + return result; +} diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 51e55a0e..b35c9fcf 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -7,6 +7,7 @@ typedef struct KeyValuePair { union { String8 key_string; + void *key_raw; U32 key_u32; U64 key_u64; }; @@ -67,21 +68,24 @@ internal BucketNode * hash_table_push_u64_u64 (Arena *arena, HashTable *ht, //- search internal KeyValuePair * hash_table_search_string (HashTable *ht, String8 string); -internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key); -internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key); -internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 path); +internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key ); +internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key ); +internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 path ); +internal void * hash_table_search_path_raw(HashTable *ht, String8 path ); internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out); //- key-value helpers -internal U32 * keys_from_hash_table_u32(Arena *arena, HashTable *ht); -internal U64 * keys_from_hash_table_u64(Arena *arena, HashTable *ht); +internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable *ht); +internal U64 * keys_from_hash_table_u64 (Arena *arena, HashTable *ht); internal KeyValuePair * key_value_pairs_from_hash_table(Arena *arena, HashTable *ht); -internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); -internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); + +internal void sort_key_value_pairs_as_u32(KeyValuePair *pairs, U64 count); +internal void sort_key_value_pairs_as_u64(KeyValuePair *pairs, U64 count); //////////////////////////////// -internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr); +internal U64Array remove_duplicates_u64_array(Arena *arena, U64Array arr); +internal String8List remove_duplicates_str8_list(Arena *arena, String8List list); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 4960fb17..b5fa1ea7 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -5,7 +5,7 @@ // Build Options #define BUILD_CONSOLE_INTERFACE 1 -#define BUILD_TITLE "Epic Games Tools (R) RAD COFF/PE Linker" +#define BUILD_TITLE "Epic Games Tools (R) RAD PE/COFF Linker" //////////////////////////////// @@ -78,7 +78,6 @@ // Code Base Extensions #include "base_ext/base_inc.h" -#include "path_ext/path.h" #include "hash_table.h" #include "thread_pool/thread_pool.h" #include "codeview_ext/codeview.h" @@ -88,7 +87,6 @@ #include "pdb_ext/pdb_builder.h" #include "base_ext/base_inc.c" -#include "path_ext/path.c" #include "hash_table.c" #include "thread_pool/thread_pool.c" #include "codeview_ext/codeview.c" @@ -348,24 +346,29 @@ lnk_manifest_from_inputs(Arena *arena, String8List input_manifest_path_list, String8List deps_list) { + Temp scratch = scratch_begin(&arena, 1); + + String8List unique_deps = remove_duplicates_str8_list(scratch.arena, deps_list); + String8 manifest_data; if (input_manifest_path_list.node_count > 0) { ProfBegin("Merge Manifests"); - Temp scratch = scratch_begin(&arena, 1); - String8 linker_manifest = lnk_make_linker_manifest(scratch.arena, manifest_uac, manifest_level, manifest_ui_access, deps_list); + String8 linker_manifest = lnk_make_linker_manifest(scratch.arena, manifest_uac, manifest_level, manifest_ui_access, unique_deps); // write linker manifest to temp file String8 linker_manifest_path = push_str8f(scratch.arena, "%S.manifest.temp", manifest_name); - lnk_write_data_to_file_path(linker_manifest_path, linker_manifest); + lnk_write_data_to_file_path(linker_manifest_path, str8_zero(), linker_manifest); + + String8List unique_input_manifest_paths = remove_duplicates_str8_list(scratch.arena, input_manifest_path_list); // push linker manifest - str8_list_push(scratch.arena, &input_manifest_path_list, linker_manifest_path); + str8_list_push(scratch.arena, &unique_input_manifest_paths, linker_manifest_path); // launch mt.exe to merge input manifests String8 merged_manifest_path = push_str8f(scratch.arena, "%S.manifest.merged", manifest_name); - lnk_merge_manifest_files(mt_path, merged_manifest_path, input_manifest_path_list); + lnk_merge_manifest_files(mt_path, merged_manifest_path, unique_input_manifest_paths); // read mt.exe output from disk manifest_data = lnk_read_data_from_file_path(arena, merged_manifest_path); @@ -377,12 +380,12 @@ lnk_manifest_from_inputs(Arena *arena, os_delete_file_at_path(linker_manifest_path); os_delete_file_at_path(merged_manifest_path); - scratch_end(scratch); ProfEnd(); } else { - manifest_data = lnk_make_linker_manifest(arena, manifest_uac, manifest_level, manifest_ui_access, deps_list); + manifest_data = lnk_make_linker_manifest(arena, manifest_uac, manifest_level, manifest_ui_access, unique_deps); } + scratch_end(scratch); return manifest_data; } @@ -411,13 +414,13 @@ lnk_res_number_id_is_before(void *raw_a, void *raw_b) } internal void -lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir) +lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_Section *dir_sect = lnk_section_table_push(st, str8_lit(".rsrc$01"), LNK_RSRC_SECTION_FLAGS); - LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".rsrc$02"), LNK_RSRC_SECTION_FLAGS); + LNK_Section *dir_sect = lnk_section_table_push(sectab, str8_lit(".rsrc$01"), LNK_RSRC_SECTION_FLAGS); + LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".rsrc$02"), LNK_RSRC_SECTION_FLAGS); LNK_Chunk *dir_tree_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); LNK_Chunk *dir_data_chunk = lnk_section_push_chunk_list(dir_sect, dir_sect->root, str8_zero()); @@ -577,7 +580,7 @@ lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE } internal void -lnk_add_resource_debug_s(LNK_SectionTable *st, +lnk_add_resource_debug_s(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 obj_path, String8 cwd_path, @@ -671,7 +674,7 @@ lnk_add_resource_debug_s(LNK_SectionTable *st, str8_serial_push_data_list(scratch.arena, &sub_sect_srl, symbol_srl.first); str8_serial_push_align(scratch.arena, &sub_sect_srl, CV_C13SubSectionAlign); - LNK_Section *debug_s = lnk_section_table_push(st, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); + LNK_Section *debug_s = lnk_section_table_push(sectab, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); String8 sub_sect_data = str8_serial_end(debug_s->arena, &sub_sect_srl); lnk_section_push_chunk_data(debug_s, debug_s->root, sub_sect_data, str8_zero()); @@ -703,24 +706,24 @@ lnk_make_res_obj(TP_Context *tp, temp_tp_arena->v[0] = arena_alloc(); LNK_SymbolTable *symtab = lnk_symbol_table_init(temp_tp_arena); - LNK_SectionTable *st = lnk_section_table_alloc(0, sect_virt_align, sect_file_align); - LNK_Section *header_sect = lnk_section_table_push(st, str8_lit(".null"), 0); + LNK_SectionTable *sectab = lnk_section_table_alloc(0, sect_virt_align, sect_file_align); + LNK_Section *header_sect = lnk_section_table_push(sectab, str8_lit(".null"), 0); - lnk_serialize_pe_resource_tree(st, symtab, root_dir); + lnk_serialize_pe_resource_tree(sectab, symtab, root_dir); CV_Arch cv_arch = cv_arch_from_coff_machine(machine); - lnk_add_resource_debug_s(st, symtab, path, cwd_path, exe_path, cv_arch, res_file_list, res_hash_array); + lnk_add_resource_debug_s(sectab, symtab, path, cwd_path, exe_path, cv_arch, res_file_list, res_hash_array); // register section symbols (after this point don't push new sections) - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; lnk_symbol_table_push_defined_chunk(symtab, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } - st->null_sect = lnk_section_list_remove(&st->list, str8_lit(".null")); - lnk_section_table_build_data(tp, st, machine); - lnk_section_table_push_null(st); - lnk_section_table_assign_indices(st); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + sectab->null_sect = lnk_section_list_remove(§ab->list, str8_lit(".null")); + lnk_section_table_build_data(tp, sectab, machine); + lnk_section_table_push_null(sectab); + lnk_section_table_assign_indices(sectab); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); COFF_Symbol16List coff_symbol_list = {0}; @@ -732,7 +735,7 @@ lnk_make_res_obj(TP_Context *tp, coff_symbol16_list_push(scratch.arena, &coff_symbol_list, coff_feat00); // emit coff symbols for section definitions - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; if (sect == header_sect) continue; if (!sect->emit_header) continue; @@ -765,7 +768,7 @@ lnk_make_res_obj(TP_Context *tp, // convert relocations and symbols to coff format { - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; // filter out resource relocations @@ -824,8 +827,8 @@ lnk_make_res_obj(TP_Context *tp, if (coff_reloc_list.count == 0) continue; // push section for relocation data - String8 sect_name = push_str8f(st->arena, "%S.relocs", sect->name); - LNK_Section *reloc_sect = lnk_section_table_push(st, sect_name, 0); + String8 sect_name = push_str8f(sectab->arena, "%S.relocs", sect->name); + LNK_Section *reloc_sect = lnk_section_table_push(sectab, sect_name, 0); reloc_sect->emit_header = 0; // push chunk layout for relocations @@ -845,7 +848,7 @@ lnk_make_res_obj(TP_Context *tp, } } - LNK_Section *misc_sect = lnk_section_table_push(st, str8_lit(".misc"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove); + LNK_Section *misc_sect = lnk_section_table_push(sectab, str8_lit(".misc"), COFF_SectionFlag_LnkInfo|COFF_SectionFlag_LnkRemove); misc_sect->emit_header = 0; // serialize coff symbol list @@ -891,9 +894,9 @@ lnk_make_res_obj(TP_Context *tp, // build section headers { LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { - if (sect_node == st->null_sect) continue; - if (!sect_node->data.emit_header) continue; + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { + if (sect_node == sectab->null_sect) continue; + if (!sect_node->data.emit_header) continue; LNK_Section *sect = §_node->data; // init section header @@ -938,13 +941,13 @@ lnk_make_res_obj(TP_Context *tp, lnk_symbol_table_push(symtab, coff_section_header_count_symbol); } - lnk_section_table_assign_indices(st); - lnk_section_table_build_data(tp, st, machine); - lnk_section_table_assign_file_offsets(st); - String8 res_obj = lnk_section_table_serialize(tp, arena, st, machine); - sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); - lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, res_obj, 0); - lnk_section_table_release(&st); + lnk_section_table_assign_indices(sectab); + lnk_section_table_build_data(tp, sectab, machine); + lnk_section_table_assign_file_offsets(sectab); + String8 res_obj = lnk_section_table_serialize(tp, arena, sectab, machine); + sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); + lnk_patch_relocs_linker(tp, symtab, sectab, sect_id_map, res_obj, 0); + lnk_section_table_release(§ab); arena_release(temp_tp_arena->v[0]); scratch_end(scratch); @@ -955,7 +958,7 @@ lnk_make_res_obj(TP_Context *tp, internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, - LNK_SectionTable *st, + LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8List res_data_list, String8List res_path_list, @@ -1027,10 +1030,10 @@ lnk_make_linker_coff_obj(TP_Context *tp, temp_tp_arena->count = 1; LNK_SymbolTable *symtab = lnk_symbol_table_init(temp_tp_arena); - LNK_SectionTable *st = lnk_section_table_alloc(0, 1, 1); + LNK_SectionTable *sectab = lnk_section_table_alloc(0, 1, 1); - LNK_Section *header_sect = lnk_section_table_push(st, str8_lit(".coffhdr"), 0); - LNK_Section *debug_s_sect = lnk_section_table_push(st, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); + LNK_Section *header_sect = lnk_section_table_push(sectab, str8_lit(".coffhdr"), 0); + LNK_Section *debug_s_sect = lnk_section_table_push(sectab, str8_lit(".debug$S"), LNK_DEBUG_SECTION_FLAGS); // TODO: remove! hack! header_sect->emit_header = 0; @@ -1102,15 +1105,15 @@ lnk_make_linker_coff_obj(TP_Context *tp, { // register section symbols (after this point don't push new sections) - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; lnk_symbol_table_push_defined_chunk(symtab, sect->name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } LNK_Chunk *coff_section_header_array_chunk = lnk_section_push_chunk_list(header_sect, header_sect->root, str8_zero()); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { - if (sect_node == st->null_sect) continue; - if (!sect_node->data.emit_header) continue; + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { + if (sect_node == sectab->null_sect) continue; + if (!sect_node->data.emit_header) continue; LNK_Section *sect = §_node->data; // init section header @@ -1154,14 +1157,14 @@ lnk_make_linker_coff_obj(TP_Context *tp, lnk_symbol_table_push(symtab, coff_section_header_count_symbol); } - lnk_section_table_assign_indices(st); - lnk_section_table_build_data(tp, st, machine); - lnk_section_table_assign_file_offsets(st); - String8 coff_data = lnk_section_table_serialize(tp, arena, st, machine); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); - lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, coff_data, 0); + lnk_section_table_assign_indices(sectab); + lnk_section_table_build_data(tp, sectab, machine); + lnk_section_table_assign_file_offsets(sectab); + String8 coff_data = lnk_section_table_serialize(tp, arena, sectab, machine); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); + lnk_patch_relocs_linker(tp, symtab, sectab, sect_id_map, coff_data, 0); - lnk_section_table_release(&st); + lnk_section_table_release(§ab); scratch_end(scratch); return coff_data; @@ -1285,7 +1288,7 @@ lnk_push_linker_symbols(LNK_SymbolTable *symtab, COFF_MachineType machine) LNK_Symbol *image_base = lnk_symbol_table_push_defined_chunk(symtab, str8_lit("__ImageBase"), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_Any, 0); { // load config symbols - if (machine == COFF_Machine_X86) { + if (machine == COFF_MachineType_X86) { lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_TABLE_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0); lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_SAFE_SE_HANDLER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Extern, 0, g_null_chunk_ptr, 0, COFF_ComdatSelect_NoDuplicates, 0); } @@ -1375,7 +1378,7 @@ lnk_push_pe_debug_data_directory(LNK_Section *sect, } internal void -lnk_build_debug_pdb(LNK_SectionTable *st, +lnk_build_debug_pdb(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_Section *sect, LNK_Chunk *dir_array_chunk, @@ -1402,7 +1405,7 @@ lnk_build_debug_pdb(LNK_SectionTable *st, } internal void -lnk_build_debug_rdi(LNK_SectionTable *st, +lnk_build_debug_rdi(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_Section *debug_sect, LNK_Chunk *debug_dir_array_chunk, @@ -1412,7 +1415,7 @@ lnk_build_debug_rdi(LNK_SectionTable *st, { ProfBeginFunction(); - LNK_Section *rdi_sect = lnk_section_table_push(st, str8_lit(".raddbg"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead); + LNK_Section *rdi_sect = lnk_section_table_push(sectab, str8_lit(".raddbg"), COFF_SectionFlag_CntInitializedData|COFF_SectionFlag_MemRead); // push chunks String8 debug_rdi = pe_make_debug_header_rdi(rdi_sect->arena, guid, rdi_path); @@ -1431,7 +1434,7 @@ lnk_build_debug_rdi(LNK_SectionTable *st, internal void lnk_build_guard_tables(TP_Context *tp, - LNK_SectionTable *st, + LNK_SectionTable *sectab, LNK_SymbolTable *symtab, LNK_ExportTable *exptab, LNK_ObjList obj_list, @@ -1443,7 +1446,7 @@ lnk_build_guard_tables(TP_Context *tp, ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); enum { GUARD_FIDS, GUARD_IATS, GUARD_LJMP, GUARD_EHCONT, GUARD_COUNT }; LNK_SymbolList guard_symbol_list_table[GUARD_COUNT]; MemoryZeroStruct(&guard_symbol_list_table[0]); @@ -1558,8 +1561,8 @@ lnk_build_guard_tables(TP_Context *tp, #endif // build section data - lnk_section_table_build_data(tp, st, machine); - lnk_section_table_assign_virtual_offsets(st); + lnk_section_table_build_data(tp, sectab, machine); + lnk_section_table_assign_virtual_offsets(sectab); // compute symbols virtual offsets U64Array guard_voff_arr_table[GUARD_COUNT]; @@ -1601,12 +1604,12 @@ lnk_build_guard_tables(TP_Context *tp, { ".gehcont", LNK_GEHCONT_SYMBOL_NAME, LNK_GEHCONT_SECTION_FLAGS }, }; for (U64 i = 0; i < ArrayCount(sect_layout); ++i) { - LNK_Section *sect = lnk_section_table_push(st, str8_cstring(sect_layout[i].name), sect_layout[i].flags); + LNK_Section *sect = lnk_section_table_push(sectab, str8_cstring(sect_layout[i].name), sect_layout[i].flags); lnk_symbol_table_push_defined_chunk(symtab, str8_cstring(sect_layout[i].symbol), LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } // TODO: emit table for SEH on X86 - if (machine == COFF_Machine_X86) { + if (machine == COFF_MachineType_X86) { lnk_not_implemented("__safe_se_handler_table"); lnk_not_implemented("__safe_se_handler_count"); } @@ -1616,10 +1619,10 @@ lnk_build_guard_tables(TP_Context *tp, LNK_Symbol *gljmp_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_GLJMP_SYMBOL_NAME)); LNK_Symbol *gehcont_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_GEHCONT_SYMBOL_NAME)); - LNK_Section *gfids_sect = lnk_section_table_search_id(st, gfids_symbol->u.defined.u.chunk->ref.sect_id); - LNK_Section *giats_sect = lnk_section_table_search_id(st, giats_symbol->u.defined.u.chunk->ref.sect_id); - LNK_Section *gljmp_sect = lnk_section_table_search_id(st, gljmp_symbol->u.defined.u.chunk->ref.sect_id); - LNK_Section *gehcont_sect = lnk_section_table_search_id(st, gehcont_symbol->u.defined.u.chunk->ref.sect_id); + LNK_Section *gfids_sect = lnk_section_table_search_id(sectab, gfids_symbol->u.defined.u.chunk->ref.sect_id); + LNK_Section *giats_sect = lnk_section_table_search_id(sectab, giats_symbol->u.defined.u.chunk->ref.sect_id); + LNK_Section *gljmp_sect = lnk_section_table_search_id(sectab, gljmp_symbol->u.defined.u.chunk->ref.sect_id); + LNK_Section *gehcont_sect = lnk_section_table_search_id(sectab, gehcont_symbol->u.defined.u.chunk->ref.sect_id); LNK_Chunk *gfids_array_chunk = gfids_sect->root; LNK_Chunk *giats_array_chunk = giats_sect->root; @@ -1680,7 +1683,7 @@ lnk_build_guard_tables(TP_Context *tp, gflags_def->u.va |= PE_LoadConfigGuardFlags_EH_CONTINUATION_TABLE_PRESENT; } { - LNK_Section *didat_sect = lnk_section_table_search(st, str8_lit(".didat")); + LNK_Section *didat_sect = lnk_section_table_search(sectab, str8_lit(".didat")); if (didat_sect) { gflags_def->u.va |= PE_LoadConfigGuardFlags_DELAYLOAD_IAT_IN_ITS_OWN_SECTION; } @@ -1849,7 +1852,7 @@ lnk_base_reloc_page_array_sort(LNK_BaseRelocPageArray arr) internal void lnk_build_base_relocs(TP_Context *tp, TP_Arena *tp_arena, - LNK_SectionTable *st, + LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, @@ -1860,10 +1863,10 @@ lnk_build_base_relocs(TP_Context *tp, TP_Temp temp = tp_temp_begin(tp_arena); - lnk_section_table_build_data(tp, st, machine); - lnk_section_table_assign_virtual_offsets(st); + lnk_section_table_build_data(tp, sectab, machine); + lnk_section_table_assign_virtual_offsets(sectab); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(tp_arena->v[0], st); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(tp_arena->v[0], sectab); LNK_BaseRelocPageList *page_list_arr = push_array(tp_arena->v[0], LNK_BaseRelocPageList, tp->worker_count); HashTable **page_ht_arr = push_array_no_zero(tp_arena->v[0], HashTable *, tp->worker_count); @@ -1873,7 +1876,7 @@ lnk_build_base_relocs(TP_Context *tp, // emit pages from relocs defined in section table ProfBegin("Emit Relocs From Section Table"); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_BaseRelocTask task = {0}; task.page_size = page_size; task.sect_id_map = sect_id_map; @@ -1935,7 +1938,7 @@ lnk_build_base_relocs(TP_Context *tp, ProfEnd(); if (main_page_list->count > 0) { - LNK_Section *base_reloc_sect = lnk_section_table_push(st, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); + LNK_Section *base_reloc_sect = lnk_section_table_push(sectab, str8_lit(".reloc"), LNK_RELOC_SECTION_FLAGS); lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_BASE_RELOC_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, base_reloc_sect->root, 0, 0, 0); ProfBegin("Page List -> Array"); @@ -2010,7 +2013,8 @@ lnk_build_base_relocs(TP_Context *tp, Assert(*block_size_ptr <= buf_size); // push page chunk - lnk_section_push_chunk_raw(base_reloc_sect, base_reloc_sect->root, buf, block_size, str8_zero()); + LNK_Chunk *page_chunk = lnk_section_push_chunk_raw(base_reloc_sect, base_reloc_sect->root, buf, block_size, str8_zero()); + lnk_chunk_set_debugf(base_reloc_sect->arena, page_chunk, "Base Reloc Page (VirtOff: %#x Size: %#x, Pads: %#x)", page->voff, block_size, pad_reloc_count); // purge voffs for next run hash_table_purge(voff_ht); @@ -2275,11 +2279,11 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, } // push COFF header array chunk - LNK_Chunk *COFF_FileHeader_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); - lnk_chunk_set_debugf(header_sect->arena, COFF_FileHeader_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); + LNK_Chunk *coff_section_array_chunk = lnk_section_push_chunk_list(header_sect, parent_chunk, str8_zero()); + lnk_chunk_set_debugf(header_sect->arena, coff_section_array_chunk, LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME); // define symbol for COFF header array - lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, COFF_FileHeader_array_chunk, 0, 0, 0); + lnk_symbol_table_push_defined_chunk(symtab, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, coff_section_array_chunk, 0, 0, 0); // push headers for (LNK_Section *sect = §_arr.v[0], *sect_opl = sect + sect_arr.count; sect < sect_opl; sect += 1) { @@ -2289,38 +2293,39 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, if (!sect->has_layout) { continue; } - COFF_SectionHeader *COFF_FileHeader = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1); + COFF_SectionHeader *coff_section = push_array_no_zero(header_sect->arena, COFF_SectionHeader, 1); // TODO: for objs we can store long name in string table and write here /offset - if (sect->name.size > sizeof(COFF_FileHeader->name)) { + if (sect->name.size > sizeof(coff_section->name)) { lnk_error(LNK_Warning_LongSectionName, "not enough space in COFF section header to store entire name \"%S\"", sect->name); } - MemorySet(&COFF_FileHeader->name[0], 0, sizeof(COFF_FileHeader->name)); - MemoryCopy(&COFF_FileHeader->name[0], sect->name.str, Min(sect->name.size, sizeof(COFF_FileHeader->name))); - COFF_FileHeader->vsize = 0; // :vsize - COFF_FileHeader->voff = 0; // :voff - COFF_FileHeader->fsize = 0; // :fsize - COFF_FileHeader->foff = 0; // :foff - COFF_FileHeader->relocs_foff = 0; // :relocs_foff - COFF_FileHeader->lines_foff = 0; // obsolete - COFF_FileHeader->reloc_count = 0; // :reloc_count - COFF_FileHeader->line_count = 0; // obsolete - COFF_FileHeader->flags = sect->flags; + MemorySet(&coff_section->name[0], 0, sizeof(coff_section->name)); + MemoryCopy(&coff_section->name[0], sect->name.str, Min(sect->name.size, sizeof(coff_section->name))); + coff_section->vsize = 0; // :vsize + coff_section->voff = 0; // :voff + coff_section->fsize = 0; // :fsize + coff_section->foff = 0; // :foff + coff_section->relocs_foff = 0; // :relocs_foff + coff_section->lines_foff = 0; // obsolete + coff_section->reloc_count = 0; // :reloc_count + coff_section->line_count = 0; // obsolete + coff_section->flags = sect->flags; // push chunk - LNK_Chunk *COFF_FileHeader_chunk = lnk_section_push_chunk_raw(header_sect, COFF_FileHeader_array_chunk, COFF_FileHeader, sizeof(*COFF_FileHeader), str8_zero()); + LNK_Chunk *coff_section_chunk = lnk_section_push_chunk_raw(header_sect, coff_section_array_chunk, coff_section, sizeof(*coff_section), str8_zero()); + lnk_chunk_set_debugf(header_sect->arena, coff_section_chunk, "COFF_SECTION_HEADER %S", sect->name); // :vsize - lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, coff_section_chunk, LNK_Reloc_CHUNK_SIZE_VIRT_32, OffsetOf(COFF_SectionHeader, vsize), sect->name, LNK_SymbolScopeFlag_Internal); // :voff - lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, coff_section_chunk, LNK_Reloc_VIRT_OFF_32, OffsetOf(COFF_SectionHeader, voff), sect->name, LNK_SymbolScopeFlag_Internal); if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { // :fsize - lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, coff_section_chunk, LNK_Reloc_CHUNK_SIZE_FILE_32, OffsetOf(COFF_SectionHeader, fsize), sect->name, LNK_SymbolScopeFlag_Internal); // :foff - lnk_section_push_reloc_undefined(header_sect, COFF_FileHeader_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal); + lnk_section_push_reloc_undefined(header_sect, coff_section_chunk, LNK_Reloc_FILE_OFF_32, OffsetOf(COFF_SectionHeader, foff), sect->name, LNK_SymbolScopeFlag_Internal); } // TODO: :reloc_off @@ -2328,10 +2333,10 @@ lnk_build_coff_section_table(LNK_SymbolTable *symtab, LNK_Section *header_sect, } // push symbol for section header count - U64 header_count = COFF_FileHeader_array_chunk->u.list->count; + U64 header_count = coff_section_array_chunk->u.list->count; lnk_symbol_table_push_defined_va(symtab, str8_lit(LNK_COFF_SECT_HEADER_COUNT_SYMBOL_NAME), LNK_DefinedSymbolVisibility_Internal, 0, header_count); - return COFF_FileHeader_array_chunk; + return coff_section_array_chunk; } internal LNK_Chunk * @@ -2374,7 +2379,7 @@ lnk_build_win32_image_header(LNK_SymbolTable *symtab, lnk_build_pe_magic(symtab, header_sect, pe_magic_chunk); lnk_build_coff_file_header(symtab, header_sect, coff_file_header_chunk, config->machine, config->time_stamp, config->file_characteristics); switch (config->machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { lnk_build_pe_optional_header_x64(symtab, header_sect, pe_optional_chunk, @@ -2767,7 +2772,7 @@ THREAD_POOL_TASK_FUNC(lnk_section_reloc_patcher) String8 image_data = task->image_data; LNK_SymbolTable *symtab = task->symtab; - LNK_SectionTable *st = task->st; + LNK_SectionTable *sectab = task->sectab; LNK_Section **sect_id_map = task->sect_id_map; U64 base_addr = task->base_addr; Rng1U64 range = task->range_arr[task_id]; @@ -2781,24 +2786,24 @@ THREAD_POOL_TASK_FUNC(lnk_section_reloc_patcher) continue; } String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, chunk->ref); - lnk_apply_reloc(base_addr, st->sect_align, st->file_align, sect_id_map, symtab, chunk_data, reloc); + lnk_apply_reloc(base_addr, sectab->sect_align, sectab->file_align, sect_id_map, symtab, chunk_data, reloc); int bad_vs = 0; (void)bad_vs; } } } 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) +lnk_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *sectab, LNK_Section **sect_id_map, String8 image_data, U64 base_addr) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); - LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, st->list); + LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, sectab->list); LNK_SectionRelocPatcher task = {0}; task.image_data = image_data; task.symtab = symtab; - task.st = st; + task.sectab = sectab; task.sect_id_map = sect_id_map; task.sect_arr = sect_arr.v; task.base_addr = base_addr; @@ -2824,14 +2829,14 @@ THREAD_POOL_TASK_FUNC(lnk_obj_reloc_patcher) continue; } String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, reloc->chunk->ref); - lnk_apply_reloc(task->base_addr, task->st->sect_align, task->st->file_align, task->sect_id_map, task->symtab, chunk_data, reloc); + lnk_apply_reloc(task->base_addr, task->sectab->sect_align, task->sectab->file_align, task->sect_id_map, task->symtab, chunk_data, reloc); int bad_vs = 0; (void)bad_vs; } } } 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) +lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symtab, LNK_SectionTable *sectab, LNK_Section **sect_id_map, String8 image_data, U64 base_addr) { ProfBeginFunction(); Temp scratch = scratch_begin(0,0); @@ -2839,7 +2844,7 @@ lnk_patch_relocs_obj(TP_Context *tp, LNK_ObjList obj_list, LNK_SymbolTable *symt LNK_ObjRelocPatcher task; task.image_data = image_data; task.symtab = symtab; - task.st = st; + task.sectab = sectab; task.sect_id_map = sect_id_map; task.base_addr = base_addr; task.obj_arr = lnk_obj_arr_from_list(scratch.arena, obj_list); @@ -2874,24 +2879,24 @@ lnk_init_section_table(LNK_SymbolTable *symtab, U64 section_virt_off, U64 sect_a { ".tls", LNK_TLS_SYMBOL_NAME, LNK_DATA_SECTION_FLAGS }, }; - LNK_SectionTable *st = lnk_section_table_alloc(section_virt_off, sect_align, file_align); + LNK_SectionTable *sectab = lnk_section_table_alloc(section_virt_off, sect_align, file_align); for (U64 i = 0; i < ArrayCount(sect_layout); ++i) { - LNK_Section *sect = lnk_section_table_push(st, str8_cstring(sect_layout[i].name), sect_layout[i].flags); + LNK_Section *sect = lnk_section_table_push(sectab, str8_cstring(sect_layout[i].name), sect_layout[i].flags); sect->symbol_name = str8_cstring(sect_layout[i].symbol); sect->symbol_name = push_str8_copy(sect->arena, sect->symbol_name); lnk_symbol_table_push_defined_chunk(symtab, sect->symbol_name, LNK_DefinedSymbolVisibility_Internal, 0, sect->root, 0, 0, 0); } - st->null_sect = lnk_section_list_remove(&st->list, str8_lit(".null")); + sectab->null_sect = lnk_section_list_remove(§ab->list, str8_lit(".null")); // dont build layout because we discard debug from image and move it to pdb - LNK_Section *debug_sect = lnk_section_table_search(st, str8_lit(".debug")); + LNK_Section *debug_sect = lnk_section_table_search(sectab, str8_lit(".debug")); debug_sect->emit_header = 0; debug_sect->has_layout = 0; ProfEnd(); - return st; + return sectab; } internal LNK_MergeDirectiveList @@ -2923,7 +2928,7 @@ lnk_init_merge_directive_list(Arena *arena, LNK_ObjList obj_list) } internal void -lnk_discard_meta_data_sections(LNK_SectionTable *st) +lnk_discard_meta_data_sections(LNK_SectionTable *sectab) { static char * meta_data_sect_arr[] = { ".gfids", @@ -2933,7 +2938,7 @@ lnk_discard_meta_data_sections(LNK_SectionTable *st) }; for (U64 meta_idx = 0; meta_idx < ArrayCount(meta_data_sect_arr); meta_idx += 1) { String8 name = str8_cstring(meta_data_sect_arr[meta_idx]); - LNK_Section *sect = lnk_section_table_search(st, name); + LNK_Section *sect = lnk_section_table_search(sectab, name); if (sect) { lnk_visit_chunks(sect->id, sect->root, lnk_chunk_mark_discarded, NULL); sect->root->is_discarded = 0; @@ -2955,15 +2960,15 @@ lnk_pdata_is_before_x8664(void *raw_a, void *raw_b) //////////////////////////////// internal void -lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) +lnk_log_size_breakdown(LNK_SectionTable *sectab, LNK_SymbolTable *symtab) { Temp scratch = scratch_begin(0, 0); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); U64 code_size = 0; U64 data_size = 0; - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; if (sect->has_layout) { U64 sect_size = lnk_file_size_from_chunk_ref(sect_id_map, sect->root->ref); @@ -2977,21 +2982,21 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) LNK_Symbol *dos_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_HEADER_SYMBOL_NAME)); LNK_Symbol *dos_program_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_DOS_PROGRAM_SYMBOL_NAME)); - LNK_Symbol *COFF_FileHeader_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME)); + LNK_Symbol *coff_file_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_FILE_HEADER_SYMBOL_NAME)); LNK_Symbol *coff_section_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_COFF_SECT_HEADER_ARRAY_SYMBOL_NAME)); LNK_Symbol *pe_opt_header_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_OPT_HEADER_SYMBOL_NAME)); LNK_Symbol *pe_directories_symbol = lnk_symbol_table_search(symtab, LNK_SymbolScopeFlag_Internal, str8_lit(LNK_PE_DIRECTORY_ARRAY_SYMBOL_NAME)); LNK_Chunk *dos_header_chunk = dos_header_symbol->u.defined.u.chunk; LNK_Chunk *dos_program_chunk = dos_program_symbol->u.defined.u.chunk; - LNK_Chunk *COFF_FileHeader_chunk = COFF_FileHeader_symbol->u.defined.u.chunk; + LNK_Chunk *coff_file_header_chunk = coff_file_header_symbol->u.defined.u.chunk; LNK_Chunk *coff_section_header_chunk = coff_section_header_symbol->u.defined.u.chunk; LNK_Chunk *pe_opt_header_chunk = pe_opt_header_symbol->u.defined.u.chunk; LNK_Chunk *pe_directories_chunk = pe_directories_symbol->u.defined.u.chunk; U64 dos_header_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_header_chunk->ref); U64 dos_program_size = lnk_file_size_from_chunk_ref(sect_id_map, dos_program_chunk->ref); - U64 COFF_FileHeader_size = lnk_file_size_from_chunk_ref(sect_id_map, COFF_FileHeader_chunk->ref); + U64 coff_file_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_file_header_chunk->ref); U64 coff_section_header_size = lnk_file_size_from_chunk_ref(sect_id_map, coff_section_header_chunk->ref); U64 pe_opt_header_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_opt_header_chunk->ref); U64 pe_directories_size = lnk_file_size_from_chunk_ref(sect_id_map, pe_directories_chunk->ref); @@ -3000,7 +3005,7 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) str8_list_pushf(scratch.arena, &output_list, "--- Image Size Breakdown -------------------------------------------------------"); str8_list_pushf(scratch.arena, &output_list, " DOS Header: %M", dos_header_size); str8_list_pushf(scratch.arena, &output_list, " DOS Program Stub: %M", dos_program_size); - str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", COFF_FileHeader_size); + str8_list_pushf(scratch.arena, &output_list, " COFF Header: %M", coff_file_header_size); str8_list_pushf(scratch.arena, &output_list, " COFF Section Headers: %M", coff_section_header_size); str8_list_pushf(scratch.arena, &output_list, " PE Header: %M", pe_opt_header_size); str8_list_pushf(scratch.arena, &output_list, " Directories: %M", pe_directories_size); @@ -3015,7 +3020,7 @@ lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab) } internal void -lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st) +lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *sectab) { Temp scratch = scratch_begin(0, 0); @@ -3024,7 +3029,7 @@ lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTabl lib_count += lib_index[i].count; } U32 reloc_count = 0; - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { reloc_count += sect_node->data.reloc_list.count; } @@ -3079,7 +3084,7 @@ lnk_write_thread(void *raw_ctx) { ProfBeginFunction(); LNK_WriteThreadContext *ctx = raw_ctx; - lnk_write_data_to_file_path(ctx->path, ctx->data); + lnk_write_data_to_file_path(ctx->path, ctx->temp_path, ctx->data); ProfEnd(); } @@ -3136,6 +3141,212 @@ LNK_CHUNK_VISITOR_SIG(lnk_max_tls_align) return 0; } +global LNK_Section **g_rad_sort_sect_id_map = 0; + +typedef struct +{ + U64 off; + LNK_Chunk *chunk; +} LNK_ChunkOffPair; + +internal int +lnk_map_sort_on_chunk_file_off(void *raw_a, void *raw_b) +{ + LNK_Chunk **a = raw_a; + LNK_Chunk **b = raw_b; + + U64 a_file_off = lnk_virt_off_from_chunk_ref(g_rad_sort_sect_id_map, (*a)->ref); + U64 b_file_off = lnk_virt_off_from_chunk_ref(g_rad_sort_sect_id_map, (*b)->ref); + + int is_before = a_file_off < b_file_off; + return is_before; +} + +internal int +lnk_map_sort_on_chunk_off(void *raw_a, void *raw_b) +{ + LNK_ChunkOffPair *a = raw_a; + LNK_ChunkOffPair *b = raw_b; + + int is_before = a->off < b->off; + return is_before; +} + +internal U64 +lnk_chunk_off_pair_array_bsearch(LNK_ChunkOffPair *arr, U64 count, U64 value) +{ + if(count > 1 && arr[0].off <= value && value < arr[count-1].off) + { + U64 l = 0; + U64 r = count - 1; + for(; l <= r; ) + { + U64 m = l + (r - l) / 2; + if(arr[m].off == value) + { + return m; + } + else if(arr[m].off < value) + { + l = m + 1; + } + else + { + r = m - 1; + } + } + } + else if (count == 1 && arr[0].off == value) + { + return 0; + } + return max_U64; +} + +internal String8List +lnk_build_rad_chunk_map(Arena *arena, String8 image_data, U64 thread_count, LNK_ObjList objs, LNK_LibList lib_index[LNK_InputSource_Count], LNK_SectionTable *sectab, LNK_SymbolTable *symtab) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + + String8List map = {0}; + + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); + + ProfBegin("SECTIONS"); + str8_list_pushf(arena, &map, "# SECTIONS\n"); + for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { + LNK_Section *sect = §_n->data; + if (sect->has_layout) { + LNK_Chunk **chunks = push_array_no_zero(scratch.arena, LNK_Chunk *, sect->layout.total_count); + MemoryCopyTyped(chunks, sect->layout.chunk_ptr_array, sect->layout.total_count); + + g_rad_sort_sect_id_map = sect_id_map; + radsort(chunks, sect->layout.total_count, lnk_map_sort_on_chunk_file_off); + + str8_list_pushf(arena, &map, "%S\n", sect->name); + str8_list_pushf(arena, &map, "%-8s %-8s %-8s %-8s %-16s %-8s %s\n", "FileOff", "VirtOff", "VirtSize", "FileSize", "Blake3", "ChunkRef", "Source"); + for (U64 chunk_idx = 0; chunk_idx < sect->layout.total_count; ++chunk_idx) { + LNK_Chunk *chunk = chunks[chunk_idx]; + if (chunk != g_null_chunk_ptr) { + Temp temp = temp_begin(scratch.arena); + + U64 file_off = lnk_file_off_from_chunk_ref(sect_id_map, chunk->ref); + U64 virt_off = lnk_virt_off_from_chunk_ref(sect_id_map, chunk->ref); + U64 virt_size = lnk_virt_size_from_chunk_ref(sect_id_map, chunk->ref); + U64 file_size = lnk_file_size_from_chunk_ref(sect_id_map, chunk->ref); + String8 chunk_data = lnk_data_from_chunk_ref(sect_id_map, image_data, chunk->ref); + + U128 chunk_hash = {0}; + if (~sect->flags & COFF_SectionFlag_CntUninitializedData) { + blake3_hasher hasher; blake3_hasher_init(&hasher); + blake3_hasher_update(&hasher, chunk_data.str, chunk_data.size); + blake3_hasher_finalize(&hasher, (U8 *)&chunk_hash, sizeof(chunk_hash)); + } + + String8 file_off_str = push_str8f(temp.arena, "%08x", file_off); + String8 virt_off_str = push_str8f(temp.arena, "%08x", virt_off); + String8 virt_size_str = push_str8f(temp.arena, "%08x", virt_size); + String8 file_size_str = push_str8f(temp.arena, "%08x", file_size); + String8 chunk_hash_str = push_str8f(temp.arena, "%08x%08x", chunk_hash.u64[0], chunk_hash.u64[1]); + String8 chunk_ref_str = push_str8f(temp.arena, "{%llx,%llx}", chunk->ref.sect_id, chunk->ref.chunk_id); + String8 source_str; + { + String8List source_list = {0}; + + // chunk type + str8_list_pushf(temp.arena, &source_list, "[%S]", lnk_string_from_chunk_type(chunk->type)); + + // location + if (chunk->obj) { + if (chunk->obj->lib_path.size) { + String8 lib_name = chunk->obj->lib_path; + lib_name = str8_skip_last_slash(lib_name); + lib_name = str8_chop_last_dot(lib_name); + + String8 obj_name = chunk->obj->path; + obj_name = str8_skip_last_slash(obj_name); + + str8_list_pushf(temp.arena, &source_list, "%S:%S", lib_name, obj_name); + } else { + str8_list_push(temp.arena, &source_list, chunk->obj->path); + } + } + + // debug comment +#if LNK_DEBUG_CHUNKS + if (chunk->debug.size) { + if (source_str.size) { + str8_list_pushf(temp.arena, &source_list, "(%S)", chunk->debug); + } else if (chunk->debug.size) { + str8_list_push(temp.arena, &source_list, chunk->debug); + } + } +#endif + + // string join + source_str = str8_list_join(temp.arena, &source_list, &(StringJoin){.sep=str8_lit(" ")}); + } + + str8_list_pushf(arena, &map, "%-8S %-8S %-8S %-8S %-16S %-8S %S\n", file_off_str, virt_off_str, virt_size_str, file_size_str, chunk_hash_str, chunk_ref_str, source_str); + + temp_end(temp); + } + } + str8_list_pushf(arena, &map, "\n"); + } + } + ProfEnd(); + + + ProfBegin("SYMBOLS"); + str8_list_pushf(arena, &map, "# SYMBOLS\n"); + str8_list_pushf(arena, &map, "%-8s %s\n", "ChunkRef", "Symbol"); + for (LNK_ObjNode *obj_n = objs.first; obj_n != 0; obj_n = obj_n->next) { + LNK_Obj *obj = &obj_n->data; + for (LNK_SymbolNode *symbol_n = obj->symbol_list.first; symbol_n != 0; symbol_n = symbol_n->next) { + LNK_Symbol *symbol = symbol_n->data; + if (LNK_Symbol_IsDefined(symbol->type)) { + if (symbol->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) { + LNK_Chunk *chunk = symbol->u.defined.u.chunk; + String8 chunk_ref_str = push_str8f(scratch.arena, "{%llx,%llx}", chunk->ref.sect_id, chunk->ref.chunk_id); + + String8 lib_name = obj->lib_path; + lib_name = str8_skip_last_slash(lib_name); + lib_name = str8_chop_last_dot(lib_name); + + String8 obj_name = obj->path; + obj_name = str8_skip_last_slash(obj_name); + + str8_list_pushf(arena, &map, "%-8S (%S%s%S) %S\n", + chunk_ref_str, + lib_name, lib_name.size ? ":" : "", obj_name, + symbol->name); + } + } + } + } + str8_list_pushf(arena, &map, "\n"); + ProfEnd(); + + + ProfBegin("LIBS"); + for (U64 input_source = 0; input_source < LNK_InputSource_Count; ++input_source) { + if (lib_index[input_source].count) { + str8_list_pushf(arena, &map, "# LIBS (%S)\n", lnk_string_from_input_source(input_source)); + for (LNK_LibNode *lib_n = lib_index[input_source].first; lib_n != 0; lib_n = lib_n->next) { + str8_list_pushf(arena, &map, "%S\n", lib_n->data.path); + } + } + } + ProfEnd(); + + + scratch_end(scratch); + ProfEnd(); + return map; +} + internal void lnk_run(int argc, char **argv) { @@ -3164,6 +3375,7 @@ lnk_run(int argc, char **argv) State_BuildBaseRelocs, State_FinalizeImage, State_BuildImpLib, + State_BuildRadChunkMap, State_BuildDebugInfo, }; struct StateNode { @@ -3224,7 +3436,7 @@ lnk_run(int argc, char **argv) // state LNK_SymbolTable *symtab = lnk_symbol_table_init(tp_arena); - LNK_SectionTable *st = lnk_init_section_table(symtab, config->section_virt_off, config->sect_align, config->file_align); + LNK_SectionTable *sectab = lnk_init_section_table(symtab, config->section_virt_off, config->sect_align, config->file_align); LNK_ImportTable *imptab_static = 0; LNK_ImportTable *imptab_delayed = 0; LNK_ExportTable *exptab = lnk_export_table_alloc(); @@ -3251,6 +3463,7 @@ lnk_run(int argc, char **argv) B32 report_unresolved_symbols = 1; B32 check_unused_delay_loads = !!(config->flags & LNK_ConfigFlag_CheckUnusedDelayLoadDll); B32 build_imp_lib = config->build_imp_lib; + B32 build_rad_chunk_map = (config->rad_chunk_map == LNK_SwitchState_Yes); LNK_ObjList obj_list = {0}; LNK_LibList lib_index[LNK_InputSource_Count] = {0}; String8 image_data = str8_zero(); @@ -3285,7 +3498,7 @@ lnk_run(int argc, char **argv) switch (state) { case State_Null: break; case State_SearchEntryPoint: { - ProfBegin("Serach Entry Point"); + ProfBegin("Search Entry Point"); LNK_Symbol *entry_point_symbol = 0; B32 is_entry_point_unspecified = config->entry_point_name.size == 0; @@ -3406,8 +3619,8 @@ lnk_run(int argc, char **argv) String8 delay_helper_name = str8_zero(); switch (config->machine) { - case COFF_Machine_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break; - case COFF_Machine_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break; + case COFF_MachineType_X86: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_X86_SYMBOL_NAME); break; + case COFF_MachineType_X64: delay_helper_name = str8_cstring(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME); break; default: NotImplemented; } @@ -3466,10 +3679,10 @@ lnk_run(int argc, char **argv) if (is_delayed) { if (!imptab_delayed) { - Assert(config->machine != COFF_Machine_Unknown); + Assert(config->machine != COFF_MachineType_Unknown); B32 is_unloadable = !!(config->flags & LNK_ConfigFlag_DelayUnload); B32 is_bindable = !!(config->flags & LNK_ConfigFlag_DelayBind); - imptab_delayed = lnk_import_table_alloc_delayed(st, symtab, config->machine, is_unloadable, is_bindable); + imptab_delayed = lnk_import_table_alloc_delayed(sectab, symtab, config->machine, is_unloadable, is_bindable); } LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_delayed, import_header->dll_name); if (!dll) { @@ -3481,8 +3694,8 @@ lnk_run(int argc, char **argv) } } else { if (!imptab_static) { - Assert(config->machine != COFF_Machine_Unknown); - imptab_static = lnk_import_table_alloc_static(st, symtab, config->machine); + Assert(config->machine != COFF_MachineType_Unknown); + imptab_static = lnk_import_table_alloc_static(sectab, symtab, config->machine); } LNK_ImportDLL *dll = lnk_import_table_search_dll(imptab_static, import_header->dll_name); if (!dll) { @@ -3556,21 +3769,21 @@ lnk_run(int argc, char **argv) } ProfEnd(); - LNK_ObjNodeArray obj_node_arr = lnk_obj_list_push_parallel(tp, tp_arena, &obj_list, st, config->function_pad_min, unique_obj_input_list.count, input_obj_arr); + LNK_ObjNodeArray obj_node_arr = lnk_obj_list_push_parallel(tp, tp_arena, &obj_list, sectab, config->function_pad_min, unique_obj_input_list.count, input_obj_arr); ProfBegin("Machine Compat Check"); for (U64 obj_idx = 0; obj_idx < obj_node_arr.count; ++obj_idx) { LNK_Obj *obj = &obj_node_arr.v[obj_idx].data; // derive machine from obj - if (config->machine == COFF_Machine_Unknown) { + if (config->machine == COFF_MachineType_Unknown) { config->machine = obj->machine; - } else if (config->machine != COFF_Machine_X64) { + } else if (config->machine != COFF_MachineType_X64) { lnk_error_with_loc(LNK_Error_UnsupportedMachine, obj->path, obj->lib_path, "%S machine is supported", coff_string_from_machine_type(obj->machine)); } else { // is obj machine compatible? if (config->machine != obj->machine && - obj->machine != COFF_Machine_Unknown) { // obj with unknown machine type is compatible with any other machine type + obj->machine != COFF_MachineType_Unknown) { // obj with unknown machine type is compatible with any other machine type lnk_error_obj(LNK_Error_IncompatibleObj, obj, "conflicting machine types expected %S but got %S", coff_string_from_machine_type(config->machine), @@ -3763,7 +3976,7 @@ lnk_run(int argc, char **argv) ProfBeginDynamic("Write Manifest To: %.*s", str8_varg(config->manifest_name)); Temp temp = temp_begin(scratch.arena); String8 manifest_data = lnk_manifest_from_inputs(temp.arena, config->mt_path, config->manifest_name, config->manifest_uac, config->manifest_level, config->manifest_ui_access, input_manifest_path_list, manifest_dep_list); - lnk_write_data_to_file_path(config->manifest_name, manifest_data); + lnk_write_data_to_file_path(config->manifest_name, str8_zero(), manifest_data); temp_end(temp); ProfEnd(); } break; @@ -3799,7 +4012,7 @@ lnk_run(int argc, char **argv) String8 obj_name = str8_lit("* Resources *"); String8 obj_data = lnk_obj_from_res_file_list(tp, tp_arena->v[0], - st, + sectab, symtab, res_data_list, res_path_list, @@ -3888,14 +4101,14 @@ lnk_run(int argc, char **argv) case State_DiscardMetaDataSections: { ProfBegin("Discard Meta Data Sections"); - lnk_discard_meta_data_sections(st); + lnk_discard_meta_data_sections(sectab); ProfEnd(); } break; case State_BuildDebugDirectory: { ProfBegin("Build Debug Directory"); // push debug directory layout chunks - LNK_Section *debug_sect = lnk_section_table_search(st, str8_lit(".rdata")); + LNK_Section *debug_sect = lnk_section_table_search(sectab, str8_lit(".rdata")); LNK_Chunk *debug_chunk = lnk_section_push_chunk_list(debug_sect, debug_sect->root, str8_zero()); LNK_Chunk *debug_dir_array_chunk = lnk_section_push_chunk_list(debug_sect, debug_chunk, str8_zero()); @@ -3904,12 +4117,12 @@ lnk_run(int argc, char **argv) // debug entry for PDB if (config->debug_mode != LNK_DebugMode_None && config->debug_mode != LNK_DebugMode_Null) { - lnk_build_debug_pdb(st, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->age, config->pdb_alt_path); + lnk_build_debug_pdb(sectab, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->age, config->pdb_alt_path); } // debug entry for RDI if (config->rad_debug == LNK_SwitchState_Yes) { - lnk_build_debug_rdi(st, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->rad_debug_alt_path); + lnk_build_debug_rdi(sectab, symtab, debug_sect, debug_dir_array_chunk, config->time_stamp, config->guid, config->rad_debug_alt_path); } ProfEnd(); @@ -3926,38 +4139,38 @@ lnk_run(int argc, char **argv) lnk_collect_exports_from_obj_directives(exptab, obj_list, symtab); // build export table section - lnk_build_edata(exptab, st, symtab, config->image_name, config->machine); + lnk_build_edata(exptab, sectab, symtab, config->image_name, config->machine); ProfEnd(); } break; case State_MergeSections: { ProfBegin("Merge Sections"); LNK_MergeDirectiveList merge_list = lnk_init_merge_directive_list(scratch.arena, obj_list); - lnk_section_table_merge(st, merge_list); + lnk_section_table_merge(sectab, merge_list); ProfEnd(); } break; case State_BuildCFGuards: { ProfBegin("Build CF Guards"); B32 emit_suppress_flag = 1; // MSVC emits this flag but every entry has zero set. - lnk_build_guard_tables(tp, st, symtab, exptab, obj_list, config->machine, config->entry_point_name, config->guard_flags, emit_suppress_flag); + lnk_build_guard_tables(tp, sectab, symtab, exptab, obj_list, config->machine, config->entry_point_name, config->guard_flags, emit_suppress_flag); ProfEnd(); } break; case State_BuildBaseRelocs: { ProfBegin("Base Relocs"); - lnk_build_base_relocs(tp, tp_arena, st, symtab, config->machine, config->page_size, config->file_characteristics, obj_list); + lnk_build_base_relocs(tp, tp_arena, sectab, symtab, config->machine, config->page_size, config->file_characteristics, obj_list); ProfEnd(); } break; case State_FinalizeImage: { ProfBegin("Build Win32 Header"); // remove empty section headers from output image - lnk_section_table_remove_empties(st, symtab); + lnk_section_table_remove_empties(sectab, symtab); // collect output sections - LNK_SectionArray out_sect_arr = lnk_section_table_get_output_sections(scratch.arena, st); + LNK_SectionArray out_sect_arr = lnk_section_table_get_output_sections(scratch.arena, sectab); // push back null section where we store image header - LNK_Section *header_sect = lnk_section_table_push_null(st); + LNK_Section *header_sect = lnk_section_table_push_null(sectab); // fill out header section with win32 image header data lnk_build_win32_image_header(symtab, header_sect, header_sect->root, config, out_sect_arr); @@ -3965,24 +4178,24 @@ lnk_run(int argc, char **argv) ProfEnd(); // finalize sections - lnk_section_table_build_data(tp, st, config->machine); - lnk_section_table_assign_indices(st); - lnk_section_table_assign_virtual_offsets(st); - lnk_section_table_assign_file_offsets(st); + lnk_section_table_build_data(tp, sectab, config->machine); + lnk_section_table_assign_indices(sectab); + lnk_section_table_assign_virtual_offsets(sectab); + lnk_section_table_assign_file_offsets(sectab); ProfBegin("Image Serialize"); - image_data = lnk_section_table_serialize(tp, scratch.arena, st, config->machine); + image_data = lnk_section_table_serialize(tp, scratch.arena, sectab, config->machine); Assert(image_data.size > 0); ProfEnd(); // image layout is finalized, section id map is stable after this point - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); ProfBegin("Patch Relocs"); U64 base_addr = lnk_get_base_addr(config); - lnk_patch_relocs_obj(tp, obj_list, symtab, st, sect_id_map, image_data, base_addr); - lnk_patch_relocs_linker(tp, symtab, st, sect_id_map, image_data, base_addr); + lnk_patch_relocs_obj(tp, obj_list, symtab, sectab, sect_id_map, image_data, base_addr); + lnk_patch_relocs_linker(tp, symtab, sectab, sect_id_map, image_data, base_addr); ProfEnd(); @@ -3992,18 +4205,18 @@ lnk_run(int argc, char **argv) if (pdata_symbol) { String8 pdata = lnk_data_from_chunk_ref_no_pad(sect_id_map, image_data, pdata_symbol->u.defined.u.chunk->ref); switch (config->machine) { - case COFF_Machine_X86: - case COFF_Machine_X64: { + case COFF_MachineType_X86: + case COFF_MachineType_X64: { U64 count = pdata.size / sizeof(PE_IntelPdata); radsort((PE_IntelPdata *)pdata.str, count, lnk_pdata_is_before_x8664); } break; - case COFF_Machine_Arm64: - case COFF_Machine_Arm: { + case COFF_MachineType_Arm64: + case COFF_MachineType_Arm: { AssertAlways(!"TOOD: ARM"); } break; - case COFF_Machine_MipsFpu: - case COFF_Machine_Mips16: - case COFF_Machine_MipsFpu16: { + case COFF_MachineType_MipsFpu: + case COFF_MachineType_Mips16: + case COFF_MachineType_MipsFpu16: { AssertAlways(!"TODO: MIPS"); } break; } @@ -4080,10 +4293,14 @@ lnk_run(int argc, char **argv) } } - LNK_WriteThreadContext *ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1); - ctx->path = config->image_name; - ctx->data = image_data; - image_write_thread = os_thread_launch(lnk_write_thread, ctx, 0); + // write image file in background + { + LNK_WriteThreadContext *ctx = push_array(scratch.arena, LNK_WriteThreadContext, 1); + ctx->path = config->image_name; + ctx->temp_path = config->temp_image_name; + ctx->data = image_data; + image_write_thread = os_thread_launch(lnk_write_thread, ctx, 0); + } if (lnk_get_log_status(LNK_Log_InputObj)) { U64 total_input_size = 0; @@ -4110,22 +4327,28 @@ lnk_run(int argc, char **argv) ProfBegin("Build Imp Lib"); lnk_timer_begin(LNK_Timer_Lib); String8List lib_list = lnk_build_import_lib(tp, tp_arena, config->machine, config->time_stamp, config->imp_lib_name, config->image_name, exptab); - lnk_write_data_list_to_file_path(config->imp_lib_name, lib_list); + lnk_write_data_list_to_file_path(config->imp_lib_name, str8_zero(), lib_list); lnk_timer_end(LNK_Timer_Lib); ProfEnd(); } break; + case State_BuildRadChunkMap: { + ProfBegin("RAD Chunk Map"); + String8List map = lnk_build_rad_chunk_map(scratch.arena, image_data, config->worker_count, obj_list, lib_index, sectab, symtab); + lnk_write_data_list_to_file_path(config->rad_chunk_map_name, config->temp_rad_chunk_map_name, map); + ProfEnd(); + } break; case State_BuildDebugInfo: { ProfBegin("Debug Info"); lnk_timer_begin(LNK_Timer_Debug); LNK_CodeViewInput input = lnk_make_code_view_input(tp, tp_arena, config->lib_dir_list, obj_list); CV_DebugT *types = lnk_import_types(tp, tp_arena, &input); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); if (config->rad_debug == LNK_SwitchState_Yes) { lnk_timer_begin(LNK_Timer_Rdi); RDI_Arch arch = rdi_arch_from_coff_machine(config->machine); - LNK_SectionArray image_sects = lnk_section_table_get_output_sections(scratch.arena, st); + LNK_SectionArray image_sects = lnk_section_table_get_output_sections(scratch.arena, sectab); String8List rdi_data = lnk_build_rad_debug_info(tp, tp_arena, @@ -4143,7 +4366,8 @@ lnk_run(int argc, char **argv) input.parsed_symbols, types); - lnk_write_data_list_to_file_path(config->rad_debug_name, rdi_data); + lnk_write_data_list_to_file_path(config->rad_debug_name, config->temp_rad_debug_name, rdi_data); + lnk_timer_end(LNK_Timer_Rdi); } @@ -4177,7 +4401,7 @@ lnk_run(int argc, char **argv) input.parsed_symbols, types); - lnk_write_data_list_to_file_path(config->pdb_name, pdb_data); + lnk_write_data_list_to_file_path(config->pdb_name, config->temp_pdb_name, pdb_data); lnk_timer_end(LNK_Timer_Pdb); } @@ -4311,6 +4535,11 @@ lnk_run(int argc, char **argv) continue; } } + if (build_rad_chunk_map) { + build_rad_chunk_map = 0; + state_list_push(scratch.arena, state_list, State_BuildRadChunkMap); + continue; + } if (build_debug_info) { build_debug_info = 0; state_list_push(scratch.arena, state_list, State_BuildDebugInfo); @@ -4324,10 +4553,10 @@ lnk_run(int argc, char **argv) } if (lnk_get_log_status(LNK_Log_SizeBreakdown)) { - lnk_log_size_breakdown(st, symtab); + lnk_log_size_breakdown(sectab, symtab); } if (lnk_get_log_status(LNK_Log_LinkStats)) { - lnk_log_link_stats(obj_list, lib_index, st); + lnk_log_link_stats(obj_list, lib_index, sectab); } if (lnk_get_log_status(LNK_Log_Timers)) { lnk_log_timers(); @@ -4337,7 +4566,7 @@ lnk_run(int argc, char **argv) // linker is done, punt memory release to OS //arena_release(ht_arena); - //lnk_section_table_release(&st); + //lnk_section_table_release(§ab); //lnk_export_table_release(&export_table); //lnk_import_table_release(&imptab_static); //lnk_import_table_release(&imptab_delayed); diff --git a/src/linker/lnk.h b/src/linker/lnk.h index 9f2b1b35..2790fa60 100644 --- a/src/linker/lnk.h +++ b/src/linker/lnk.h @@ -204,7 +204,7 @@ typedef struct { String8 image_data; LNK_SymbolTable *symtab; - LNK_SectionTable *st; + LNK_SectionTable *sectab; LNK_Section **sect_id_map; U64 base_addr; LNK_Section **sect_arr; @@ -215,7 +215,7 @@ typedef struct { String8 image_data; LNK_SymbolTable *symtab; - LNK_SectionTable *st; + LNK_SectionTable *sectab; LNK_Section **sect_id_map; U64 base_addr; LNK_Obj **obj_arr; @@ -224,6 +224,7 @@ typedef struct typedef struct { String8 path; + String8 temp_path; String8 data; } LNK_WriteThreadContext; @@ -261,10 +262,10 @@ internal void lnk_merge_manifest_files(String8 mt_path, String8 out_name, Str //////////////////////////////// // Resources -internal void lnk_serialize_pe_resource_tree(LNK_SectionTable *st, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir); -internal void lnk_add_resource_debug_s(LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array); +internal void lnk_serialize_pe_resource_tree(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, PE_ResourceDir *root_dir); +internal void lnk_add_resource_debug_s(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 obj_path, String8 cwd_path, String8 exe_path, CV_Arch arch, String8List res_file_list, MD5Hash *res_hash_array); internal String8 lnk_make_res_obj(TP_Context *tp, Arena *arena, PE_ResourceDir *root_dir, COFF_MachineType machine, COFF_TimeStamp time_stamp, String8 path, String8 cwd_path, String8 exe_path, String8List res_file_list, MD5Hash *res_hash_array); -internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, LNK_SectionTable *st, LNK_SymbolTable *symtab, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); +internal String8 lnk_obj_from_res_file_list(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8List res_file_list, String8List res_path_list, COFF_MachineType machine, U32 time_stamp, String8 work_dir, PathStyle system_path_style, String8 obj_name); //////////////////////////////// // Debug @@ -274,10 +275,10 @@ 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, 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, PE_ImageFileCharacteristics file_chars, LNK_ObjList obj_list); +internal void lnk_build_debug_pdb(LNK_SectionTable *sectab, 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 *sectab, 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 *sectab, 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 *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, U64 page_size, PE_ImageFileCharacteristics file_chars, LNK_ObjList obj_list); internal LNK_Chunk * lnk_build_dos_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent_chunk); internal LNK_Chunk * lnk_build_pe_magic(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent); internal LNK_Chunk * lnk_build_coff_file_header(LNK_SymbolTable *symtab, LNK_Section *header_sect, LNK_Chunk *parent, COFF_MachineType machine, COFF_TimeStamp time_stamp, PE_ImageFileCharacteristics file_characteristics); @@ -289,15 +290,15 @@ internal LNK_Chunk * lnk_build_win32_image_header(LNK_SymbolTable *symtab, LNK_S //////////////////////////////// // Relocs -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_patch_relocs_linker(TP_Context *tp, LNK_SymbolTable *symtab, LNK_SectionTable *sectab, 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 *sectab, 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); //////////////////////////////// -internal void lnk_log_size_breakdown(LNK_SectionTable *st, LNK_SymbolTable *symtab); -internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *st); +internal void lnk_log_size_breakdown(LNK_SectionTable *sectab, LNK_SymbolTable *symtab); +internal void lnk_log_link_stats(LNK_ObjList obj_list, LNK_LibList *lib_index, LNK_SectionTable *sectab); internal void lnk_log_timers(void); //////////////////////////////// diff --git a/src/linker/lnk_chunk.c b/src/linker/lnk_chunk.c index c35e4b73..be7b7211 100644 --- a/src/linker/lnk_chunk.c +++ b/src/linker/lnk_chunk.c @@ -790,3 +790,15 @@ lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 return result; } +internal String8 +lnk_string_from_chunk_type(LNK_ChunkType type) +{ + switch (type) { + case LNK_Chunk_Null: return str8_lit("Null"); + case LNK_Chunk_Leaf: return str8_lit("Leaf"); + case LNK_Chunk_LeafArray: return str8_lit("LeafArray"); + case LNK_Chunk_List: return str8_lit("List"); + default: InvalidPath; + } + return str8_zero(); +} diff --git a/src/linker/lnk_chunk.h b/src/linker/lnk_chunk.h index 0b64d968..ed53cf36 100644 --- a/src/linker/lnk_chunk.h +++ b/src/linker/lnk_chunk.h @@ -5,7 +5,13 @@ //////////////////////////////// -#define LNK_DEBUG_CHUNKS 0 +#define LNK_DEBUG_CHUNKS 1 + +#if LNK_DEBUG_CHUNKS +# define lnk_chunk_set_debugf(a, c, f, ...) do { (c)->debug = push_str8f((a), f, __VA_ARGS__); } while(0) +#else +# define lnk_chunk_set_debugf(a, c, f, ...) (void)(c) +#endif //////////////////////////////// @@ -40,6 +46,7 @@ typedef struct LNK_Chunk struct LNK_ChunkList *list; struct LNK_ChunkArray *arr; } u; + struct LNK_Obj *obj; #if LNK_DEBUG_CHUNKS String8 debug; #endif @@ -115,7 +122,7 @@ typedef struct LNK_ChunkPadArrayNode } LNK_ChunkPadArrayNode; typedef struct LNK_ChunkPadArrayList { - U64 count; + U64 count; LNK_ChunkPadArrayNode *first; LNK_ChunkPadArrayNode *last; } LNK_ChunkPadArrayList; @@ -199,9 +206,5 @@ internal LNK_ChunkNode * lnk_chunk_ptr_list_reserve(Arena *arena, LNK_ChunkList internal String8Array lnk_data_arr_from_chunk_ptr_list(Arena *arena, LNK_ChunkList list); internal String8Array * lnk_data_arr_from_chunk_ptr_list_arr(Arena *arena, LNK_ChunkList *list_arr, U64 count); -#if LNK_DEBUG_CHUNKS -#define lnk_chunk_set_debugf(a, c, f, ...) do { (c)->debug = push_str8f((a), f, __VA_ARGS__); } while(0) -#else -#define lnk_chunk_set_debugf(a, c, f, ...) (void)(c) -#endif +internal String8 lnk_string_from_chunk_type(LNK_ChunkType type); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index 7d123f23..53ad9cda 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -132,6 +132,7 @@ global read_only struct { 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_ChunkMap, "RAD_CHUNK_MAP", ":FILENAME", "Emit file with the output image's layout description." }, { 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." }, @@ -152,17 +153,17 @@ global read_only struct { 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_SharedThreadPool, "RAD_SHARED_THREAD_POOL", "[:STRING]", "Default value \"" LNK_DEFAULT_THREAD_POOL_NAME "\"" }, - { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, + { LNK_CmdSwitch_Rad_SharedThreadPoolMaxWorkers, "RAD_SHARED_THREAD_POOL_MAX_WORKERS", ":#", "Sets maximum number of workers in a thread pool." }, { 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_WriteTempFiles, "RAD_WRITE_TEMP_FILES", "[:NO]", "When speicifed linker writes image and debug info to temporary files and renames after link is done." }, { 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. When /RAD_SHARED_THREAD_POOL is specified this number cant exceed /RAD_SHARED_THREAD_POOL_MAX_WORKERS." }, - { LNK_CmdSwitch_Help, "HELP", "", "" }, { LNK_CmdSwitch_Help, "?", "", "" }, }; @@ -355,11 +356,11 @@ lnk_get_default_function_pad_min(COFF_MachineType machine) { U64 function_pad_min = 0; switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: { function_pad_min = 5; } break; - case COFF_Machine_X64: { + case COFF_MachineType_X64: { function_pad_min = 6; } break; default: { @@ -399,12 +400,12 @@ lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineTyp case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { - case COFF_Machine_X64: - case COFF_Machine_X86: ver = make_version(6,0); break; + case COFF_MachineType_X64: + case COFF_MachineType_X86: ver = make_version(6,0); break; - case COFF_Machine_ArmNt: - case COFF_Machine_Arm64: - case COFF_Machine_Arm: ver = make_version(6,2); break; + case COFF_MachineType_ArmNt: + case COFF_MachineType_Arm64: + case COFF_MachineType_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -412,12 +413,12 @@ lnk_get_default_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineTyp case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { - case COFF_Machine_X64: - case COFF_Machine_X86: ver = make_version(6,0); break; + case COFF_MachineType_X64: + case COFF_MachineType_X86: ver = make_version(6,0); break; - case COFF_Machine_ArmNt: - case COFF_Machine_Arm64: - case COFF_Machine_Arm: ver = make_version(6,2); break; + case COFF_MachineType_ArmNt: + case COFF_MachineType_Arm64: + case COFF_MachineType_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -447,13 +448,13 @@ lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType ma case PE_WindowsSubsystem_WINDOWS_CUI: { switch (machine) { - case COFF_Machine_X86: ver = make_version(5,1); break; + case COFF_MachineType_X86: ver = make_version(5,1); break; - case COFF_Machine_X64: ver = make_version(5,2); break; + case COFF_MachineType_X64: ver = make_version(5,2); break; - case COFF_Machine_ArmNt: - case COFF_Machine_Arm64: - case COFF_Machine_Arm: ver = make_version(6,2); break; + case COFF_MachineType_ArmNt: + case COFF_MachineType_Arm64: + case COFF_MachineType_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -461,13 +462,13 @@ lnk_get_min_subsystem_version(PE_WindowsSubsystem subsystem, COFF_MachineType ma case PE_WindowsSubsystem_WINDOWS_GUI: { switch (machine) { - case COFF_Machine_X86: ver = make_version(5,1); break; + case COFF_MachineType_X86: ver = make_version(5,1); break; - case COFF_Machine_X64: ver = make_version(5,2); break; + case COFF_MachineType_X64: ver = make_version(5,2); break; - case COFF_Machine_ArmNt: - case COFF_Machine_Arm64: - case COFF_Machine_Arm: ver = make_version(6,2); break; + case COFF_MachineType_ArmNt: + case COFF_MachineType_Arm64: + case COFF_MachineType_Arm: ver = make_version(6,2); break; default: lnk_not_implemented("define min subsystem(%S) version for %S", pe_string_from_subsystem(subsystem), coff_string_from_machine_type(machine)); break; } @@ -882,7 +883,7 @@ lnk_print_help(void) fprintf(stdout, "--- Help -------------------------------------------------------\n"); fprintf(stdout, " %s\n", BUILD_TITLE_STRING_LITERAL); fprintf(stdout, "\n"); - fprintf(stdout, " Usage: rad-link.exe [Options] [Files] [@rsp]\n"); + fprintf(stdout, " Usage: radlink.exe [Options] [Files] [@rsp]\n"); fprintf(stdout, "\n"); fprintf(stdout, " Options:\n"); @@ -953,8 +954,6 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) internal void lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_name, String8List value_strings, String8 obj_path, String8 lib_path) { - Assert(cmd_name.size); // switch must have a defined name in the table - Temp scratch = scratch_begin(&arena,1); LNK_CmdSwitchType cmd_switch = lnk_cmd_switch_type_from_string(cmd_name); @@ -1213,7 +1212,7 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam case LNK_CmdSwitch_Machine: { if (value_strings.node_count == 1) { COFF_MachineType machine = coff_machine_from_string(value_strings.first->string); - if (machine != COFF_Machine_Unknown) { + if (machine != COFF_MachineType_Unknown) { config->machine = machine; } else { lnk_error_cmd_switch(LNK_Error_Cmdl, obj_path, lib_path, cmd_switch, "unknown parameter \"%S\"", value_strings.first->string); @@ -1522,6 +1521,11 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam lnk_cmd_switch_set_flag_64(obj_path, lib_path, cmd_switch, value_strings, &config->flags, LNK_ConfigFlag_CheckUnusedDelayLoadDll); } break; + case LNK_CmdSwitch_Rad_ChunkMap: { + lnk_cmd_switch_parse_string_copy(arena, obj_path, lib_path, cmd_switch, value_strings, &config->rad_chunk_map_name); + config->rad_chunk_map = LNK_SwitchState_Yes; + } break; + case LNK_CmdSwitch_Rad_Debug: { lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->rad_debug); } break; @@ -1754,6 +1758,10 @@ lnk_apply_cmd_option_to_config(Arena *arena, LNK_Config *config, String8 cmd_nam } } break; + case LNK_CmdSwitch_Rad_WriteTempFiles: { + lnk_cmd_switch_parse_flag(obj_path, lib_path, cmd_switch, value_strings, &config->write_temp_files); + } break; + case LNK_CmdSwitch_Rad_TimeStamp: { lnk_cmd_switch_parse_u32(obj_path, lib_path, cmd_switch, value_strings, &config->time_stamp, 0); } break; @@ -1972,22 +1980,22 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Out)) { String8 name = str8_list_first(&config->input_list[LNK_Input_Obj]); String8 ext = (config->file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) ? str8_lit("dll") : str8_lit("exe"); - config->image_name = make_file_name_with_ext(scratch.arena, name, ext); + config->image_name = path_replace_file_extension(scratch.arena, name, ext); } // handle empty /PDB if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_Pdb)) { - config->pdb_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("pdb")); + config->pdb_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("pdb")); } // 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(scratch.arena, config->image_name, str8_lit("rdi")); + config->rad_debug_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("rdi")); } // handle empty /IMPLIB if (!lnk_cmd_line_has_switch(cmd_line, LNK_CmdSwitch_ImpLib)) { - config->imp_lib_name = make_file_name_with_ext(scratch.arena, config->image_name, str8_lit("lib")); + config->imp_lib_name = path_replace_file_extension(scratch.arena, config->image_name, str8_lit("lib")); } // handle empty /MANIFESTFILE @@ -2054,6 +2062,14 @@ lnk_config_from_cmd_line(Arena *arena, String8List raw_cmd_line) // :Rad_DebugAltPath config->rad_debug_alt_path = lnk_expand_env_vars_windows(arena, env_vars, config->rad_debug_alt_path); + // create temporary files names + if (config->write_temp_files == LNK_SwitchState_Yes) { + config->temp_rad_chunk_map_name = push_str8f(arena, "%S.tmp%x", config->rad_chunk_map_name, config->time_stamp); + config->temp_image_name = push_str8f(arena, "%S.tmp%x", config->image_name, config->time_stamp); + config->temp_pdb_name = push_str8f(arena, "%S.tmp%x", config->pdb_name, config->time_stamp); + config->temp_rad_debug_name = push_str8f(arena, "%S.tmp%x", config->rad_debug_name, config->time_stamp); + } + 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(" ") }); fprintf(stderr, "--------------------------------------------------------------------------------\n"); diff --git a/src/linker/lnk_config.h b/src/linker/lnk_config.h index 871e9662..81f64066 100644 --- a/src/linker/lnk_config.h +++ b/src/linker/lnk_config.h @@ -128,6 +128,7 @@ typedef enum LNK_CmdSwitch_Rad_Age, LNK_CmdSwitch_Rad_BuildInfo, LNK_CmdSwitch_Rad_CheckUnusedDelayLoadDll, + LNK_CmdSwitch_Rad_ChunkMap, LNK_CmdSwitch_Rad_Debug, LNK_CmdSwitch_Rad_DebugName, LNK_CmdSwitch_Rad_DebugAltPath, @@ -155,6 +156,7 @@ typedef enum LNK_CmdSwitch_Rad_SymbolTableCapInternal, LNK_CmdSwitch_Rad_SymbolTableCapWeak, LNK_CmdSwitch_Rad_SymbolTableCapLib, + LNK_CmdSwitch_Rad_WriteTempFiles, LNK_CmdSwitch_Rad_TargetOs, LNK_CmdSwitch_Rad_TimeStamp, LNK_CmdSwitch_Rad_Version, @@ -354,6 +356,8 @@ typedef struct LNK_Config String8 manifest_ui_access; String8List manifest_dependency_list; LNK_SwitchState rad_debug; + LNK_SwitchState rad_chunk_map; + String8 rad_chunk_map_name; String8 rad_debug_name; String8 rad_debug_alt_path; String8List include_symbol_list; @@ -364,6 +368,11 @@ typedef struct LNK_Config U64 symbol_table_cap_lib; B32 build_imp_lib; B32 build_exp; + LNK_SwitchState write_temp_files; + String8 temp_image_name; + String8 temp_pdb_name; + String8 temp_rad_debug_name; + String8 temp_rad_chunk_map_name; } LNK_Config; typedef enum diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index b3418b83..7e857d20 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -2676,7 +2676,7 @@ lnk_replace_type_names_with_hashes(TP_Context *tp, TP_Arena *arena, CV_DebugT de 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); + lnk_write_data_list_to_file_path(map_name, str8_zero(), map); tp_arena_release(&task.map_arena); } diff --git a/src/linker/lnk_error.h b/src/linker/lnk_error.h index 2f3cd415..ad6dd4ba 100644 --- a/src/linker/lnk_error.h +++ b/src/linker/lnk_error.h @@ -31,10 +31,10 @@ typedef enum LNK_Error_LoadRes, LNK_Error_IO, LNK_Error_LargeAddrAwareRequired, + LNK_Error_InvalidPath, LNK_Error_StopLast, LNK_Error_First, - LNK_Error_InvalidPath, LNK_Error_AlreadyDefinedSymbol, LNK_Error_AlternateNameConflict, LNK_Error_CvPrecomp, diff --git a/src/linker/lnk_export_table.c b/src/linker/lnk_export_table.c index ff36c649..d2beb95e 100644 --- a/src/linker/lnk_export_table.c +++ b/src/linker/lnk_export_table.c @@ -171,7 +171,7 @@ lnk_export_array_from_list(Arena *arena, LNK_ExportList list) } internal void -lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine) +lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -195,7 +195,7 @@ lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable * } } - LNK_Section *edata = lnk_section_table_search(st, str8_lit(".edata")); + LNK_Section *edata = lnk_section_table_search(sectab, str8_lit(".edata")); // push header PE_ExportTableHeader *header = push_array(edata->arena, PE_ExportTableHeader, 1); diff --git a/src/linker/lnk_export_table.h b/src/linker/lnk_export_table.h index 25cc31ca..08be801f 100644 --- a/src/linker/lnk_export_table.h +++ b/src/linker/lnk_export_table.h @@ -41,6 +41,6 @@ internal LNK_ExportTable * lnk_export_table_alloc(void); internal void lnk_export_table_release(LNK_ExportTable **exptab_ptr); internal LNK_Export * lnk_export_table_search(LNK_ExportTable *exptab, String8 name); internal void lnk_collect_exports_from_def_files(LNK_ExportTable *exptab, String8List path_list); -internal void lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine); +internal void lnk_build_edata(LNK_ExportTable *exptab, LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 image_name, COFF_MachineType machine); internal void lnk_collect_exports_from_obj_directives(LNK_ExportTable *exptab, LNK_ObjList obj_list, LNK_SymbolTable *symtab); diff --git a/src/linker/lnk_import_table.c b/src/linker/lnk_import_table.c index 34f44e52..c1973f30 100644 --- a/src/linker/lnk_import_table.c +++ b/src/linker/lnk_import_table.c @@ -2,19 +2,24 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal LNK_ImportTable * -lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine) +lnk_import_table_alloc_static(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine) { ProfBeginFunction(); - LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".idata"), LNK_IDATA_SECTION_FLAGS); - LNK_Section *code_sect = lnk_section_table_search(st, str8_lit(".text")); + LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".idata"), LNK_IDATA_SECTION_FLAGS); + LNK_Section *code_sect = lnk_section_table_search(sectab, str8_lit(".text")); LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); LNK_Chunk *iat_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); LNK_Chunk *ilt_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, code_sect->root, str8_zero()); - + lnk_chunk_set_debugf(data_sect->arena, dll_table_chunk, "DLL_TABLE" ); + lnk_chunk_set_debugf(data_sect->arena, int_chunk, "IMPORT_NAME_TABLE" ); + lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IMPORT_ADDRESS_TABLE"); + lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "IMPORT_LOOKUP_TABLE" ); + lnk_chunk_set_debugf(data_sect->arena, code_chunk, "IMPORT_TABLE_CODE" ); + 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"); @@ -42,12 +47,12 @@ lnk_import_table_alloc_static(LNK_SectionTable *st, LNK_SymbolTable *symtab, COF } internal LNK_ImportTable * -lnk_import_table_alloc_delayed(LNK_SectionTable *st, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable) +lnk_import_table_alloc_delayed(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine, B32 is_unloadable, B32 is_bindable) { ProfBeginFunction(); - LNK_Section *data_sect = lnk_section_table_push(st, str8_lit(".didat"), LNK_DEBUG_DIR_SECTION_FLAGS); - LNK_Section *code_sect = lnk_section_table_search(st, str8_lit(".text")); + LNK_Section *data_sect = lnk_section_table_push(sectab, str8_lit(".didat"), LNK_DEBUG_DIR_SECTION_FLAGS); + LNK_Section *code_sect = lnk_section_table_search(sectab, str8_lit(".text")); LNK_Chunk *dll_table_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); LNK_Chunk *int_chunk = lnk_section_push_chunk_list(data_sect, data_sect->root, str8_zero()); @@ -177,6 +182,10 @@ lnk_import_table_push_dll_static(LNK_ImportTable *imptab, LNK_SymbolTable *symta LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero()); 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()); + lnk_chunk_set_debugf(data_sect->arena, int_table_chunk, "%S.INT", dll_name); + lnk_chunk_set_debugf(data_sect->arena, ilt_table_chunk, "%S.ILT", dll_name); + lnk_chunk_set_debugf(data_sect->arena, iat_table_chunk, "%S.IAT", dll_name); + lnk_chunk_set_debugf(data_sect->arena, code_table_chunk, "%S.CODE", dll_name); 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); @@ -256,24 +265,26 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt // emit entry chunk 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()); + lnk_chunk_set_debugf(data_sect->arena, imp_desc_chunk, "%S.IMP_DESC", dll_name); // emit entry 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); + LNK_Chunk *int_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->int_chunk, str8_zero()); + lnk_chunk_set_debugf(data_sect->arena, int_table_chunk, "%S.DELAY_INT", dll_name); 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"); + lnk_chunk_set_debugf(data_sect->arena, null_string_chunk, "%S.STRING_TABLE_NULL", dll_name); // 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()); + lnk_chunk_set_debugf(data_sect->arena, name_chunk, "%S.DELAY_NAME", dll_name); 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); @@ -283,6 +294,7 @@ 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()); + lnk_chunk_set_debugf(data_sect->arena, handle_chunk, "%S.DELAY_HANDLE", dll_name); 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); @@ -292,18 +304,19 @@ 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()); + lnk_chunk_set_debugf(data_sect->arena, iat_table_chunk, "%S.DELAY_IAT", dll_name); 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); + lnk_chunk_set_debugf(data_sect->arena, null_iat_chunk, "%S.DELAY_IAT_TERMINATOR", dll_name); // emit ILT chunk LNK_Chunk *ilt_table_chunk = lnk_section_push_chunk_list(data_sect, imptab->ilt_chunk, str8_zero()); 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); + lnk_chunk_set_debugf(data_sect->arena, null_ilt_chunk, "%S.DELAY_ILT_TERMINATOR", dll_name); 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); @@ -318,6 +331,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Chunk *biat_chunk = 0; if (imptab->flags & LNK_ImportTableFlag_EmitBiat) { biat_chunk = lnk_section_push_chunk_list(data_sect, imptab->biat_chunk, str8_zero()); + lnk_chunk_set_debugf(data_sect->arena, biat_chunk, "%S.DELAY_BIAT", dll_name); 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); @@ -330,6 +344,7 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Chunk *uiat_chunk = NULL; if (imptab->flags & LNK_ImportTableFlag_EmitUiat) { uiat_chunk = lnk_section_push_chunk_list(data_sect, imptab->uiat_chunk, str8_zero()); + lnk_chunk_set_debugf(data_sect->arena, uiat_chunk, "%S.DELAY_UIAT", dll_name); 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); @@ -340,14 +355,15 @@ lnk_import_table_push_dll_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *symt // emit chunk for DLL thunk/load code LNK_Chunk *code_chunk = lnk_section_push_chunk_list(code_sect, imptab->code_chunk, str8_zero()); - lnk_chunk_set_debugf(code_sect->arena, code_chunk, "code for %S", dll_name); + lnk_chunk_set_debugf(code_sect->arena, code_chunk, "%S.DLAY_CODE", dll_name); // emit tail merge LNK_Chunk *tail_merge_chunk = 0; switch (machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { LNK_Symbol *delay_load_helper_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], str8_lit(LNK_DELAY_LOAD_HELPER2_SYMBOL_NAME), LNK_SymbolScopeFlag_Main); tail_merge_chunk = lnk_emit_tail_merge_thunk_x64(code_sect, code_chunk, imp_desc_symbol, delay_load_helper_symbol); + lnk_chunk_set_debugf(code_sect->arena, code_chunk, "%S.X64_TAIL_MERGE", dll_name); } break; default: { lnk_not_implemented("TODO: __tailMerge for %S", coff_string_from_machine_type(machine)); @@ -402,6 +418,8 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt String8 ordinal_data = lnk_ordinal_data_from_hint(data_sect->arena, dll->machine, header->hint_or_ordinal); ilt_chunk = lnk_section_push_chunk_data(data_sect, ilt_table_chunk, ordinal_data, sort_index); iat_chunk = lnk_section_push_chunk_data(data_sect, iat_table_chunk, ordinal_data, sort_index); + lnk_chunk_set_debugf(data_sect->arena, ilt_chunk, "ILT entry for %S.%u", dll->name, header->hint_or_ordinal); + lnk_chunk_set_debugf(data_sect->arena, iat_chunk, "IAT entry for %S.%u", dll->name, header->hint_or_ordinal); // associate chunks lnk_section_associate_chunks(data_sect, iat_chunk, ilt_chunk); @@ -410,6 +428,7 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt // put together name look up entry String8 int_data = coff_make_import_lookup(data_sect->arena, header->hint_or_ordinal, header->func_name); LNK_Chunk *int_chunk = lnk_section_push_chunk_data(data_sect, int_table_chunk, int_data, str8_zero()); + lnk_chunk_set_debugf(data_sect->arena, int_chunk, "INT entry for %S.%S (Hint: %u)", dll->name, header->func_name, header->hint_or_ordinal); // create symbol for lookup chunk String8 int_symbol_name = push_str8f(symtab->arena->v[0], "static.%S.%S.name", dll->name, header->func_name); @@ -446,10 +465,11 @@ lnk_import_table_push_func_static(LNK_ImportTable *imptab, LNK_SymbolTable *symt LNK_Symbol *jmp_thunk_symbol = g_null_symbol_ptr; if (header->type == COFF_ImportHeader_Code) { switch (dll->machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { // generate jump thunk LNK_Chunk *jmp_thunk_chunk = lnk_emit_indirect_jump_thunk_x64(code_sect, code_table_chunk, iat_symbol); lnk_section_associate_chunks(data_sect, iat_chunk, jmp_thunk_chunk); + lnk_chunk_set_debugf(data_sect->arena, jmp_thunk_chunk, "Jump thunk to %S.%S", dll->name, iat_symbol->name); // push jump thunk symbol String8 jmp_thunk_symbol_name = push_str8_copy(symtab->arena->v[0], header->func_name); @@ -507,7 +527,7 @@ lnk_import_table_push_func_delayed(LNK_ImportTable *imptab, LNK_SymbolTable *sym LNK_Chunk *load_thunk_chunk = 0; if (header->type == COFF_ImportHeader_Code) { switch (dll->machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { String8 iat_symbol_name = push_str8f(symtab->arena->v[0], "__imp_%S", header->func_name); LNK_Symbol *iat_symbol = lnk_make_undefined_symbol(symtab->arena->v[0], iat_symbol_name, LNK_SymbolScopeFlag_Main); @@ -624,12 +644,12 @@ lnk_ordinal_data_from_hint(Arena *arena, COFF_MachineType machine, U16 hint) { String8 ordinal_data = str8_zero(); switch (machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { U64 *ordinal = push_array(arena, U64, 1); *ordinal = coff_make_ordinal64(hint); ordinal_data = str8_struct(ordinal); } break; - case COFF_Machine_X86: { + case COFF_MachineType_X86: { U32 *ordinal = push_array(arena, U32, 1); *ordinal = coff_make_ordinal32(hint); ordinal_data = str8_struct(ordinal); diff --git a/src/linker/lnk_import_table.h b/src/linker/lnk_import_table.h index 6005b622..3bb9eb2f 100644 --- a/src/linker/lnk_import_table.h +++ b/src/linker/lnk_import_table.h @@ -59,8 +59,8 @@ typedef struct LNK_ImportTable HashTable *dll_ht; } LNK_ImportTable; -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 LNK_ImportTable * lnk_import_table_alloc_static(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, COFF_MachineType machine); +internal LNK_ImportTable * lnk_import_table_alloc_delayed(LNK_SectionTable *sectab, 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_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); diff --git a/src/linker/lnk_io.c b/src/linker/lnk_io.c index 8969cd50..6b9aee8d 100644 --- a/src/linker/lnk_io.c +++ b/src/linker/lnk_io.c @@ -53,6 +53,118 @@ lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_ //////////////////////////////// +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; +} + +internal OS_Handle +lnk_file_open_with_rename_permissions(String8 path) +{ + OS_Handle file_handle = os_handle_zero(); +#if _WIN32 + Temp scratch = scratch_begin(0,0); + + // open file with permissions to rename + String16 path16 = str16_from_8(scratch.arena, path); + SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes) }; + HANDLE native_handle = CreateFileW((WCHAR*)path16.str, + GENERIC_WRITE|DELETE, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + &security_attributes, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0); + if (native_handle != INVALID_HANDLE_VALUE) { + file_handle.u64[0] = (U64)native_handle; + } + + scratch_end(scratch); +#else +#error "TODO: file rename" +#endif + return file_handle; +} + +internal B32 +lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file) +{ +#if _WIN32 + FILE_DISPOSITION_INFO file_disposition = {0}; + file_disposition.DeleteFile = (BOOL)delete_file; + B32 is_set = SetFileInformationByHandle((HANDLE)handle.u64[0], FileDispositionInfo, &file_disposition, sizeof(file_disposition)); +#else +#error "TODO: file rename" +#endif + return is_set; +} + +internal B32 +lnk_file_rename(OS_Handle handle, String8 new_name) +{ + Temp scratch = scratch_begin(0,0); +#if _WIN32 + String16 new_name16 = str16_from_8(scratch.arena, new_name); + + U64 file_rename_info_size = sizeof(FILE_RENAME_INFO); + U64 buffer_size = file_rename_info_size + sizeof(new_name16.str)*new_name16.size; + U8 *buffer = push_array(scratch.arena, U8, buffer_size); + + FILE_RENAME_INFO *rename_info = (FILE_RENAME_INFO *)buffer; + rename_info->ReplaceIfExists = 1; + rename_info->FileNameLength = new_name16.size * sizeof(new_name16.str[0]); + MemoryCopy(rename_info->FileName, new_name16.str, new_name16.size * sizeof(new_name16.str[0])); + + B32 is_renamed = SetFileInformationByHandle((HANDLE)handle.u64[0], FileRenameInfo, buffer, buffer_size); +#else +#error "TODO: file rename" +#endif + scratch_end(scratch); + return is_renamed; +} + internal void lnk_log_read(String8 path, U64 size) { @@ -163,33 +275,69 @@ lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array } internal void -lnk_write_data_list_to_file_path(String8 path, String8List data) +lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List data) { ProfBeginV("Write %M to %S", data.total_size, path); - B32 is_written = 0; + B32 open_with_rename = (temp_path.size > 0); + OS_Handle file_handle = {0}; + String8 open_file_path = {0}; + if (open_with_rename) { + file_handle = lnk_file_open_with_rename_permissions(temp_path); + open_file_path = temp_path; - OS_Handle handle; - if (lnk_open_file_write((char*)path.str, path.size, &handle, sizeof(handle))) { - U64 offset = 0; + // mark file to be deleted on exit, so we don't leave corrupted files on disk + if (!lnk_file_set_delete_on_close(file_handle, 1)) { + lnk_error(LNK_Error_IO, "failed to update file disposition on %S", open_file_path); + } + } else { + lnk_open_file_write((char*)path.str, path.size, &file_handle, sizeof(file_handle)); + open_file_path = path; + } + + if (!os_handle_match(file_handle, os_handle_zero())) { + // try to reserve up front file size + if (!os_file_reserve_size(file_handle, data.total_size)) { + lnk_log(LNK_Log_IO_Write, "Failed to pre-allocate file %S with size %M", open_file_path, data.total_size); + } + + // write data nodes + U64 bytes_written = 0; for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) { - U64 write_size = lnk_write_file(&handle, offset, data_n->string.str, data_n->string.size); + U64 write_size = lnk_write_file(&file_handle, bytes_written, data_n->string.str, data_n->string.size); if (write_size != data_n->string.size) { break; } - offset += data_n->string.size; + bytes_written += data_n->string.size; + } + B32 is_write_complete = (bytes_written == data.total_size); + + if (is_write_complete) { + // rename temp file + if (open_with_rename) { + // all writes succeeded, remove delete on exit flag + if (!lnk_file_set_delete_on_close(file_handle, 0)) { + lnk_error(LNK_Error_IO, "failed to update file disposition on %S", open_file_path); + } + + if (lnk_file_rename(file_handle, path)) { + lnk_log(LNK_Log_IO_Write, "Renamed %S -> %S", temp_path, path); + } else { + lnk_error(LNK_Error_IO, "failed to rename %S -> %S", temp_path, path); + } + } } - lnk_close_file(&handle); + // clean up file handle + lnk_close_file(&file_handle); - is_written = (offset == data.total_size); - if (is_written) { + // log write + if (is_write_complete) { 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); + lnk_error(LNK_Error_IO, "incomplete write, %M written, expected %M, file %S", bytes_written, data.total_size, path); } } else { lnk_error(LNK_Error_NoAccess, "don't have access to write to %S", path); @@ -199,59 +347,13 @@ lnk_write_data_list_to_file_path(String8 path, String8List data) } internal void -lnk_write_data_to_file_path(String8 path, String8 data) +lnk_write_data_to_file_path(String8 path, String8 temp_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); + lnk_write_data_list_to_file_path(path, temp_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; -} diff --git a/src/linker/lnk_io.h b/src/linker/lnk_io.h index 9bd504bb..13b0d777 100644 --- a/src/linker/lnk_io.h +++ b/src/linker/lnk_io.h @@ -24,11 +24,16 @@ shared_function uint64_t lnk_write_file(void *raw_handle, uint64_t offset, void //////////////////////////////// +internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path); + +internal OS_Handle lnk_file_open_with_rename_permissions(String8 path); +internal B32 lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file); +internal B32 lnk_file_rename(OS_Handle handle, String8 new_name); + 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 void lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List list); +internal void lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data); -internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path); diff --git a/src/linker/lnk_lib.c b/src/linker/lnk_lib.c index b200b1db..d02f4fac 100644 --- a/src/linker/lnk_lib.c +++ b/src/linker/lnk_lib.c @@ -541,7 +541,7 @@ lnk_build_import_entry_obj(Arena *arena, String8 dll_name, COFF_MachineType mach { ProfBeginFunction(); - Assert(machine == COFF_Machine_X64); + Assert(machine == COFF_MachineType_X64); Assert(str8_match_lit("dll", str8_skip_last_dot(dll_name), StringMatchFlag_CaseInsensitive|StringMatchFlag_RightSideSloppy)); String8List list = {0}; @@ -939,16 +939,16 @@ lnk_build_import_lib(TP_Context *tp, TP_Arena *arena, COFF_MachineType machine, } LNK_InputObj **inputs = lnk_array_from_input_obj_list(scratch.arena, input_obj_list); - LNK_SectionTable *st = lnk_section_table_alloc(0,0,0); + LNK_SectionTable *sectab = lnk_section_table_alloc(0,0,0); LNK_ObjList obj_list = {0}; - lnk_obj_list_push_parallel(tp, arena, &obj_list, st, 0, input_obj_list.count, inputs); + lnk_obj_list_push_parallel(tp, arena, &obj_list, sectab, 0, input_obj_list.count, inputs); LNK_LibBuild import_lib = lnk_build_lib(scratch.arena, machine, time_stamp, dll_name, obj_list, exptab); B32 emit_second_member = 0; // MSVC linker refuses to link with lib that has the second member. String8List coff_archive_data = lnk_coff_archive_from_lib_build(arena->v[0], &import_lib, emit_second_member, time_stamp, /* -rw-r--r-- */ 644); // cleanup memory - lnk_section_table_release(&st); + lnk_section_table_release(§ab); scratch_end(scratch); ProfEnd(); diff --git a/src/linker/lnk_obj.c b/src/linker/lnk_obj.c index d53802d2..af16561c 100644 --- a/src/linker/lnk_obj.c +++ b/src/linker/lnk_obj.c @@ -315,105 +315,50 @@ lnk_sect_defn_list_concat_in_place_arr(LNK_SectDefnList *list, LNK_SectDefnList internal THREAD_POOL_TASK_FUNC(lnk_obj_initer) { - Temp scratch = scratch_begin(&arena, 1); - - LNK_ObjIniter *task = raw_task; - LNK_InputObj *input = task->inputs[task_id]; - U64 obj_idx = task->obj_id_base + task_id; - LNK_ObjNode *obj_node = task->obj_node_arr + task_id; - LNK_Obj *obj = &obj_node->data; + LNK_ObjIniter *task = raw_task; + LNK_InputObj *input = task->inputs[task_id]; + LNK_Obj *obj = &task->obj_node_arr[task_id].data; + U64 obj_idx = task->obj_id_base + task_id; - String8 cached_path = push_str8_copy(arena, input->path); - String8 cached_lib_path = push_str8_copy(arena, input->lib_path); - - // parse coff obj + // + // parse obj header + // COFF_FileHeaderInfo coff_info = coff_file_header_info_from_data(input->data); - Rng1U64 coff_file_header_range = rng_1u64(0, coff_info.header_size); - Rng1U64 coff_sect_arr_range = rng_1u64(coff_info.section_array_off, coff_info.section_array_off + coff_info.section_count_no_null * sizeof(COFF_SectionHeader)); - Rng1U64 coff_symbols_range = rng_1u64(coff_info.symbol_off, coff_info.symbol_off + coff_info.symbol_count * coff_info.symbol_size); - String8 raw_coff_sect_arr = str8_substr(input->data, coff_sect_arr_range); - String8 raw_coff_symbols = str8_substr(input->data, coff_symbols_range); + String8 raw_coff_section_table = str8_substr(input->data, coff_info.section_table_range); + String8 raw_coff_symbol_table = str8_substr(input->data, coff_info.symbol_table_range); + String8 raw_coff_string_table = str8_substr(input->data, coff_info.string_table_range); - if (raw_coff_sect_arr.size != dim_1u64(coff_sect_arr_range)) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read section header table"); + // + // error check: section table / symbol table / string table + // + if (raw_coff_section_table.size != dim_1u64(coff_info.section_table_range)) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read section header table"); } - if (raw_coff_symbols.size != dim_1u64(coff_symbols_range)) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "corrupted file, unable to read symbol table"); + if (raw_coff_symbol_table.size != dim_1u64(coff_info.symbol_table_range)) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read symbol table"); + } + if (raw_coff_string_table.size != dim_1u64(coff_info.string_table_range)) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "corrupted file, unable to read string table"); } - COFF_SectionHeader *coff_sect_arr = (COFF_SectionHeader *)raw_coff_sect_arr.str; - void *coff_symbols = raw_coff_symbols.str; + U64 chunk_count = coff_info.section_count_no_null + /* :common_block */ 1; + String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); + String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); + LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, chunk_count); + LNK_ChunkPtr *chunk_ptr_arr = push_array_no_zero(arena, LNK_ChunkPtr, chunk_count); - // :function_pad_min - U64 function_pad_min; - if (task->function_pad_min) { - function_pad_min = *task->function_pad_min; - } else { - function_pad_min = lnk_get_default_function_pad_min(coff_info.machine); + for (U64 chunk_idx = 0; chunk_idx < chunk_count; chunk_idx += 1) { + chunk_ptr_arr[chunk_idx] = &chunk_arr[chunk_idx]; } - U64 chunk_count = 1; // :common_block - chunk_count += coff_info.section_count_no_null; + // + // setup :common_block + // - String8 *sect_name_arr = push_array_no_zero(arena, String8, chunk_count); - String8 *sect_sort_arr = push_array_no_zero(arena, String8, chunk_count); - LNK_Chunk *chunk_arr = push_array(arena, LNK_Chunk, chunk_count); - - // :common_block U64 common_block_idx = chunk_count - 1; sect_name_arr[common_block_idx] = str8_lit(".bss"); sect_sort_arr[common_block_idx] = str8_lit("~"); - for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { - COFF_SectionHeader *coff_sect = &coff_sect_arr[sect_idx]; - - // read name - String8 sect_name = coff_name_from_section_header(input->data, coff_sect, coff_info.string_table_off); - - // parse section name - coff_parse_section_name(sect_name, §_name_arr[sect_idx], §_sort_arr[sect_idx]); - - String8 data; - if (coff_sect->flags & COFF_SectionFlag_CntUninitializedData) { - data = str8(0, coff_sect->fsize); - } else { - if (coff_sect->fsize > 0) { - Rng1U64 range = rng_1u64(coff_sect->foff, coff_sect->foff + coff_sect->fsize); - data = str8_substr(input->data, range); - - if (contains_1u64(coff_file_header_range, coff_sect->foff) || - (coff_sect->fsize > 0 && contains_1u64(coff_file_header_range, coff_sect->foff + coff_sect->fsize-1))) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1); - } - if (contains_1u64(coff_sect_arr_range, coff_sect->foff) || - (coff_sect->fsize > 0 && contains_1u64(coff_sect_arr_range, coff_sect->foff + coff_sect->fsize-1))) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into section header table)", sect_name, sect_idx+1); - } - if (contains_1u64(coff_symbols_range, coff_sect->foff) || - (coff_sect->fsize > 0 && contains_1u64(coff_symbols_range, coff_sect->foff + coff_sect->fsize-1))) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into symbol table)", sect_name, sect_idx+1); - } - if (dim_1u64(range) != coff_sect->fsize) { - lnk_error_with_loc(LNK_Error_IllData, cached_path, cached_lib_path, "header (%S No. %#llx) defines out of bounds section data", sect_name, sect_idx+1); - } - } else { - data = str8_zero(); - } - } - - LNK_Chunk *chunk = &chunk_arr[sect_idx]; - chunk->align = coff_align_size_from_section_flags(coff_sect->flags); - chunk->is_discarded = !!(coff_sect->flags & COFF_SectionFlag_LnkRemove); - chunk->sort_chunk = 1; - chunk->type = LNK_Chunk_Leaf; - chunk->sort_idx = sect_sort_arr[sect_idx]; - chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx); - chunk->flags = coff_sect->flags; - chunk->u.leaf = data; - lnk_chunk_set_debugf(arena, chunk, "%S: name: %S, obj_idx: 0x%llX isect: 0x%llX", cached_path, sect_name_arr[sect_idx], obj_idx, sect_idx); - } - - // :common_block LNK_Chunk *master_common_block = &chunk_arr[common_block_idx]; master_common_block->ref = lnk_chunk_ref(0,0); // :chunk_ref_assign master_common_block->align = 1; @@ -425,23 +370,120 @@ 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", cached_path); + master_common_block->obj = obj; + lnk_chunk_set_debugf(arena, master_common_block, "obj[%llx] master common block", obj_idx); - LNK_ChunkPtr *chunk_ptr_arr = push_array_no_zero(arena, LNK_ChunkPtr, chunk_count); - for (U64 i = 0; i < chunk_count; ++i) { - chunk_ptr_arr[i] = &chunk_arr[i]; + // + // parse section table + // + COFF_SectionHeader *coff_section_table = (COFF_SectionHeader *)raw_coff_section_table.str; + for (U64 sect_idx = 0; sect_idx < coff_info.section_count_no_null; sect_idx += 1) { + COFF_SectionHeader *coff_sect_header = &coff_section_table[sect_idx]; + + // read name + String8 sect_name = coff_name_from_section_header(raw_coff_string_table, coff_sect_header); + + // parse name + coff_parse_section_name(sect_name, §_name_arr[sect_idx], §_sort_arr[sect_idx]); + + // find contents + String8 sect_data; + if (coff_sect_header->flags & COFF_SectionFlag_CntUninitializedData) { + sect_data = str8(0, coff_sect_header->fsize); + } else { + if (coff_sect_header->fsize > 0) { + Rng1U64 sect_range = rng_1u64(coff_sect_header->foff, coff_sect_header->foff + coff_sect_header->fsize); + sect_data = str8_substr(input->data, sect_range); + + if (contains_1u64(coff_info.header_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(coff_info.header_range, sect_range.max-1))) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into file header)", sect_name, sect_idx+1); + } + if (contains_1u64(coff_info.section_table_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(coff_info.section_table_range, sect_range.max-1))) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into section header table)", sect_name, sect_idx+1); + } + if (contains_1u64(coff_info.symbol_table_range, coff_sect_header->foff) || + (coff_sect_header->fsize > 0 && contains_1u64(coff_info.symbol_table_range, sect_range.max-1))) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data (file offsets point into symbol table)", sect_name, sect_idx+1); + } + if (dim_1u64(sect_range) != coff_sect_header->fsize) { + lnk_error_with_loc(LNK_Error_IllData, input->path, input->lib_path, "header (%S No. %#llx) defines out of bounds section data", sect_name, sect_idx+1); + } + } else { + sect_data = str8_zero(); + } + } + + // fill out chunk + LNK_Chunk *chunk = &chunk_arr[sect_idx]; + chunk->align = coff_align_size_from_section_flags(coff_sect_header->flags); + chunk->is_discarded = !!(coff_sect_header->flags & COFF_SectionFlag_LnkRemove); + chunk->sort_chunk = 1; + chunk->type = LNK_Chunk_Leaf; + chunk->sort_idx = sect_sort_arr[sect_idx]; + chunk->input_idx = LNK_MakeChunkInputIdx(obj_idx, sect_idx); + chunk->flags = coff_sect_header->flags; + chunk->u.leaf = sect_data; + chunk->obj = obj; + lnk_chunk_set_debugf(arena, chunk, "obj[%llx] sect[%llx]", obj_idx, sect_idx); + } + + // + // :function_pad_min + // + U64 function_pad_min; + if (task->function_pad_min) { + function_pad_min = *task->function_pad_min; + } else { + function_pad_min = lnk_get_default_function_pad_min(coff_info.machine); + } + + // + // convert from COFF + // + void *coff_symbol_table = raw_coff_symbol_table.str; + LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, obj, input->path, input->lib_path, coff_info.is_big_obj, function_pad_min, coff_info.section_count_no_null, coff_section_table, coff_info.symbol_count, coff_symbol_table, raw_coff_string_table, chunk_ptr_arr, master_common_block); + LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); + LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_section_table, chunk_ptr_arr, symbol_arr); + + // + // parse directives + // + LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, input->path, input->lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); + + // parse exports + LNK_ExportParseList export_parse = {0}; + for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) { + lnk_parse_export_directive(arena, &export_parse, dir->value_list, input->path, input->lib_path); + } + + // push /export symbols + for (LNK_ExportParse *exp = export_parse.first; exp != 0; exp = exp->next) { + LNK_Symbol *symbol = lnk_make_undefined_symbol(arena, exp->name, LNK_SymbolScopeFlag_Main); + lnk_symbol_list_push(arena, &symbol_list, symbol); + } + + // push /include symbols + String8List include_symbol_list = {0}; + for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_Include].first; dir != 0; dir = dir->next) { + str8_list_concat_in_place(&include_symbol_list, &dir->value_list); + } + + // parse /alternatename + LNK_AltNameList alt_name_list = {0}; + for (LNK_Directive *dir = directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) { + String8 *invalid_string = lnk_parse_alt_name_directive_list(arena, dir->value_list, &alt_name_list); + if (invalid_string != 0) { + lnk_error_with_loc(LNK_Error_Cmdl, input->path, input->lib_path, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string); + } } - // convert from coff - LNK_SymbolArray symbol_arr = lnk_symbol_array_from_coff(arena, input->data, obj, cached_path, cached_lib_path, coff_info.is_big_obj, function_pad_min, coff_info.string_table_off, coff_info.section_count_no_null, coff_sect_arr, coff_info.symbol_count, coff_symbols, chunk_ptr_arr, master_common_block); - LNK_SymbolList symbol_list = lnk_symbol_list_from_array(arena, symbol_arr); - LNK_RelocList *reloc_list_arr = lnk_reloc_list_array_from_coff(arena, coff_info.machine, input->data, coff_info.section_count_no_null, coff_sect_arr, chunk_ptr_arr, symbol_arr); - LNK_DirectiveInfo directive_info = lnk_directive_info_from_sections(arena, cached_path, cached_lib_path, coff_info.section_count_no_null, reloc_list_arr, sect_name_arr, chunk_arr); // fill out obj obj->data = input->data; - obj->path = cached_path; - obj->lib_path = cached_lib_path; + obj->path = push_str8_copy(arena, input->path); + obj->lib_path = push_str8_copy(arena, input->lib_path); obj->input_idx = obj_idx; obj->machine = coff_info.machine; obj->chunk_count = chunk_count; @@ -452,33 +494,9 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer) obj->symbol_list = symbol_list; obj->sect_reloc_list_arr = reloc_list_arr; obj->directive_info = directive_info; - - // parse exports - LNK_ExportParseList export_parse = {0}; - for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Export].first; dir != 0; dir = dir->next) { - lnk_parse_export_directive(arena, &obj->export_parse, dir->value_list, obj->path, obj->lib_path); - } - - // push /export symbols - for (LNK_ExportParse *exp = export_parse.first; exp != 0; exp = exp->next) { - LNK_Symbol *symbol = lnk_make_undefined_symbol(arena, exp->name, LNK_SymbolScopeFlag_Main); - lnk_symbol_list_push(arena, &obj->symbol_list, symbol); - } - - // push /include symbols - for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_Include].first; dir != 0; dir = dir->next) { - str8_list_concat_in_place(&obj->include_symbol_list, &dir->value_list); - } - - // parse /alternatename - for (LNK_Directive *dir = obj->directive_info.v[LNK_CmdSwitch_AlternateName].first; dir != 0; dir = dir->next) { - String8 *invalid_string = lnk_parse_alt_name_directive_list(arena, dir->value_list, &obj->alt_name_list); - if (invalid_string != 0) { - lnk_error_obj(LNK_Error_Cmdl, obj, "invalid syntax \"%S\", expected format \"FROM=TO\"", *invalid_string); - } - } - - scratch_end(scratch); + obj->export_parse = export_parse; + obj->include_symbol_list = include_symbol_list; + obj->alt_name_list = alt_name_list; } internal @@ -526,14 +544,14 @@ THREAD_POOL_TASK_FUNC(lnk_chunk_counter) LNK_ChunkCounter *task = raw_task; LNK_Obj *obj = &task->obj_arr[obj_idx].data; for (U64 chunk_idx = 0; chunk_idx < obj->chunk_count; chunk_idx += 1) { - String8 name = obj->sect_name_arr[chunk_idx]; + String8 name = obj->sect_name_arr[chunk_idx]; LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; - LNK_Section *sect = lnk_section_table_search(task->st, name); + LNK_Section *sect = lnk_section_table_search(task->sectab, name); U64 count = 0; lnk_visit_chunks(0, chunk, lnk_chunk_get_count_cb, &count); - task->chunk_count_arr_arr[sect->id][obj_idx] += count; + task->chunk_counts[sect->id][obj_idx] += count; } } @@ -543,8 +561,8 @@ LNK_CHUNK_VISITOR_SIG(lnk_chunk_ref_assign) LNK_ChunkRefAssign *ctx = ud; // alloc chunk id - U64 chunk_id = ctx->chunk_id_arr_arr[sect_id][ctx->obj_idx]; - ctx->chunk_id_arr_arr[sect_id][ctx->obj_idx] += 1; + U64 chunk_id = *ctx->chunk_id; + *ctx->chunk_id += 1; // set chunk ref chunk->ref = lnk_chunk_ref(sect_id, chunk_id); @@ -568,14 +586,12 @@ THREAD_POOL_TASK_FUNC(lnk_chunk_ref_assigner) LNK_Chunk *chunk = obj->chunk_arr[chunk_idx]; // :find_chunk_section - LNK_Section *sect = lnk_section_table_search(task->st, name); - Assert(sect); + LNK_Section *sect = lnk_section_table_search(task->sectab, name); // :chunk_ref_assign - LNK_ChunkRefAssign ctx; - ctx.cman = sect->cman; - ctx.chunk_id_arr_arr = task->chunk_id_arr_arr; - ctx.obj_idx = obj_idx; + LNK_ChunkRefAssign ctx = {0}; + ctx.cman = sect->cman; + ctx.chunk_id = &task->chunk_ids[sect->id][obj_idx]; lnk_visit_chunks(sect->id, chunk, lnk_chunk_ref_assign, &ctx); // push to section chunk list @@ -589,7 +605,7 @@ internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *arena, LNK_ObjList *obj_list, - LNK_SectionTable *st, + LNK_SectionTable *sectab, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs) @@ -611,7 +627,7 @@ lnk_obj_list_push_parallel(TP_Context *tp, } ProfEnd(); - if (st) { + if (sectab) { ProfBegin("Section Table Update"); { TP_Temp temp = tp_temp_begin(arena); @@ -631,7 +647,7 @@ lnk_obj_list_push_parallel(TP_Context *tp, HashTable *ht = hash_table_init(arena->v[0], 128); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; hash_table_push_string_u64(arena->v[0], ht, sect->name, sect->flags); } @@ -674,7 +690,7 @@ lnk_obj_list_push_parallel(TP_Context *tp, // push new sections for :find_chunk_section for (LNK_SectDefn *curr = new_list.first; curr != 0; curr = curr->next) { - lnk_section_table_push(st, curr->name, curr->flags & ~COFF_SectionFlags_LnkFlags); + lnk_section_table_push(sectab, curr->name, curr->flags & ~COFF_SectionFlags_LnkFlags); } tp_temp_end(temp); @@ -682,27 +698,27 @@ lnk_obj_list_push_parallel(TP_Context *tp, ProfEnd(); ProfBegin("Count Chunks Per Section"); - U64 **chunk_id_arr_arr; + U64 **chunk_ids; { - U64 **chunk_count_arr_arr = push_array_no_zero(scratch.arena, U64 *, st->id_max); - for (U64 sect_idx = 0; sect_idx < st->id_max; sect_idx += 1) { - chunk_count_arr_arr[sect_idx] = push_array(scratch.arena, U64, obj_arr.count); + U64 **chunk_counts = push_array_no_zero(scratch.arena, U64 *, sectab->id_max); + for (U64 sect_idx = 0; sect_idx < sectab->id_max; sect_idx += 1) { + chunk_counts[sect_idx] = push_array(scratch.arena, U64, obj_arr.count); } - LNK_ChunkCounter task; - task.st = st; - task.obj_arr = obj_arr.v; - task.chunk_count_arr_arr = chunk_count_arr_arr; + LNK_ChunkCounter task = {0}; + task.sectab = sectab; + task.obj_arr = obj_arr.v; + task.chunk_counts = chunk_counts; tp_for_parallel(tp, 0, obj_arr.count, lnk_chunk_counter, &task); - chunk_id_arr_arr = chunk_count_arr_arr; - for (U64 sect_idx = 1; sect_idx < st->id_max; sect_idx += 1) { - LNK_Section *sect = lnk_section_table_search_id(st, sect_idx); + chunk_ids = chunk_counts; + for (U64 sect_idx = 1; sect_idx < sectab->id_max; sect_idx += 1) { + LNK_Section *sect = lnk_section_table_search_id(sectab, sect_idx); if (!sect) continue; for (U64 obj_idx = 0; obj_idx < obj_arr.count; obj_idx += 1) { U64 chunk_id_base = sect->cman->total_chunk_count; - sect->cman->total_chunk_count += chunk_count_arr_arr[sect_idx][obj_idx]; - chunk_id_arr_arr[sect_idx][obj_idx] = chunk_id_base; + sect->cman->total_chunk_count += chunk_counts[sect_idx][obj_idx]; + chunk_ids[sect_idx][obj_idx] = chunk_id_base; } } } @@ -711,16 +727,16 @@ lnk_obj_list_push_parallel(TP_Context *tp, ProfBegin("Assign Chunk Refs"); { LNK_ChunkRefAssigner task; - task.st = st; + task.sectab = sectab; task.range_arr = tp_divide_work(scratch.arena, obj_arr.count, tp->worker_count); - task.chunk_id_arr_arr = chunk_id_arr_arr; + task.chunk_ids = chunk_ids; task.obj_arr = obj_arr.v; - task.nosort_chunk_list_arr_arr = lnk_make_chunk_list_arr_arr(scratch.arena, st->id_max, tp->worker_count); - task.chunk_list_arr_arr = lnk_make_chunk_list_arr_arr(scratch.arena, st->id_max, tp->worker_count); + task.nosort_chunk_list_arr_arr = lnk_make_chunk_list_arr_arr(scratch.arena, sectab->id_max, tp->worker_count); + task.chunk_list_arr_arr = lnk_make_chunk_list_arr_arr(scratch.arena, sectab->id_max, tp->worker_count); tp_for_parallel(tp, arena, tp->worker_count, lnk_chunk_ref_assigner, &task); // merge chunks - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; lnk_chunk_list_concat_in_place_arr(sect->nosort_chunk->u.list, task.nosort_chunk_list_arr_arr[sect->id], tp->worker_count); lnk_chunk_list_concat_in_place_arr(sect->root->u.list, task.chunk_list_arr_arr[sect->id], tp->worker_count); @@ -736,28 +752,27 @@ lnk_obj_list_push_parallel(TP_Context *tp, internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, - String8 raw_coff, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, - U64 string_table_off, U64 sect_count, - COFF_SectionHeader *coff_sect_arr, - U64 coff_symbol_count, - void *coff_symbols, - LNK_ChunkPtr *chunk_ptr_arr, + COFF_SectionHeader *section_table, + U64 symbol_count, + void *symbol_table, + String8 string_table, + LNK_ChunkPtr *chunk_table, LNK_Chunk *master_common_block) { if (function_pad_min) { COFF_ParsedSymbol symbol; - for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { + for (U64 symbol_idx = 0; symbol_idx < symbol_count; symbol_idx += (1 + symbol.aux_symbol_count)) { // read symbol if (is_big_obj) { - symbol = coff_parse_symbol32(raw_coff, string_table_off, &((COFF_Symbol32 *)coff_symbols)[symbol_idx]); + symbol = coff_parse_symbol32(string_table, &((COFF_Symbol32 *)symbol_table)[symbol_idx]); } else { - symbol = coff_parse_symbol16(raw_coff, string_table_off, &((COFF_Symbol16 *)coff_symbols)[symbol_idx]); + symbol = coff_parse_symbol16(string_table, &((COFF_Symbol16 *)symbol_table)[symbol_idx]); } // is this a function symbol? @@ -766,11 +781,11 @@ lnk_symbol_array_from_coff(Arena *arena, if (symbol.section_number == 0 || symbol.section_number > sect_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out ouf bounds section index in symbol \"%S (%u)\"", symbol.name, symbol.section_number); } - if (symbol.value > coff_sect_arr[symbol.section_number-1].fsize) { + if (symbol.value > section_table[symbol.section_number-1].fsize) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "out of bounds section offset in symbol \"%S (%u)\"", symbol.name, symbol.value); } - LNK_Chunk *chunk = chunk_ptr_arr[symbol.section_number-1]; + LNK_Chunk *chunk = chunk_table[symbol.section_number-1]; if (symbol.value > 0) { // convert leaf to list // @@ -787,7 +802,8 @@ lnk_symbol_array_from_coff(Arena *arena, chunk_list->input_idx = chunk->input_idx; chunk_list->flags = chunk->flags; chunk_list->u.list = push_array(arena, LNK_ChunkList, 1); - lnk_chunk_set_debugf(arena, chunk_list, "%S: function chunk list for %S", obj_path, symbol.name); + chunk_list->obj = obj; + lnk_chunk_set_debugf(arena, chunk_list, "function chunk list for %S", symbol.name); // update properties on first chunk chunk->min_size = function_pad_min; @@ -802,7 +818,7 @@ lnk_symbol_array_from_coff(Arena *arena, chunk = chunk_list; // set list chunk to be head of this section - chunk_ptr_arr[symbol.section_number-1] = chunk_list; + chunk_table[symbol.section_number-1] = chunk_list; } // find chunk that is near symbol @@ -834,7 +850,8 @@ lnk_symbol_array_from_coff(Arena *arena, split_chunk->is_discarded = current->data->is_discarded; split_chunk->flags = current->data->flags; split_chunk->u.leaf = right_data; - lnk_chunk_set_debugf(arena, split_chunk, "%S: chunk split on function %S SECT%x SPLIT_POS %#llx", obj_path, symbol.name, symbol.section_number, split_pos); + split_chunk->obj = obj; + lnk_chunk_set_debugf(arena, split_chunk, "chunk split on function %S sect %x split pos %#llx", symbol.name, symbol.section_number, split_pos); LNK_ChunkNode *split_node = push_array(arena, LNK_ChunkNode, 1); split_node->data = split_chunk; @@ -856,23 +873,23 @@ lnk_symbol_array_from_coff(Arena *arena, } LNK_SymbolArray symbol_array = {0}; - symbol_array.count = coff_symbol_count; + symbol_array.count = symbol_count; symbol_array.v = push_array(arena, LNK_Symbol, symbol_array.count); COFF_ParsedSymbol parsed_symbol; - for (U64 symbol_idx = 0; symbol_idx < coff_symbol_count; symbol_idx += (1 + parsed_symbol.aux_symbol_count)) { + for (U64 symbol_idx = 0; symbol_idx < symbol_count; symbol_idx += (1 + parsed_symbol.aux_symbol_count)) { void *aux_symbols; if (is_big_obj) { - COFF_Symbol32 *ptr = &((COFF_Symbol32 *)coff_symbols)[symbol_idx]; - parsed_symbol = coff_parse_symbol32(raw_coff, string_table_off, ptr); - aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; + COFF_Symbol32 *ptr = &((COFF_Symbol32 *)symbol_table)[symbol_idx]; + parsed_symbol = coff_parse_symbol32(string_table, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } else { - COFF_Symbol16 *ptr = (COFF_Symbol16 *)coff_symbols + symbol_idx; - parsed_symbol = coff_parse_symbol16(raw_coff, string_table_off, ptr); - aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; + COFF_Symbol16 *ptr = (COFF_Symbol16 *)symbol_table + symbol_idx; + parsed_symbol = coff_parse_symbol16(string_table, ptr); + aux_symbols = parsed_symbol.aux_symbol_count ? ptr+1 : 0; } - if (symbol_idx + parsed_symbol.aux_symbol_count + 1 > coff_symbol_count) { + if (symbol_idx + parsed_symbol.aux_symbol_count + 1 > symbol_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds aux symbol count %llu", parsed_symbol.name, symbol_idx, parsed_symbol.aux_symbol_count); } @@ -882,7 +899,7 @@ lnk_symbol_array_from_coff(Arena *arena, if (parsed_symbol.section_number == 0 || parsed_symbol.section_number > sect_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out ouf bounds section index %x", parsed_symbol.name, symbol_idx, parsed_symbol.section_number); } - if (parsed_symbol.value > coff_sect_arr[parsed_symbol.section_number-1].fsize) { + if (parsed_symbol.value > section_table[parsed_symbol.section_number-1].fsize) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section offset %x into section %x", parsed_symbol.name, symbol_idx, parsed_symbol.value, parsed_symbol.section_number); } @@ -897,13 +914,13 @@ lnk_symbol_array_from_coff(Arena *arena, } - LNK_Chunk *chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + LNK_Chunk *chunk = chunk_table[parsed_symbol.section_number-1]; U64 offset = parsed_symbol.value; COFF_ComdatSelectType selection = COFF_ComdatSelect_Any; U64 check_sum = 0; - B32 is_comdat = (coff_sect_arr[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) && + B32 is_comdat = (section_table[parsed_symbol.section_number-1].flags & COFF_SectionFlag_LnkCOMDAT) && parsed_symbol.value == 0 && parsed_symbol.aux_symbol_count > 0 && parsed_symbol.type.u.lsb == COFF_SymType_Null && @@ -925,8 +942,8 @@ lnk_symbol_array_from_coff(Arena *arena, // associate chunks if (secdef_number > 0 && secdef_number <= sect_count) { - LNK_Chunk *head_chunk = chunk_ptr_arr[secdef_number-1]; - LNK_Chunk *associate_chunk = chunk_ptr_arr[parsed_symbol.section_number-1]; + LNK_Chunk *head_chunk = chunk_table[secdef_number-1]; + LNK_Chunk *associate_chunk = chunk_table[parsed_symbol.section_number-1]; lnk_chunk_associate(head_chunk, associate_chunk); } else { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "symbol %S (No. %llx) has out of bounds section definition number %u", parsed_symbol.name, symbol_idx, secdef_number); @@ -960,7 +977,7 @@ lnk_symbol_array_from_coff(Arena *arena, } COFF_SymbolWeakExt *weak_ext = aux_symbols; - if (weak_ext->tag_index >= coff_symbol_count) { + if (weak_ext->tag_index >= symbol_count) { lnk_error_with_loc(LNK_Error_IllData, obj_path, lib_path, "weak symbol \"%S (%u)\" points to out of bounds symbol", parsed_symbol.name, symbol_idx); } @@ -985,7 +1002,8 @@ lnk_symbol_array_from_coff(Arena *arena, chunk->type = LNK_Chunk_Leaf; chunk->flags = master_common_block->flags; chunk->u.leaf = str8(0, parsed_symbol.value); - lnk_chunk_set_debugf(arena, chunk, "%S: common block %S", obj_path, parsed_symbol.name); + chunk->obj = obj; + lnk_chunk_set_debugf(arena, chunk, "common block %S", parsed_symbol.name); lnk_chunk_list_push(arena, master_common_block->u.list, chunk); LNK_DefinedSymbolFlags flags = 0; @@ -1024,10 +1042,10 @@ lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 c { LNK_RelocList *reloc_list_arr = push_array_no_zero(arena, LNK_RelocList, sect_count); for (U64 sect_idx = 0; sect_idx < sect_count; ++sect_idx) { - COFF_SectionHeader *COFF_FileHeader = &coff_sect_arr[sect_idx]; - COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, COFF_FileHeader); - COFF_Reloc *coff_reloc_v = (COFF_Reloc *)(coff_data.str + coff_reloc_info.array_off); - LNK_Chunk *sect_chunk = chunk_ptr_arr[sect_idx]; + COFF_SectionHeader *coff_sect_header = &coff_sect_arr[sect_idx]; + COFF_RelocInfo coff_reloc_info = coff_reloc_info_from_section_header(coff_data, coff_sect_header); + COFF_Reloc *coff_reloc_v = (COFF_Reloc *)(coff_data.str + coff_reloc_info.array_off); + LNK_Chunk *sect_chunk = chunk_ptr_arr[sect_idx]; reloc_list_arr[sect_idx] = lnk_reloc_list_from_coff_reloc_array(arena, machine, sect_chunk, symbol_array, coff_reloc_v, coff_reloc_info.count); } return reloc_list_arr; diff --git a/src/linker/lnk_obj.h b/src/linker/lnk_obj.h index fa821460..ec07d32e 100644 --- a/src/linker/lnk_obj.h +++ b/src/linker/lnk_obj.h @@ -112,7 +112,7 @@ typedef struct LNK_ObjNode *obj_node_arr; U64 obj_id_base; LNK_SectDefnList *defn_arr; - LNK_SectionTable *st; + LNK_SectionTable *sectab; U64 *function_pad_min; } LNK_ObjIniter; @@ -126,23 +126,22 @@ typedef struct typedef struct { - LNK_SectionTable *st; + LNK_SectionTable *sectab; LNK_ObjNode *obj_arr; - U64 **chunk_count_arr_arr; + U64 **chunk_counts; } LNK_ChunkCounter; typedef struct { LNK_ChunkManager *cman; - U64 **chunk_id_arr_arr; - U64 obj_idx; + U64 *chunk_id; } LNK_ChunkRefAssign; typedef struct { - LNK_SectionTable *st; + LNK_SectionTable *sectab; Rng1U64 *range_arr; - U64 **chunk_id_arr_arr; + U64 **chunk_ids; LNK_ObjNode *obj_arr; LNK_ChunkList **nosort_chunk_list_arr_arr; LNK_ChunkList **chunk_list_arr_arr; @@ -199,10 +198,10 @@ internal LNK_InputObjList lnk_input_obj_list_from_string_list(Arena *arena, Stri internal LNK_Obj ** lnk_obj_arr_from_list(Arena *arena, LNK_ObjList list); internal LNK_ObjNodeArray lnk_obj_list_reserve(Arena *arena, LNK_ObjList *list, U64 count); internal LNK_ChunkList * lnk_collect_obj_chunks(TP_Context *tp, TP_Arena *arena, U64 obj_count, LNK_Obj **obj_arr, String8 name, String8 postfix, B32 collect_discarded); -internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *st, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs); +internal LNK_ObjNodeArray lnk_obj_list_push_parallel(TP_Context *tp, TP_Arena *tp_arena, LNK_ObjList *obj_list, LNK_SectionTable *sectab, U64 *function_pad_min, U64 input_count, LNK_InputObj **inputs); internal LNK_Chunk * lnk_sect_chunk_array_from_coff(Arena *arena, U64 obj_id, String8 obj_path, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, String8 *sect_name_arr, String8 *sect_postfix_arr); -internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, String8 coff_data, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 string_table_off, U64 sect_count, COFF_SectionHeader *coff_sect_arr, U64 coff_symbol_count, void *coff_symbols, LNK_ChunkPtr *chunk_ptr_arr, LNK_Chunk *master_common_block); +internal LNK_SymbolArray lnk_symbol_array_from_coff(Arena *arena, LNK_Obj *obj, String8 obj_path, String8 lib_path, B32 is_big_obj, U64 function_pad_min, U64 sect_count, COFF_SectionHeader *section_table, U64 symbol_count, void *symbol_table, String8 string_table, LNK_ChunkPtr *chunk_table, LNK_Chunk *master_common_block); internal LNK_RelocList lnk_reloc_list_from_coff_reloc_array(Arena *arena, COFF_MachineType machine, LNK_Chunk *chunk, LNK_SymbolArray symbol_array, COFF_Reloc *reloc_v, U64 reloc_count); internal LNK_RelocList * lnk_reloc_list_array_from_coff(Arena *arena, COFF_MachineType machine, String8 coff_data, U64 sect_count, COFF_SectionHeader *coff_sect_arr, LNK_ChunkPtr *chunk_ptr_arr, LNK_SymbolArray symbol_array); internal LNK_DirectiveInfo lnk_directive_info_from_sections(Arena *arena, String8 obj_path, String8 lib_path, U64 chunk_count, LNK_RelocList *reloc_list_arr, String8 *sect_name_arr, LNK_Chunk *chunk_arr); diff --git a/src/linker/lnk_reloc.c b/src/linker/lnk_reloc.c index b37120bd..f78df7e6 100644 --- a/src/linker/lnk_reloc.c +++ b/src/linker/lnk_reloc.c @@ -117,8 +117,8 @@ lnk_ext_reloc_type_from_coff(COFF_MachineType machine, U32 type) { LNK_RelocType result = LNK_Reloc_NULL; switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X64: { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: { switch (type) { case COFF_Reloc_X64_Abs: result = LNK_Reloc_NULL; break; case COFF_Reloc_X64_Addr64: result = LNK_Reloc_ADDR_64; break; @@ -150,7 +150,7 @@ lnk_ext_reloc_type_to_coff(COFF_MachineType machine, LNK_RelocType type) { U32 result = 0; switch (machine) { - case COFF_Machine_X64: { + case COFF_MachineType_X64: { switch (type) { case LNK_Reloc_NULL: result = COFF_Reloc_X64_Abs; break; case LNK_Reloc_ADDR_64: result = COFF_Reloc_X64_Addr64; break; diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 4ac8cb25..4da0b857 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -236,8 +236,8 @@ lnk_code_align_byte_from_machine(COFF_MachineType machine) { U8 align_byte = 0; switch (machine) { - case COFF_Machine_X64: - case COFF_Machine_X86: { + case COFF_MachineType_X64: + case COFF_MachineType_X86: { align_byte = 0xCC; } break; default: { @@ -271,33 +271,33 @@ lnk_section_table_alloc(U64 section_virt_off, U64 sect_align, U64 file_align) { ProfBeginFunction(); Arena *arena = arena_alloc(); - LNK_SectionTable *st = push_array(arena, LNK_SectionTable, 1); - st->arena = arena; - st->section_virt_off = section_virt_off; - st->sect_align = sect_align; - st->file_align = file_align; + LNK_SectionTable *sectab = push_array(arena, LNK_SectionTable, 1); + sectab->arena = arena; + sectab->section_virt_off = section_virt_off; + sectab->sect_align = sect_align; + sectab->file_align = file_align; ProfEnd(); - return st; + return sectab; } internal void lnk_section_table_release(LNK_SectionTable **st_ptr) { ProfBeginFunction(); - LNK_SectionTable *st = *st_ptr; - arena_release(st->arena); + LNK_SectionTable *sectab = *st_ptr; + arena_release(sectab->arena); *st_ptr = NULL; ProfEnd(); } internal LNK_Section * -lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags flags) +lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags) { ProfBeginFunction(); - LNK_SectionList *sect_list = &st->list; + LNK_SectionList *sect_list = §ab->list; - LNK_SectionNode *sect_node = push_array(st->arena, LNK_SectionNode, 1); - String8 sort_index = lnk_make_section_sort_index(st->arena, name, flags, st->id_max); + LNK_SectionNode *sect_node = push_array(sectab->arena, LNK_SectionNode, 1); + String8 sort_index = lnk_make_section_sort_index(sectab->arena, name, flags, sectab->id_max); B32 found = 0; for (LNK_SectionNode *curr = sect_list->first, *prev = NULL; curr != NULL; prev = curr, curr = curr->next) { @@ -320,8 +320,8 @@ lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags fla } sect_list->count += 1; - U64 sect_id = st->id_max; - st->id_max += 1; + U64 sect_id = sectab->id_max; + sectab->id_max += 1; LNK_Section *sect = §_node->data; sect->arena = arena_alloc(); @@ -329,7 +329,7 @@ lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags fla sect->name = push_str8_copy(sect->arena, name); sect->sort_index = sort_index; sect->flags = flags; - sect->cman = lnk_chunk_manager_alloc(sect->arena, sect_id, st->file_align); + sect->cman = lnk_chunk_manager_alloc(sect->arena, sect_id, sectab->file_align); sect->root = sect->cman->root; sect->nosort_chunk = lnk_chunk_push_list(sect->arena, sect->cman, sect->root, str8(0,0)); sect->nosort_chunk->sort_chunk = 0; @@ -338,18 +338,19 @@ lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags fla sect->is_loose = 1; lnk_chunk_set_debugf(sect->arena, sect->root, "root chunk for %S", name); + lnk_chunk_set_debugf(sect->arena, sect->nosort_chunk, "nosort chunk for %S", name); ProfEnd(); return sect; } internal LNK_Section * -lnk_section_table_push_null(LNK_SectionTable *st) +lnk_section_table_push_null(LNK_SectionTable *sectab) { - LNK_SectionList *list = &st->list; - SLLQueuePushFront(list->first, list->last, st->null_sect); + LNK_SectionList *list = §ab->list; + SLLQueuePushFront(list->first, list->last, sectab->null_sect); list->count += 1; - return &st->null_sect->data; + return §ab->null_sect->data; } LNK_CHUNK_VISITOR_SIG(lnk_chunk_has_leaf) @@ -374,12 +375,12 @@ LNK_CHUNK_VISITOR_SIG(lnk_chunk_mark_discarded) } internal void -lnk_section_table_remove(LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 name) +lnk_section_table_remove(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 name) { ProfBeginFunction(); // remove node from list - LNK_SectionNode *sect_node = lnk_section_list_remove(&st->list, name); + LNK_SectionNode *sect_node = lnk_section_list_remove(§ab->list, name); LNK_Section *sect = §_node->data; // remove symbol for section root chunk @@ -389,22 +390,22 @@ lnk_section_table_remove(LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 lnk_visit_chunks(sect->id, sect->root, lnk_chunk_mark_discarded, NULL); // push to empties - SLLQueuePush(st->empties_list.first, st->empties_list.last, sect_node); - st->empties_list.count += 1; + SLLQueuePush(sectab->empties_list.first, sectab->empties_list.last, sect_node); + sectab->empties_list.count += 1; ProfEnd(); } internal LNK_Section * -lnk_section_table_search(LNK_SectionTable *st, String8 name) +lnk_section_table_search(LNK_SectionTable *sectab, String8 name) { - return lnk_section_list_search(&st->list, name); + return lnk_section_list_search(§ab->list, name); } internal LNK_Section * -lnk_section_table_search_id(LNK_SectionTable *st, U64 id) +lnk_section_table_search_id(LNK_SectionTable *sectab, U64 id) { - for (LNK_SectionNode *node = st->list.first; node != NULL; node = node->next) { + for (LNK_SectionNode *node = sectab->list.first; node != NULL; node = node->next) { if (node->data.id == id) { return &node->data; } @@ -413,16 +414,16 @@ lnk_section_table_search_id(LNK_SectionTable *st, U64 id) } internal void -lnk_section_table_merge(LNK_SectionTable *st, LNK_MergeDirectiveList merge_list) +lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_Section **src_dst = push_array(scratch.arena, LNK_Section *, st->id_max); + LNK_Section **src_dst = push_array(scratch.arena, LNK_Section *, sectab->id_max); for (LNK_MergeDirectiveNode *merge_node = merge_list.first; merge_node != NULL; merge_node = merge_node->next) { LNK_MergeDirective *merge = &merge_node->data; // are we trying to merge section that was already merged? - LNK_Section *merge_sect = lnk_section_list_search(&st->merge_list, merge->src); + LNK_Section *merge_sect = lnk_section_list_search(§ab->merge_list, merge->src); if (merge_sect) { LNK_Section *dst = src_dst[merge_sect->id]; B32 is_ambiguous_merge = !str8_match(dst->name, merge->dst, 0); @@ -435,7 +436,7 @@ lnk_section_table_merge(LNK_SectionTable *st, LNK_MergeDirectiveList merge_list) } // find source seciton - LNK_Section *src = lnk_section_table_search(st, merge->src); + LNK_Section *src = lnk_section_table_search(sectab, merge->src); if (src == NULL) { lnk_error(LNK_Warning_IllData, "Can't find section \"%S\" to merge with \"%S\"", merge->src, merge->dst); // TODO: supplement obj path if applicable @@ -443,7 +444,7 @@ lnk_section_table_merge(LNK_SectionTable *st, LNK_MergeDirectiveList merge_list) } // handle case where destination section doesn't exist - LNK_Section *dst = lnk_section_table_search(st, merge->dst); + LNK_Section *dst = lnk_section_table_search(sectab, merge->dst); if (dst == NULL) { src->name = push_str8_copy(src->arena, merge->dst); src_dst[src->id] = src; @@ -457,24 +458,24 @@ lnk_section_table_merge(LNK_SectionTable *st, LNK_MergeDirectiveList merge_list) lnk_section_merge(dst, src); // remove from output section list - LNK_SectionNode *src_node = lnk_section_list_remove(&st->list, src->name); + LNK_SectionNode *src_node = lnk_section_list_remove(§ab->list, src->name); // push section to merged list - SLLQueuePush(st->merge_list.first, st->merge_list.last, src_node); - st->merge_list.count += 1; + SLLQueuePush(sectab->merge_list.first, sectab->merge_list.last, src_node); + sectab->merge_list.count += 1; } scratch_end(scratch); ProfEnd(); } internal void -lnk_section_table_remove_empties(LNK_SectionTable *st, LNK_SymbolTable *symtab) +lnk_section_table_remove_empties(LNK_SectionTable *sectab, LNK_SymbolTable *symtab) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); String8List name_list = {0}; - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; B32 no_data = 1; @@ -487,28 +488,28 @@ lnk_section_table_remove_empties(LNK_SectionTable *st, LNK_SymbolTable *symtab) } for (String8Node *name = name_list.first; name != NULL; name = name->next) { - lnk_section_table_remove(st, symtab, name->string); + lnk_section_table_remove(sectab, symtab, name->string); } scratch_end(scratch); ProfEnd(); } internal LNK_SectionArray -lnk_section_table_get_output_sections(Arena *arena, LNK_SectionTable *st) +lnk_section_table_get_output_sections(Arena *arena, LNK_SectionTable *sectab) { LNK_SectionArray result = {0}; result.count = 0; - result.v = push_array(arena, LNK_Section, st->list.count); + result.v = push_array(arena, LNK_Section, sectab->list.count); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != 0; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != 0; sect_node = sect_node->next) { if (sect_node->data.emit_header && sect_node->data.has_layout) { - Assert(result.count < st->list.count); + Assert(result.count < sectab->list.count); result.v[result.count] = sect_node->data; result.count += 1; } } - U64 unused_entry_count = st->list.count - result.count; + U64 unused_entry_count = sectab->list.count - result.count; arena_pop(arena, unused_entry_count * sizeof(result.v[0])); return result; @@ -525,12 +526,12 @@ THREAD_POOL_TASK_FUNC(lnk_section_data_builder) } internal void -lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *st, COFF_MachineType machine) +lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *sectab, COFF_MachineType machine) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, st->list); + LNK_SectionPtrArray sect_arr = lnk_section_ptr_array_from_list(scratch.arena, sectab->list); LNK_SectionDataBuilder task = {0}; task.machine = machine; @@ -543,32 +544,32 @@ lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *st, COFF_MachineT } internal void -lnk_section_table_assign_virtual_offsets(LNK_SectionTable *st) +lnk_section_table_assign_virtual_offsets(LNK_SectionTable *sectab) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); - U64 cursor = st->section_virt_off; + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); + U64 cursor = sectab->section_virt_off; Assert(cursor >= 0x1000); - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { - if (sect_node == st->null_sect) continue; + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { + if (sect_node == sectab->null_sect) continue; LNK_Section *sect = §_node->data; if (!sect->has_layout) continue; sect->virt_off = cursor; U64 sect_size = lnk_virt_size_from_chunk_ref(sect_id_map, sect->root->ref); cursor += sect_size; - cursor = AlignPow2(cursor, st->sect_align); + cursor = AlignPow2(cursor, sectab->sect_align); } scratch_end(scratch); ProfEnd(); } internal void -lnk_section_table_assign_file_offsets(LNK_SectionTable *st) +lnk_section_table_assign_file_offsets(LNK_SectionTable *sectab) { ProfBeginFunction(); U64 cursor = 0; - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; if (sect->flags & COFF_SectionFlag_CntUninitializedData) { continue; @@ -582,11 +583,11 @@ lnk_section_table_assign_file_offsets(LNK_SectionTable *st) } internal void -lnk_section_table_assign_indices(LNK_SectionTable *st) +lnk_section_table_assign_indices(LNK_SectionTable *sectab) { ProfBeginFunction(); U64 isect = 0; - for (LNK_SectionNode *sect_node = st->list.first; sect_node != NULL; sect_node = sect_node->next) { + for (LNK_SectionNode *sect_node = sectab->list.first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; if (sect->emit_header) { sect->isect = isect++; @@ -596,13 +597,13 @@ lnk_section_table_assign_indices(LNK_SectionTable *st) } internal String8 -lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine) +lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, COFF_MachineType machine) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); U64 image_size = 0; - for (LNK_SectionNode *sect_n = st->list.first; sect_n != 0; sect_n = sect_n->next) { + for (LNK_SectionNode *sect_n = sectab->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]; @@ -614,7 +615,7 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, 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) { + for (LNK_SectionNode *sect_n = sectab->list.first; sect_n != 0; sect_n = sect_n->next) { LNK_Section *sect = §_n->data; if (sect->has_layout) { if (sect->flags & COFF_SectionFlag_CntUninitializedData) { @@ -641,15 +642,15 @@ lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *st, } internal LNK_ChunkPtr ** -lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *st) +lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab) { ProfBeginFunction(); - LNK_ChunkPtr **chunk_id_map = push_array(arena, LNK_ChunkPtr *, st->id_max); - for (LNK_SectionNode *node = st->list.first; node != 0; node = node->next) { + LNK_ChunkPtr **chunk_id_map = push_array(arena, LNK_ChunkPtr *, sectab->id_max); + for (LNK_SectionNode *node = sectab->list.first; node != 0; node = node->next) { LNK_Section *sect = &node->data; chunk_id_map[sect->id] = lnk_make_chunk_id_map(arena, sect->cman); } - if (st->list.first->data.id != 0) { + if (sectab->list.first->data.id != 0) { chunk_id_map[0] = push_array(arena, LNK_ChunkPtr, 1); chunk_id_map[0][0] = g_null_chunk_ptr; } @@ -658,15 +659,15 @@ 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) +lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab) { ProfBeginFunction(); - LNK_Section **map = push_array(arena, LNK_Section *, st->id_max); - LNK_SectionList *list_arr[] = { &st->list, &st->merge_list, &st->empties_list }; + LNK_Section **map = push_array(arena, LNK_Section *, sectab->id_max); + LNK_SectionList *list_arr[] = { §ab->list, §ab->merge_list, §ab->empties_list }; for (U64 list_idx = 0; list_idx < ArrayCount(list_arr); ++list_idx) { for (LNK_SectionNode *sect_node = list_arr[list_idx]->first; sect_node != NULL; sect_node = sect_node->next) { LNK_Section *sect = §_node->data; - Assert(sect->id < st->id_max); + Assert(sect->id < sectab->id_max); Assert(map[sect->id] == NULL); map[sect->id] = sect; } @@ -879,12 +880,12 @@ lnk_file_size_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol) #if LNK_DEBUG_CHUNKS internal void -lnk_dump_chunks(LNK_SectionTable *st) +lnk_dump_chunks(LNK_SectionTable *sectab) { Temp scratch = scratch_begin(0, 0); - LNK_ChunkPtr **chunk_id_map = lnk_chunk_id_map_from_section_table(scratch.arena, st); - LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, st); - for (U64 sect_id = 0; sect_id < st->id_max; ++sect_id) { + LNK_ChunkPtr **chunk_id_map = lnk_chunk_id_map_from_section_table(scratch.arena, sectab); + LNK_Section **sect_id_map = lnk_sect_id_map_from_section_table(scratch.arena, sectab); + for (U64 sect_id = 0; sect_id < sectab->id_max; ++sect_id) { LNK_Section *sect = sect_id_map[sect_id]; if (!sect) continue; if (sect->is_merged) continue; diff --git a/src/linker/lnk_section_table.h b/src/linker/lnk_section_table.h index 4aa6f2c3..770b934b 100644 --- a/src/linker/lnk_section_table.h +++ b/src/linker/lnk_section_table.h @@ -110,21 +110,21 @@ internal LNK_Chunk * lnk_section_push_chunk_list(LNK_Section *sect, LNK_Chunk internal LNK_SectionTable * lnk_section_table_alloc(U64 section_virt_off, U64 sect_align, U64 file_align); internal void lnk_section_table_release(LNK_SectionTable **st_ptr); -internal LNK_Section * lnk_section_table_push(LNK_SectionTable *st, String8 name, COFF_SectionFlags flags); -internal LNK_Section * lnk_section_table_push_null(LNK_SectionTable *st); -internal void lnk_section_table_remove(LNK_SectionTable *st, LNK_SymbolTable *symtab, String8 name); -internal LNK_Section * lnk_section_table_search(LNK_SectionTable *st, String8 name); -internal LNK_Section * lnk_section_table_search_id(LNK_SectionTable *st, U64 id); -internal void lnk_section_table_merge(LNK_SectionTable *st, LNK_MergeDirectiveList merge_list); -internal void lnk_section_table_remove_empties(LNK_SectionTable *st, LNK_SymbolTable *symtab); -internal void lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *st, COFF_MachineType machine); -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(TP_Context *tp, Arena *arena, LNK_SectionTable *st, COFF_MachineType machine); +internal LNK_Section * lnk_section_table_push(LNK_SectionTable *sectab, String8 name, COFF_SectionFlags flags); +internal LNK_Section * lnk_section_table_push_null(LNK_SectionTable *sectab); +internal void lnk_section_table_remove(LNK_SectionTable *sectab, LNK_SymbolTable *symtab, String8 name); +internal LNK_Section * lnk_section_table_search(LNK_SectionTable *sectab, String8 name); +internal LNK_Section * lnk_section_table_search_id(LNK_SectionTable *sectab, U64 id); +internal void lnk_section_table_merge(LNK_SectionTable *sectab, LNK_MergeDirectiveList merge_list); +internal void lnk_section_table_remove_empties(LNK_SectionTable *sectab, LNK_SymbolTable *symtab); +internal void lnk_section_table_build_data(TP_Context *tp, LNK_SectionTable *sectab, COFF_MachineType machine); +internal void lnk_section_table_assign_virtual_offsets(LNK_SectionTable *sectab); +internal void lnk_section_table_assign_file_offsets(LNK_SectionTable *sectab); +internal void lnk_section_table_assign_indices(LNK_SectionTable *sectab); +internal String8 lnk_section_table_serialize(TP_Context *tp, Arena *arena, LNK_SectionTable *sectab, 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); +internal LNK_ChunkPtr ** lnk_chunk_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab); +internal LNK_Section ** lnk_sect_id_map_from_section_table(Arena *arena, LNK_SectionTable *sectab); internal LNK_ChunkRef lnk_get_final_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal LNK_Section * lnk_sect_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkRef chunk_ref); internal LNK_Chunk * lnk_chunk_from_chunk_ref(LNK_Section **sect_id_map, LNK_ChunkPtr **chunk_id_map, LNK_ChunkRef chunk_ref); @@ -146,6 +146,6 @@ internal U64 lnk_virt_size_from_symbol(LNK_Section **sect_id_map, LN internal U64 lnk_file_size_from_symbol(LNK_Section **sect_id_map, LNK_Symbol *symbol); #if LNK_DEBUG_CHUNKS -internal void lnk_dump_chunks(LNK_SectionTable *st); +internal void lnk_dump_chunks(LNK_SectionTable *sectab); #endif diff --git a/src/linker/lnk_symbol_table.c b/src/linker/lnk_symbol_table.c index 127a6f1d..79f6a3fe 100644 --- a/src/linker/lnk_symbol_table.c +++ b/src/linker/lnk_symbol_table.c @@ -221,133 +221,128 @@ lnk_symbol_hash_trie_chunk_list_push(Arena *arena, LNK_SymbolHashTrieChunkList * } internal B32 -lnk_can_replace_symbol(const LNK_Symbol *dst, const LNK_Symbol *src) +lnk_can_replace_symbol(LNK_Symbol *dst, LNK_Symbol *src) { - B32 can_replace = 0; - + Assert(src->type != LNK_Symbol_Undefined); Assert(dst != src); Assert(str8_match(dst->name, src->name, 0)); - Assert(src->type != LNK_Symbol_Undefined); + B32 can_replace = 0; + + // lazy vs lazy if (dst->type == LNK_Symbol_Lazy && src->type == LNK_Symbol_Lazy) { // link.exe picks symbol from lib that is discovered first LNK_Lib *dst_lib = dst->u.lazy.lib; LNK_Lib *src_lib = src->u.lazy.lib; - - //if (dst_lib->input_idx == src_lib->input_idx) { - //Assert(!"TODO: report duplicate symbols in lib"); - //} - can_replace = dst_lib->input_idx > src_lib->input_idx; - } else if (dst->type == LNK_Symbol_Lazy && (LNK_Symbol_IsDefined(src->type) || src->type == LNK_Symbol_Weak)) { + } + // lazy vs weak + else if (dst->type == LNK_Symbol_Lazy && (LNK_Symbol_IsDefined(src->type) || src->type == LNK_Symbol_Weak)) { can_replace = 1; - } else if (dst->type == LNK_Symbol_Weak && LNK_Symbol_IsDefined(src->type)) { - // strong definition found, replace weak symbol + } + // weak vs strong + else if (dst->type == LNK_Symbol_Weak && LNK_Symbol_IsDefined(src->type)) { can_replace = 1; - } else if (dst->type == LNK_Symbol_Weak && src->type == LNK_Symbol_Weak) { + } + // weak vs weak + else if (dst->type == LNK_Symbol_Weak && src->type == LNK_Symbol_Weak) { B32 is_fallback_same = str8_match(dst->u.weak.fallback_symbol->name, src->u.weak.fallback_symbol->name, 0); - if (!is_fallback_same) { + if (is_fallback_same) { + if (src->obj && !dst->obj) { + can_replace = 1; + } else if (src->obj && dst->obj) { + can_replace = src->obj->input_idx < dst->obj->input_idx; + } + } else { lnk_error(LNK_Error_MultiplyDefinedSymbol, "multiply defined weak symbol %S, symbol defined in:", src->name); lnk_supplement_error("%S", dst->obj->path); lnk_supplement_error("%S", src->obj->path); } + } + // defined VA vs defined chunk + else if (LNK_Symbol_IsDefined(dst->type) && dst->u.defined.value_type == LNK_DefinedSymbolValue_VA && + LNK_Symbol_IsDefined(src->type)) { + can_replace = 1; + } + // defined chunk vs defined chunk + else if (LNK_Symbol_IsDefined(dst->type) && dst->u.defined.value_type == LNK_DefinedSymbolValue_Chunk && + LNK_Symbol_IsDefined(src->type) && src->u.defined.value_type == LNK_DefinedSymbolValue_Chunk) { + LNK_DefinedSymbol *dst_defn = &dst->u.defined; + LNK_DefinedSymbol *src_defn = &src->u.defined; - if (src->obj && !dst->obj) { - can_replace = 1; - } else if (src->obj && dst->obj) { - can_replace = src->obj->input_idx < dst->obj->input_idx; + Assert(dst_defn->u.chunk->is_discarded == 0); + Assert(dst_defn->u.chunk->type == LNK_Chunk_Leaf); + Assert(src_defn->u.chunk->type == LNK_Chunk_Leaf); + + COFF_ComdatSelectType dst_select = dst_defn->u.selection; + COFF_ComdatSelectType src_select = src_defn->u.selection; + + // handle objs compiled with /GR- and /GR + if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) || + (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) { + dst_select = COFF_ComdatSelect_Largest; + src_select = COFF_ComdatSelect_Largest; } - } else if (LNK_Symbol_IsDefined(dst->type) && LNK_Symbol_IsDefined(src->type)) { - const LNK_DefinedSymbol *dst_defn = &dst->u.defined; - const LNK_DefinedSymbol *src_defn = &src->u.defined; - if (dst_defn->value_type == LNK_DefinedSymbolValue_Chunk && - src_defn->value_type == LNK_DefinedSymbolValue_Chunk) { - Assert(dst_defn->u.chunk->is_discarded == 0); - Assert(dst_defn->u.chunk->type == LNK_Chunk_Leaf); - Assert(src_defn->u.chunk->type == LNK_Chunk_Leaf); + if (src_select == dst_select) { + LNK_Chunk *dst_chunk = dst_defn->u.chunk; + LNK_Chunk *src_chunk = src_defn->u.chunk; + U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); + U64 src_chunk_size = lnk_chunk_get_size(src_chunk); - COFF_ComdatSelectType dst_select = dst_defn->u.selection; - COFF_ComdatSelectType src_select = src_defn->u.selection; - - // handle objs compiled with /GR- and /GR - if ((src_select == COFF_ComdatSelect_Any && dst_select == COFF_ComdatSelect_Largest) || - (src_select == COFF_ComdatSelect_Largest && dst_select == COFF_ComdatSelect_Any)) { - dst_select = COFF_ComdatSelect_Largest; - src_select = COFF_ComdatSelect_Largest; - } - - if (src_select == dst_select) { - switch (src_select) { - default: InvalidPath; - case COFF_ComdatSelect_Null: - case COFF_ComdatSelect_Any: { - LNK_Chunk *dst_chunk = dst_defn->u.chunk; - LNK_Chunk *src_chunk = src_defn->u.chunk; - U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); - U64 src_chunk_size = lnk_chunk_get_size(src_chunk); - if (src_chunk_size == dst_chunk_size) { - can_replace = src_chunk->input_idx < dst_chunk->input_idx; - } else { - // both COMDATs are valid but to get smaller exe pick smallest - can_replace = src_chunk_size < dst_chunk_size; - } - } break; - case COFF_ComdatSelect_NoDuplicates: { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); - } break; - case COFF_ComdatSelect_SameSize: { - LNK_Chunk *dst_chunk = dst_defn->u.chunk; - LNK_Chunk *src_chunk = src_defn->u.chunk; - U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); - U64 src_chunk_size = lnk_chunk_get_size(src_chunk); - B32 is_same_size = (dst_chunk_size == src_chunk_size); - if (!is_same_size) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); - } - } break; - case COFF_ComdatSelect_ExactMatch: { - B32 is_exact_match = (dst_defn->u.check_sum == src_defn->u.check_sum); - if (!is_exact_match) { - lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); - } - } break; - case COFF_ComdatSelect_Largest: { - LNK_Chunk *dst_chunk = dst_defn->u.chunk; - LNK_Chunk *src_chunk = src_defn->u.chunk; - U64 dst_chunk_size = lnk_chunk_get_size(dst_chunk); - U64 src_chunk_size = lnk_chunk_get_size(src_chunk); - if (dst_chunk_size == src_chunk_size) { - if (dst_defn->u.chunk->u.leaf.str == 0 && src_defn->u.chunk->u.leaf.size > 0) { - // handle communal variable - // - // MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c) - can_replace = 1; - } else { - can_replace = src_chunk->input_idx < dst_chunk->input_idx; - } - } else { - can_replace = dst_chunk_size < src_chunk_size; - } - } break; - case COFF_ComdatSelect_Associative: { - // ignore - } break; + switch (src_select) { + case COFF_ComdatSelect_Null: + case COFF_ComdatSelect_Any: { + if (src_chunk_size == dst_chunk_size) { + can_replace = src_chunk->input_idx < dst_chunk->input_idx; + } else { + // both COMDATs are valid but to get smaller exe pick smallest + can_replace = src_chunk_size < dst_chunk_size; } - } else { - String8 src_select_str = coff_string_from_comdat_select_type(src_defn->u.selection); - String8 dst_select_str = coff_string_from_comdat_select_type(dst_defn->u.selection); - lnk_error_obj(LNK_Warning_UnresolvedComdat, src->obj, - "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", - src->name, src_select_str, dst_select_str, dst->obj->path); + } break; + case COFF_ComdatSelect_NoDuplicates: { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } break; + case COFF_ComdatSelect_SameSize: { + if (dst_chunk_size != src_chunk_size) { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } + } break; + case COFF_ComdatSelect_ExactMatch: { + if (dst_defn->u.check_sum != src_defn->u.check_sum) { + lnk_error_obj(LNK_Error_MultiplyDefinedSymbol, src->obj, "multiply defined symbol %S in %S.", dst->name, dst->obj->path); + } + } break; + case COFF_ComdatSelect_Largest: { + if (dst_chunk_size == src_chunk_size) { + if (dst_defn->u.chunk->u.leaf.str == 0 && src_defn->u.chunk->u.leaf.size > 0) { + // handle communal variable + // + // MSVC CRT relies on this behaviour (e.g. __scrt_ucrt_dll_is_in_use in ucrt_detection.c) + can_replace = 1; + } else { + can_replace = src_chunk->input_idx < dst_chunk->input_idx; + } + } else { + can_replace = dst_chunk_size < src_chunk_size; + } + } break; + case COFF_ComdatSelect_Associative: { + // ignore + } break; + default: { + lnk_error_obj(LNK_Error_InvalidPath, src->obj, "unknown COMDAT selection %#x", src->obj, src_select); + } break; } - } else if (dst_defn->value_type == LNK_DefinedSymbolValue_VA && src_defn->value_type == LNK_DefinedSymbolValue_Chunk) { - can_replace = 1; } else { - InvalidPath; + String8 src_select_str = coff_string_from_comdat_select_type(src_defn->u.selection); + String8 dst_select_str = coff_string_from_comdat_select_type(dst_defn->u.selection); + lnk_error_obj(LNK_Warning_UnresolvedComdat, src->obj, + "%S: COMDAT selection conflict detected, current selection %S, leader selection %S from %S", + src->name, src_select_str, dst_select_str, dst->obj->path); } } else { - InvalidPath; + lnk_error(LNK_Error_InvalidPath, "unable to find a suitable replacement logic for symbol combination"); } return can_replace; @@ -388,19 +383,22 @@ lnk_on_symbol_replace(LNK_Symbol *dst, LNK_Symbol *src) } internal void -lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_symbol) +lnk_symbol_hash_trie_insert_or_replace(Arena *arena, + LNK_SymbolHashTrieChunkList *chunks, + LNK_SymbolHashTrie **trie, + U64 hash, + LNK_Symbol *symbol) { LNK_SymbolHashTrie **curr_trie_ptr = trie; - for (U64 h = hash; ; h <<= 2) { // load current pointer LNK_SymbolHashTrie *curr_trie = ins_atomic_ptr_eval(curr_trie_ptr); if (curr_trie == 0) { // init node - LNK_SymbolHashTrie *new_trie = lnk_symbol_hash_trie_chunk_list_push(arena, chunk_list, 512); - new_trie->name = &new_symbol->name; - new_trie->symbol = new_symbol; + LNK_SymbolHashTrie *new_trie = lnk_symbol_hash_trie_chunk_list_push(arena, chunks, 512); + new_trie->name = &symbol->name; + new_trie->symbol = symbol; MemoryZeroArray(new_trie->child); // try to insert new node @@ -412,7 +410,7 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList } // rollback chunk list push - chunk_list->last->count -= 1; + --chunks->last->count; // retry insert with trie node from another thread curr_trie = cmp; @@ -421,39 +419,38 @@ lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList // load current symbol String8 *curr_name = ins_atomic_ptr_eval(&curr_trie->name); - if (curr_name) { - if (str8_match(*curr_name, new_symbol->name, 0)) { - for (LNK_Symbol *src = new_symbol, *dst;;) { - LNK_Symbol *dst = ins_atomic_ptr_eval_assign(&curr_trie->symbol, 0); + if (curr_name && str8_match(*curr_name, symbol->name, 0)) { + for (LNK_Symbol *src = symbol;;) { + // try replacing current symbol with zero, otherwise loop back and retry + LNK_Symbol *dst = ins_atomic_ptr_eval_assign(&curr_trie->symbol, 0); - if (dst) { - if (lnk_can_replace_symbol(dst, src)) { - // HACK: patch dst because relocations might point to it - lnk_on_symbol_replace(dst, src); - - // swap - dst = src; - } else { - // discard source - lnk_on_symbol_replace(src, dst); - } - } - - // try insert back symbol - dst = ins_atomic_ptr_eval_cond_assign(&curr_trie->symbol, src, 0); - - if (dst == 0) { - break; + // apply replacement logic + LNK_Symbol *current_symbol = dst; + if (dst) { + if (lnk_can_replace_symbol(dst, src)) { + // HACK: patch dst because relocations might point to it + lnk_on_symbol_replace(dst, src); + current_symbol = src; + } else { + // discard source + lnk_on_symbol_replace(src, dst); } } - break; + // try replacing symbol, if another thread has already taken the slot, rerun the whole loop + dst = ins_atomic_ptr_eval_cond_assign(&curr_trie->symbol, current_symbol, 0); + + // symbol replaced, exit + if (dst == 0) { + goto exit; + } } } - // descend + // pick child and descend curr_trie_ptr = curr_trie->child + (h >> 62); } + exit:; } internal LNK_SymbolHashTrie * diff --git a/src/linker/lnk_symbol_table.h b/src/linker/lnk_symbol_table.h index 3426a17a..29326d6d 100644 --- a/src/linker/lnk_symbol_table.h +++ b/src/linker/lnk_symbol_table.h @@ -201,7 +201,7 @@ internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_Symbol //////////////////////////////// -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 void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunks, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *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); diff --git a/src/linker/path_ext/path.c b/src/linker/path_ext/path.c deleted file mode 100644 index 8b50bfb4..00000000 --- a/src/linker/path_ext/path.c +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -internal String8 -make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext) -{ - String8 file_name_no_ext = str8_chop_last_dot(file_name); - String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext); - return result; -} - -internal String8 -path_char_from_style(PathStyle style) -{ - String8 result = str8_zero(); - switch (style) { - case PathStyle_Null: break; - case PathStyle_Relative: break; - case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break; - case PathStyle_UnixAbsolute: result = str8_lit("/"); break; - } - return result; -} - -internal String8 -path_convert_slashes(Arena *arena, String8 path, PathStyle path_style) -{ - Temp scratch = scratch_begin(&arena, 1); - String8List list = str8_split_path(scratch.arena, path); - StringJoin join = {0}; - join.sep = path_char_from_style(path_style); - String8 result = str8_list_join(arena, &list, &join); - scratch_end(scratch); - return result; -} - -internal String8 -path_canon_from_regular_path(Arena *arena, String8 path) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 result; - result = lower_from_str8(scratch.arena, path); - result = path_convert_slashes(arena, result, PathStyle_UnixAbsolute); - scratch_end(scratch); - return result; -} - -struct { - String8 string; - PathStyle path_style; -} g_path_style_map[] = { - { str8_lit_comp("windows"), PathStyle_WindowsAbsolute }, - { str8_lit_comp("unix"), PathStyle_UnixAbsolute }, - { str8_lit_comp("system"), PathStyle_SystemAbsolute }, -}; - -internal PathStyle -path_style_from_string(String8 string) -{ - for (U64 i = 0; i < ArrayCount(g_path_style_map); ++i) { - if (str8_match(g_path_style_map[i].string, string, StringMatchFlag_CaseInsensitive)) { - return g_path_style_map[i].path_style; - } - } - return PathStyle_Null; -} - diff --git a/src/linker/path_ext/path.h b/src/linker/path_ext/path.h deleted file mode 100644 index ae3e4bb9..00000000 --- a/src/linker/path_ext/path.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#pragma once - -internal String8 make_file_name_with_ext(Arena *arena, String8 file_name, String8 ext); -internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style); -internal String8 path_canon_from_regular_path(Arena *arena, String8 path); -internal PathStyle path_style_from_string(String8 string); - diff --git a/src/linker/pdb_ext/msf_builder.c b/src/linker/pdb_ext/msf_builder.c index 9905147f..5ae0036d 100644 --- a/src/linker/pdb_ext/msf_builder.c +++ b/src/linker/pdb_ext/msf_builder.c @@ -798,7 +798,7 @@ msf_stream_alloc_(Arena *arena, MSF_StreamList *list) internal MSF_StreamNumber msf_stream_alloc_ex(MSF_Context *msf, MSF_UInt size) { - MSF_StreamNode *node = msf_stream_alloc_(msf->arena, &msf->st); + MSF_StreamNode *node = msf_stream_alloc_(msf->arena, &msf->sectab); MSF_Stream *stream = &node->data; msf_stream_resize_ex(msf, stream, size); return stream->sn; @@ -854,7 +854,7 @@ msf_stream_free(MSF_Context *msf, MSF_StreamNumber sn) B32 is_free_ok = 0; MSF_StreamNode *stream_node = msf_find_stream_node(msf, sn); if (stream_node) { - msf_stream_list_remove(&msf->st, stream_node); + msf_stream_list_remove(&msf->sectab, stream_node); msf_stream_resize_ex(msf, &stream_node->data, 0); stream_node->data.size = MSF_DELETED_STREAM_STAMP; is_free_ok = 1; @@ -1382,7 +1382,7 @@ internal MSF_StreamNode * msf_find_stream_node(MSF_Context *msf, MSF_StreamNumber sn) { MSF_StreamNode *node; - for (node = msf->st.first; node != 0; node = node->next) { + for (node = msf->sectab.first; node != 0; node = node->next) { if (node->data.sn == sn) { break; } @@ -1645,7 +1645,7 @@ msf_open(String8 data, MSF_Context **msf_out) msf->header_page_list = header_page_list; msf->root_page_list = root_page_list; msf->st_page_list = st_page_list; - msf->st = stream_list; + msf->sectab = stream_list; *msf_out = msf; @@ -1678,19 +1678,19 @@ msf_release(MSF_Context **msf_ptr) } internal String8List -msf_build_stream_table_data(Arena *arena, MSF_StreamList *st, MSF_UInt page_size, MSF_UInt page_count) +msf_build_stream_table_data(Arena *arena, MSF_StreamList *sectab, MSF_UInt page_size, MSF_UInt page_count) { ProfBeginFunction(); MSF_UInt *stream_count_ptr = push_array(arena, MSF_UInt, 1); - *stream_count_ptr = st->count; + *stream_count_ptr = sectab->count; - MSF_UInt *stream_size_arr = push_array(arena, MSF_UInt, st->count); + MSF_UInt *stream_size_arr = push_array(arena, MSF_UInt, sectab->count); MSF_UInt stream_page_count = 0; MSF_PageNumber *stream_pages_arr = push_array(arena, MSF_PageNumber, page_count); - for (MSF_StreamNode *stream_node = st->first; stream_node != 0; stream_node = stream_node->next) { + for (MSF_StreamNode *stream_node = sectab->first; stream_node != 0; stream_node = stream_node->next) { MSF_Stream *stream = &stream_node->data; // is page list correct? @@ -1747,7 +1747,7 @@ msf_build_stream_table(MSF_Context *msf, MSF_UInt *stream_table_size_out) MSF_Error error = MSF_Error_OK; - String8List st_data_list = msf_build_stream_table_data(scratch.arena, &msf->st, msf->page_size, msf->page_count); + String8List st_data_list = msf_build_stream_table_data(scratch.arena, &msf->sectab, msf->page_size, msf->page_count); MSF_UInt st_page_count = msf_count_pages(msf->page_size, st_data_list.total_size); msf_free_pages(msf, &msf->st_page_list); // TODO: page reuse diff --git a/src/linker/pdb_ext/msf_builder.h b/src/linker/pdb_ext/msf_builder.h index 40aba132..c9bda071 100644 --- a/src/linker/pdb_ext/msf_builder.h +++ b/src/linker/pdb_ext/msf_builder.h @@ -82,7 +82,7 @@ typedef struct MSF_Context MSF_PageList root_page_list; MSF_PageList st_page_list; MSF_PageList page_pool; - MSF_StreamList st; + MSF_StreamList sectab; } MSF_Context; typedef enum MSF_Error diff --git a/src/linker/rdi/rdi_coff.c b/src/linker/rdi/rdi_coff.c index 32b93862..2646860c 100644 --- a/src/linker/rdi/rdi_coff.c +++ b/src/linker/rdi/rdi_coff.c @@ -5,31 +5,31 @@ internal RDI_Arch rdi_arch_from_coff_machine(COFF_MachineType machine) { switch (machine) { - case COFF_Machine_X86: return RDI_Arch_X86; - case COFF_Machine_X64: return RDI_Arch_X64; + case COFF_MachineType_X86: return RDI_Arch_X86; + case COFF_MachineType_X64: return RDI_Arch_X64; - case COFF_Machine_Unknown: - case COFF_Machine_Am33: - case COFF_Machine_Arm: - case COFF_Machine_Arm64: - case COFF_Machine_ArmNt: - case COFF_Machine_Ebc: - case COFF_Machine_Ia64: - case COFF_Machine_M32R: - case COFF_Machine_Mips16: - case COFF_Machine_MipsFpu: - case COFF_Machine_MipsFpu16: - case COFF_Machine_PowerPc: - case COFF_Machine_PowerPcFp: - case COFF_Machine_R4000: - case COFF_Machine_RiscV32: - case COFF_Machine_RiscV64: - case COFF_Machine_Sh3: - case COFF_Machine_Sh3Dsp: - case COFF_Machine_Sh4: - case COFF_Machine_Sh5: - case COFF_Machine_Thumb: - case COFF_Machine_WceMipsV2: + case COFF_MachineType_Unknown: + case COFF_MachineType_Am33: + case COFF_MachineType_Arm: + case COFF_MachineType_Arm64: + case COFF_MachineType_ArmNt: + case COFF_MachineType_Ebc: + case COFF_MachineType_Ia64: + case COFF_MachineType_M32R: + case COFF_MachineType_Mips16: + case COFF_MachineType_MipsFpu: + case COFF_MachineType_MipsFpu16: + case COFF_MachineType_PowerPc: + case COFF_MachineType_PowerPcFp: + case COFF_MachineType_R4000: + case COFF_MachineType_RiscV32: + case COFF_MachineType_RiscV64: + case COFF_MachineType_Sh3: + case COFF_MachineType_Sh3Dsp: + case COFF_MachineType_Sh4: + case COFF_MachineType_Sh5: + case COFF_MachineType_Thumb: + case COFF_MachineType_WceMipsV2: NotImplemented; default: return RDI_Arch_NULL; diff --git a/src/mdesk/mdesk.c b/src/mdesk/mdesk.c index 92c9bcff..1b6e2f51 100644 --- a/src/mdesk/mdesk.c +++ b/src/mdesk/mdesk.c @@ -968,7 +968,10 @@ if(work_top == 0) {work_top = &broken_work;}\ String8 tag_name = md_content_string_from_token_flags_str8(token[1].flags, tag_name_raw); MD_Node *node = md_push_node(arena, MD_NodeKind_Tag, md_node_flags_from_token_flags(token[1].flags), tag_name, tag_name_raw, token[0].range.min); DLLPushBack_NPZ(&md_nil_node, work_top->first_gathered_tag, work_top->last_gathered_tag, node, next, prev); - if(token+2 < tokens_opl && token[2].flags & MD_TokenFlag_Reserved && str8_match(str8_substr(text, token[2].range), str8_lit("("), 0)) + if(token+2 < tokens_opl && token[2].flags & MD_TokenFlag_Reserved && + (str8_match(str8_substr(text, token[2].range), str8_lit("("), 0) || + str8_match(str8_substr(text, token[2].range), str8_lit("["), 0) || + str8_match(str8_substr(text, token[2].range), str8_lit("{"), 0))) { token += 3; MD_ParseWorkPush(MD_ParseWorkKind_Main, node); @@ -1052,10 +1055,13 @@ if(work_top == 0) {work_top = &broken_work;}\ goto end_consume; } - //- rjf: [main_implicit] newline -> pop + //- rjf: [main_implicit] newline -> pop *all* current implicit work tasks if(work_top->kind == MD_ParseWorkKind_MainImplicit && token->flags & MD_TokenFlag_Newline) { - MD_ParseWorkPop(); + for(;work_top->kind == MD_ParseWorkKind_MainImplicit;) + { + MD_ParseWorkPop(); + } token += 1; goto end_consume; } @@ -1198,3 +1204,25 @@ md_debug_string_list_from_tree(Arena *arena, MD_Node *root) } return strings; } + +//////////////////////////////// +//~ rjf: Node Pointer List Functions + +internal void +md_node_ptr_list_push(Arena *arena, MD_NodePtrList *list, MD_Node *node) +{ + MD_NodePtrNode *n = push_array(arena, MD_NodePtrNode, 1); + n->v = node; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal void +md_node_ptr_list_push_front(Arena *arena, MD_NodePtrList *list, MD_Node *node) +{ + MD_NodePtrNode *n = push_array(arena, MD_NodePtrNode, 1); + n->v = node; + SLLQueuePushFront(list->first, list->last, n); + list->count += 1; +} + diff --git a/src/mdesk/mdesk.h b/src/mdesk/mdesk.h index afe6fc32..455cb268 100644 --- a/src/mdesk/mdesk.h +++ b/src/mdesk/mdesk.h @@ -202,6 +202,21 @@ struct MD_NodeRec S32 pop_count; }; +typedef struct MD_NodePtrNode MD_NodePtrNode; +struct MD_NodePtrNode +{ + MD_NodePtrNode *next; + MD_Node *v; +}; + +typedef struct MD_NodePtrList MD_NodePtrList; +struct MD_NodePtrList +{ + MD_NodePtrNode *first; + MD_NodePtrNode *last; + U64 count; +}; + //////////////////////////////// //~ rjf: Text -> Tokens Types @@ -322,4 +337,10 @@ internal MD_ParseResult md_parse_from_text(Arena *arena, String8 filename, Strin internal String8List md_debug_string_list_from_tree(Arena *arena, MD_Node *root); +//////////////////////////////// +//~ rjf: Node Pointer List Functions + +internal void md_node_ptr_list_push(Arena *arena, MD_NodePtrList *list, MD_Node *node); +internal void md_node_ptr_list_push_front(Arena *arena, MD_NodePtrList *list, MD_Node *node); + #endif // MDESK_H diff --git a/src/metagen/metagen.c b/src/metagen/metagen.c index 4d68bf5a..33c4daa7 100644 --- a/src/metagen/metagen.c +++ b/src/metagen/metagen.c @@ -686,8 +686,8 @@ mg_string_from_row_desc_idx(MD_Node *row_parent, MG_ColumnDescArray descs, U64 i cell_idx -= 1; } } - MD_Node *node = md_child_from_index(row_parent, cell_idx); - result = node->string; + MD_Node *node = md_child_from_index(row_parent, cell_idx); + result = node->string; }break; case MG_ColumnKind_CheckForTag: @@ -828,8 +828,8 @@ mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpand }break; case MG_StrExprOp_Null: - { - str8_list_push(arena, out, expr->node->string); + { + str8_list_push(arena, out, expr->node->string); }break; case MG_StrExprOp_Dot: @@ -900,7 +900,14 @@ mg_eval_table_expand_expr__string(Arena *arena, MG_StrExpr *expr, MG_TableExpand } // rjf: push lookup string - { + { + B32 is_multiline = (str8_find_needle(lookup_string, 0, str8_lit("\n"), 0) < lookup_string.size); + if(is_multiline) + { + lookup_string = indented_from_string(mg_arena, lookup_string); + lookup_string = escaped_from_raw_str8(mg_arena, lookup_string); + lookup_string = escaped_from_raw_str8(mg_arena, lookup_string); + } str8_list_push(arena, out, lookup_string); } }break; @@ -1010,9 +1017,10 @@ mg_loop_table_column_expansion(Arena *arena, String8 strexpr, MG_TableExpandInfo char_idx += 1; } } - String8 expansion_str = str8_list_join(arena, &expansion_strs, 0); + String8 expansion_str = str8_list_join(arena, &expansion_strs, 0); if(expansion_str.size != 0) - { + { + expansion_str = raw_from_escaped_str8(mg_arena, expansion_str); str8_list_push(arena, out, expansion_str); } } @@ -1028,7 +1036,7 @@ mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_co Temp scratch = scratch_begin(&arena, 1); if(md_node_is_nil(gen->first) && gen->string.size != 0) { - str8_list_push(arena, &result, gen->string); + str8_list_push(arena, &result, raw_from_escaped_str8(arena, gen->string)); str8_list_push(arena, &result, str8_lit("\n")); } else for MD_EachNode(strexpr_node, gen->first) @@ -1080,7 +1088,7 @@ mg_string_list_from_table_gen(Arena *arena, MG_Map grid_name_map, MG_Map grid_co } else { - str8_list_push(arena, &result, strexpr_node->string); + str8_list_push(arena, &result, raw_from_escaped_str8(arena, strexpr_node->string)); } } } diff --git a/src/metagen/metagen_base/metagen_base_arena.c b/src/metagen/metagen_base/metagen_base_arena.c index 28eb6e83..68ad2544 100644 --- a/src/metagen/metagen_base/metagen_base_arena.c +++ b/src/metagen/metagen_base/metagen_base_arena.c @@ -52,12 +52,16 @@ 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; arena->cmt = commit_size; arena->res = reserve_size; +#if ARENA_FREE_LIST + arena->free_size = 0; + arena->free_last = 0; +#endif AsanPoisonMemoryRegion(base, commit_size); AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE); return arena; @@ -85,30 +89,67 @@ arena_push(Arena *arena, U64 size, U64 align) // rjf: chain, if needed if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain)) { - U64 res_size = current->res_size; - U64 cmt_size = current->cmt_size; - if(size + ARENA_HEADER_SIZE > res_size) + 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) { - res_size = size + ARENA_HEADER_SIZE; - cmt_size = size + ARENA_HEADER_SIZE; + if(new_block->res >= AlignPow2(size, align)) + { + if(prev_block) + { + prev_block->prev = new_block->prev; + } + else + { + 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); + break; + } } - Arena *new_block = arena_alloc(.reserve_size = res_size, - .commit_size = cmt_size, - .flags = current->flags); +#endif + + if(new_block == 0) + { + U64 res_size = current->res_size; + U64 cmt_size = current->cmt_size; + if(size + ARENA_HEADER_SIZE > res_size) + { + res_size = AlignPow2(size + ARENA_HEADER_SIZE, align); + cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, 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); + current = new_block; pos_pre = AlignPow2(current->pos, align); pos_pst = pos_pre + size; } // rjf: commit new pages, if needed - if(current->cmt < pos_pst && !(current->flags & ArenaFlag_LargePages)) + if(current->cmt < pos_pst) { - U64 cmt_pst_aligned = AlignPow2(pos_pst, current->cmt_size); + U64 cmt_pst_aligned = pos_pst + current->cmt_size-1; + cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size; U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res); U64 cmt_size = cmt_pst_clamped - current->cmt; - os_commit((U8 *)current + current->cmt, cmt_size); + U8 *cmt_ptr = (U8 *)current + current->cmt; + if(current->flags & ArenaFlag_LargePages) + { + os_commit_large(cmt_ptr, cmt_size); + } + else + { + os_commit(cmt_ptr, cmt_size); + } current->cmt = cmt_pst_clamped; } @@ -146,11 +187,23 @@ 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) + { + prev = current->prev; + current->pos = ARENA_HEADER_SIZE; + arena->free_size += current->res_size; + SLLStackPush_N(arena->free_last, current, prev); + AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res_size - ARENA_HEADER_SIZE); + } +#else for(Arena *prev = 0; current->base_pos >= big_pos; current = prev) { prev = current->prev; os_release(current, current->res); } +#endif arena->current = current; U64 new_pos = big_pos - current->base_pos; AssertAlways(new_pos <= current->pos); diff --git a/src/metagen/metagen_base/metagen_base_arena.h b/src/metagen/metagen_base/metagen_base_arena.h index f941bcd7..8696f49f 100644 --- a/src/metagen/metagen_base/metagen_base_arena.h +++ b/src/metagen/metagen_base/metagen_base_arena.h @@ -7,12 +7,12 @@ //////////////////////////////// //~ rjf: Constants -#define ARENA_HEADER_SIZE 64 +#define ARENA_HEADER_SIZE 128 //////////////////////////////// //~ rjf: Types -typedef U32 ArenaFlags; +typedef U64 ArenaFlags; enum { ArenaFlag_NoChain = (1<<0), @@ -34,12 +34,16 @@ 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; U64 cmt; U64 res; +#if ARENA_FREE_LIST + U64 free_size; + Arena *free_last; +#endif }; StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check); @@ -50,12 +54,19 @@ struct Temp U64 pos; }; +//////////////////////////////// +//~ rjf: Global Defaults + +global U64 arena_default_reserve_size = MB(64); +global U64 arena_default_commit_size = KB(64); +global ArenaFlags arena_default_flags = 0; + //////////////////////////////// //~ rjf: Arena Functions //- rjf: arena creation/destruction internal Arena *arena_alloc_(ArenaParams *params); -#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = MB(64), .commit_size = KB(64), __VA_ARGS__}) +#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, __VA_ARGS__}) internal void arena_release(Arena *arena); //- rjf: arena push/pop/pos core functions diff --git a/src/metagen/metagen_base/metagen_base_command_line.c b/src/metagen/metagen_base/metagen_base_command_line.c index ecf23745..ec726752 100644 --- a/src/metagen/metagen_base/metagen_base_command_line.c +++ b/src/metagen/metagen_base/metagen_base_command_line.c @@ -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; } diff --git a/src/metagen/metagen_base/metagen_base_command_line.h b/src/metagen/metagen_base/metagen_base_command_line.h index c37f91dc..acd7f17b 100644 --- a/src/metagen/metagen_base/metagen_base_command_line.h +++ b/src/metagen/metagen_base/metagen_base_command_line.h @@ -34,6 +34,8 @@ struct CmdLine String8List inputs; U64 option_table_size; CmdLineOpt **option_table; + U64 argc; + char **argv; }; //////////////////////////////// diff --git a/src/metagen/metagen_base/metagen_base_context_cracking.h b/src/metagen/metagen_base/metagen_base_context_cracking.h index 040c0004..bac701dd 100644 --- a/src/metagen/metagen_base/metagen_base_context_cracking.h +++ b/src/metagen/metagen_base/metagen_base_context_cracking.h @@ -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) @@ -183,7 +183,7 @@ #endif #if !defined(BUILD_ISSUES_LINK_STRING_LITERAL) -# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/raddebugger/issues" +# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGamesExt/raddebugger/issues" #endif #define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND diff --git a/src/metagen/metagen_base/metagen_base_core.c b/src/metagen/metagen_base/metagen_base_core.c index 877dcb4e..b392e4a0 100644 --- a/src/metagen/metagen_base/metagen_base_core.c +++ b/src/metagen/metagen_base/metagen_base_core.c @@ -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 @@ -399,23 +387,23 @@ txt_rng_contains(TxtRng r, TxtPt pt) //~ rjf: Toolchain/Environment Enum Functions internal U64 -bit_size_from_arch(Architecture arch) +bit_size_from_arch(Arch arch) { // TODO(rjf): metacode U64 arch_bitsize = 0; switch(arch) { - case Architecture_x64: arch_bitsize = 64; break; - case Architecture_x86: arch_bitsize = 32; break; - case Architecture_arm64: arch_bitsize = 64; break; - case Architecture_arm32: arch_bitsize = 32; break; + case Arch_x64: arch_bitsize = 64; break; + case Arch_x86: arch_bitsize = 32; break; + case Arch_arm64: arch_bitsize = 64; break; + case Arch_arm32: arch_bitsize = 32; break; default: break; } return arch_bitsize; } internal U64 -max_instruction_size_from_arch(Architecture arch) +max_instruction_size_from_arch(Arch arch) { // TODO(rjf): make this real return 64; @@ -434,17 +422,17 @@ operating_system_from_context(void){ return os; } -internal Architecture -architecture_from_context(void){ - Architecture arch = Architecture_Null; +internal Arch +arch_from_context(void){ + Arch arch = Arch_Null; #if ARCH_X64 - arch = Architecture_x64; + arch = Arch_x64; #elif ARCH_X86 - arch = Architecture_x86; + arch = Arch_x86; #elif ARCH_ARM64 - arch = Architecture_arm64; + arch = Arch_arm64; #elif ARCH_ARM32 - arch = Architecture_arm32; + arch = Arch_arm32; #endif return arch; } @@ -526,6 +514,60 @@ date_time_from_micro_seconds(U64 time){ return(result); } +internal DateTime +date_time_from_unix_time(U64 unix_time) +{ + DateTime date = {0}; + date.year = 1970; + date.day = 1 + (unix_time / 86400); + date.sec = (U32)unix_time % 60; + date.min = (U32)(unix_time / 60) % 60; + date.hour = (U32)(unix_time / 3600) % 24; + + for(;;) + { + for(date.month = 0; date.month < 12; ++date.month) + { + U64 c = 0; + switch(date.month) + { + case Month_Jan: c = 31; break; + case Month_Feb: + { + if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0)) + { + c = 29; + } + else + { + c = 28; + } + } break; + case Month_Mar: c = 31; break; + case Month_Apr: c = 30; break; + case Month_May: c = 31; break; + case Month_Jun: c = 30; break; + case Month_Jul: c = 31; break; + case Month_Aug: c = 31; break; + case Month_Sep: c = 30; break; + case Month_Oct: c = 31; break; + case Month_Nov: c = 30; break; + case Month_Dec: c = 31; break; + default: InvalidPath; + } + if(date.day <= c) + { + goto exit; + } + date.day -= c; + } + ++date.year; + } + exit:; + + return date; +} + //////////////////////////////// //~ rjf: Non-Fancy Ring Buffer Reads/Writes diff --git a/src/metagen/metagen_base/metagen_base_core.h b/src/metagen/metagen_base/metagen_base_core.h index b2483870..191e1e7f 100644 --- a/src/metagen/metagen_base/metagen_base_core.h +++ b/src/metagen/metagen_base/metagen_base_core.h @@ -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 @@ -118,8 +124,10 @@ #define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end)) #define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) -#define EachEnumVal(type, it) type it = (type)0; it < type##_COUNT; it = (type)(it+1) -#define EachNonZeroEnumVal(type, it) type it = (type)1; it < type##_COUNT; it = (type)(it+1) +#define EachIndex(it, count) (U64 it = 0; it < (count); it += 1) +#define EachElement(it, array) (U64 it = 0; it < ArrayCount(array); it += 1) +#define EachEnumVal(type, it) (type it = (type)0; it < type##_COUNT; it = (type)(it+1)) +#define EachNonZeroEnumVal(type, it) (type it = (type)1; it < type##_COUNT; it = (type)(it+1)) //////////////////////////////// //~ rjf: Memory Operation Macros @@ -170,33 +178,49 @@ //////////////////////////////// //~ rjf: Atomic Operations -#if OS_WINDOWS -# include -# include -# include +#if COMPILER_MSVC # include # 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_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1) -# 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 //////////////////////////////// @@ -430,16 +454,25 @@ typedef enum OperatingSystem } OperatingSystem; -typedef enum Architecture +typedef enum ImageType { - Architecture_Null, - Architecture_x64, - Architecture_x86, - Architecture_arm64, - Architecture_arm32, - Architecture_COUNT, + Image_Null, + Image_CoffPe, + Image_Elf32, + Image_Elf64, + Image_Macho +} ImageType; + +typedef enum Arch +{ + Arch_Null, + Arch_x64, + Arch_x86, + Arch_arm64, + Arch_arm32, + Arch_COUNT, } -Architecture; +Arch; typedef enum Compiler { @@ -468,6 +501,51 @@ 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); + +//////////////////////////////// +//~ Arrays + +typedef struct U16Array U16Array; +struct U16Array +{ + U64 count; + U16 *v; +}; +typedef struct U32Array U32Array; +struct U32Array +{ + U64 count; + U32 *v; +}; +typedef struct U64Array U64Array; +struct U64Array +{ + U64 count; + U64 *v; +}; +typedef struct U128Array U128Array; +struct U128Array +{ + U64 count; + U128 *v; +}; + //////////////////////////////// //~ NOTE(allen): Constants @@ -734,7 +812,16 @@ 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); +#if ARCH_LITTLE_ENDIAN +# define from_be_u16(x) bswap_u16(x) +# define from_be_u32(x) bswap_u32(x) +# define from_be_u64(x) bswap_u64(x) +#else +# define from_be_u16(x) (x) +# define from_be_u32(x) (x) +# define from_be_u64(x) (x) +#endif + internal U64 count_bits_set32(U32 val); internal U64 count_bits_set64(U64 val); @@ -770,19 +857,20 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt); //////////////////////////////// //~ rjf: Toolchain/Environment Enum Functions -internal U64 bit_size_from_arch(Architecture arch); -internal U64 max_instruction_size_from_arch(Architecture arch); +internal U64 bit_size_from_arch(Arch arch); +internal U64 max_instruction_size_from_arch(Arch arch); internal OperatingSystem operating_system_from_context(void); -internal Architecture architecture_from_context(void); +internal Arch arch_from_context(void); internal Compiler compiler_from_context(void); //////////////////////////////// //~ rjf: Time Functions internal DenseTime dense_time_from_date_time(DateTime date_time); -internal DateTime date_time_from_dense_time(DenseTime time); -internal DateTime date_time_from_micro_seconds(U64 time); +internal DateTime date_time_from_dense_time(DenseTime time); +internal DateTime date_time_from_micro_seconds(U64 time); +internal DateTime date_time_from_unix_time(U64 unix_time); //////////////////////////////// //~ rjf: Non-Fancy Ring Buffer Reads/Writes diff --git a/src/metagen/metagen_base/metagen_base_entry_point.c b/src/metagen/metagen_base/metagen_base_entry_point.c index 498ec0b5..21bbc363 100644 --- a/src/metagen/metagen_base/metagen_base_entry_point.c +++ b/src/metagen/metagen_base/metagen_base_entry_point.c @@ -1,26 +1,43 @@ // 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 - ThreadNameF("[main thread]"); - Temp scratch = scratch_begin(0, 0); - String8List command_line_argument_strings = os_string_list_from_argcv(scratch.arena, (int)arguments_count, arguments); + + //- rjf: parse command line + 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 B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture")); if(capture) { ProfBeginCapture(arguments[0]); } -#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL) - ts_init(); + +#if PROFILE_TELEMETRY + tmMessage(0, TMMF_ICON_NOTE, BUILD_TITLE); +#endif + + //- rjf: initialize all included layers +#if defined(ASYNC_H) && !defined(ASYNC_INIT_MANUAL) + async_init(&cmdline); +#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(); @@ -37,19 +54,16 @@ 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(DI_H) && !defined(DI_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 #if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) ctrl_init(); #endif -#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL) +#if defined(OS_GFX_H) && !defined(OS_GFX_INIT_MANUAL) os_gfx_init(); #endif #if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) @@ -64,21 +78,25 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum #if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) geo_init(); #endif -#if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL) - f_init(); +#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL) + fnt_init(); #endif -#if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL) - DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); - df_core_init(&cmdline, hist); +#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL) + d_init(); #endif -#if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL) - df_gfx_init(update_and_render, df_state_delta_history()); +#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL) + rd_init(&cmdline); #endif + + //- rjf: call into entry point entry_point(&cmdline); + + //- rjf: end captures if(capture) { ProfEndCapture(); } + scratch_end(scratch); } @@ -90,3 +108,23 @@ supplement_thread_base_entry_point(void (*entry_point)(void *params), void *para entry_point(params); 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); + ins_atomic_u64_inc_eval(&global_update_tick_idx); +#if OS_FEATURE_GRAPHICAL + B32 result = frame(); +#else + B32 result = 0; +#endif + return result; +} diff --git a/src/metagen/metagen_base/metagen_base_entry_point.h b/src/metagen/metagen_base/metagen_base_entry_point.h index 560bdcc7..318f8d9f 100644 --- a/src/metagen/metagen_base/metagen_base_entry_point.h +++ b/src/metagen/metagen_base/metagen_base_entry_point.h @@ -4,7 +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 diff --git a/src/metagen/metagen_base/metagen_base_inc.c b/src/metagen/metagen_base/metagen_base_inc.c index 74dcfe02..57aa2113 100644 --- a/src/metagen/metagen_base/metagen_base_inc.c +++ b/src/metagen/metagen_base/metagen_base_inc.c @@ -4,8 +4,8 @@ //////////////////////////////// //~ rjf: Base Includes -#undef RADDBG_LAYER_COLOR -#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f +#undef MARKUP_LAYER_COLOR +#define MARKUP_LAYER_COLOR 0.20f, 0.60f, 0.80f #include "metagen_base_core.c" #include "metagen_base_profile.c" @@ -15,5 +15,6 @@ #include "metagen_base_thread_context.c" #include "metagen_base_command_line.c" #include "metagen_base_markup.c" +#include "metagen_base_meta.c" #include "metagen_base_log.c" #include "metagen_base_entry_point.c" diff --git a/src/metagen/metagen_base/metagen_base_inc.h b/src/metagen/metagen_base/metagen_base_inc.h index 88aa65f7..55e2ebe7 100644 --- a/src/metagen/metagen_base/metagen_base_inc.h +++ b/src/metagen/metagen_base/metagen_base_inc.h @@ -17,6 +17,7 @@ #include "metagen_base_thread_context.h" #include "metagen_base_command_line.h" #include "metagen_base_markup.h" +#include "metagen_base_meta.h" #include "metagen_base_log.h" #include "metagen_base_entry_point.h" diff --git a/src/metagen/metagen_base/metagen_base_log.c b/src/metagen/metagen_base/metagen_base_log.c index 418b29ff..1c2a05f8 100644 --- a/src/metagen/metagen_base/metagen_base_log.c +++ b/src/metagen/metagen_base/metagen_base_log.c @@ -88,7 +88,7 @@ log_scope_end(Arena *arena) SLLStackPop(log_active->top_scope); if(arena != 0) { - for(EachEnumVal(LogMsgKind, kind)) + for EachEnumVal(LogMsgKind, kind) { Temp scratch = scratch_begin(&arena, 1); String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0); diff --git a/src/metagen/metagen_base/metagen_base_math.c b/src/metagen/metagen_base/metagen_base_math.c index 465d342d..2c6201f3 100644 --- a/src/metagen/metagen_base/metagen_base_math.c +++ b/src/metagen/metagen_base/metagen_base_math.c @@ -394,7 +394,7 @@ internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.m internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;} internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;} internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;} -internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;} +internal U32 dim_1u32(Rng1U32 r) {U32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;} internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;} @@ -404,7 +404,7 @@ internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.m internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;} internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;} internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;} -internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;} +internal S32 dim_1s32(Rng1S32 r) {S32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;} internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;} @@ -414,7 +414,7 @@ internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.m internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;} internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;} internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;} -internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;} +internal U64 dim_1u64(Rng1U64 r) {U64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;} internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;} @@ -424,7 +424,7 @@ internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.m internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;} internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;} internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;} -internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;} +internal S64 dim_1s64(Rng1S64 r) {S64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;} internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;} @@ -434,7 +434,7 @@ internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.m internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;} internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;} internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;} -internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;} +internal F32 dim_1f32(Rng1F32 r) {F32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;} internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;} internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;} internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;} @@ -444,7 +444,7 @@ internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s1 internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;} internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;} internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} -internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;} +internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0)), (S16)(((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0))}; return dim;} internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} @@ -454,7 +454,7 @@ internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s3 internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;} internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} -internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;} internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} @@ -464,7 +464,7 @@ internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s6 internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;} internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} -internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;} internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} @@ -474,7 +474,7 @@ internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f3 internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;} internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;} internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;} -internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;} +internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;} internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;} internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;} internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;} @@ -591,6 +591,49 @@ u32_from_rgba(Vec4F32 rgba) //////////////////////////////// //~ rjf: List Type Functions +internal void +rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng) +{ + Rng1U64Node *n = push_array(arena, Rng1U64Node, 1); + MemoryCopyStruct(&n->v, &rng); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal void +rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat) +{ + if(to_concat->first) + { + if(list->first) + { + list->last->next = to_concat->first; + list->last = to_concat->last; + } + else + { + list->first = to_concat->first; + list->last = to_concat->last; + } + MemoryZeroStruct(to_concat); + } +} + +internal Rng1U64Array +rng1u64_array_from_list(Arena *arena, Rng1U64List *list) +{ + Rng1U64Array arr = {0}; + arr.count = list->count; + arr.v = push_array_no_zero(arena, Rng1U64, arr.count); + U64 idx = 0; + for(Rng1U64Node *n = list->first; n != 0; n = n->next) + { + arr.v[idx] = n->v; + idx += 1; + } + return arr; +} + internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng) { diff --git a/src/metagen/metagen_base/metagen_base_math.h b/src/metagen/metagen_base/metagen_base_math.h index 645a6d31..b6063ad5 100644 --- a/src/metagen/metagen_base/metagen_base_math.h +++ b/src/metagen/metagen_base/metagen_base_math.h @@ -329,6 +329,28 @@ union Rng2S64 //////////////////////////////// //~ rjf: List Types +typedef struct Rng1U64Node Rng1U64Node; +struct Rng1U64Node +{ + Rng1U64Node *next; + Rng1U64 v; +}; + +typedef struct Rng1U64List Rng1U64List; +struct Rng1U64List +{ + U64 count; + Rng1U64Node *first; + Rng1U64Node *last; +}; + +typedef struct Rng1U64Array Rng1U64Array; +struct Rng1U64Array +{ + Rng1U64 *v; + U64 count; +}; + typedef struct Rng1S64Node Rng1S64Node; struct Rng1S64Node { @@ -643,6 +665,10 @@ internal U32 u32_from_rgba(Vec4F32 rgba); //////////////////////////////// //~ rjf: List Type Functions +internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng); +internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat); +internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list); + internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng); internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list); diff --git a/src/metagen/metagen_base/metagen_base_meta.c b/src/metagen/metagen_base/metagen_base_meta.c new file mode 100644 index 00000000..c60dc237 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_meta.c @@ -0,0 +1,422 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Type Info Lookups + +internal Member * +member_from_name(Type *type, String8 name) +{ + Member *member = &member_nil; + if(type->members != 0 && name.size != 0) + { + for(U64 idx = 0; idx < type->count; idx += 1) + { + if(str8_match(type->members[idx].name, name, 0)) + { + member = &type->members[idx]; + break; + } + } + } + return member; +} + +//////////////////////////////// +//~ rjf: Type Info * Instance Operations + +internal void +typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr) +{ + Temp scratch = scratch_begin(0, 0); + typedef struct RebaseTypeTask RebaseTypeTask; + struct RebaseTypeTask + { + RebaseTypeTask *next; + Type *type; + U8 *ptr; + }; + RebaseTypeTask start_task = {0, type, data.str}; + RebaseTypeTask *first_task = &start_task; + RebaseTypeTask *last_task = first_task; + for(RebaseTypeTask *t = first_task; t != 0; t = t->next) + { + switch(t->type->kind) + { + default:{}break; + case TypeKind_Ptr: + if(!(t->type->flags & TypeFlag_IsExternal)) + { + *(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr)); + }break; + case TypeKind_Array: + { + for(U64 idx = 0; idx < t->type->count; idx += 1) + { + RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1); + task->type = t->type->direct; + task->ptr = t->ptr + t->type->direct->size * idx; + SLLQueuePush(first_task, last_task, task); + } + }break; + case TypeKind_Struct: + { + for(U64 idx = 0; idx < t->type->count; idx += 1) + { + Member *member = &t->type->members[idx]; + RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1); + task->type = member->type; + task->ptr = t->ptr + member->value; + SLLQueuePush(first_task, last_task, task); + } + }break; + } + } + scratch_end(scratch); +} + +internal String8 +serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strings = {0}; + str8_serial_begin(scratch.arena, &strings); + { + typedef struct SerializeTypeTask SerializeTypeTask; + struct SerializeTypeTask + { + SerializeTypeTask *next; + Type *type; + U64 count; + U8 *src; + Type *containing_type; + U8 *containing_ptr; + B32 is_post_header; + }; + SerializeTypeTask start_task = {0, type, 1, data.str}; + SerializeTypeTask *first_task = &start_task; + SerializeTypeTask *last_task = first_task; + for(SerializeTypeTask *t = first_task; t != 0; t = t->next) + { + switch(t->type->kind) + { + //- rjf: leaf -> just copy the data directly + default: + if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf) + { + str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count)); + }break; + + //- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data + case TypeKind_Ptr: + { + // rjf: unpack info about this pointer + TypeSerializePtrRefInfo *ptr_ref_info = 0; + for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1) + { + if(params->ptr_ref_infos[idx].type == t->type->direct) + { + ptr_ref_info = ¶ms->ptr_ref_infos[idx]; + break; + } + } + + // rjf: indexification -> subtract base, divide direct size, write index + if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0) + { + U64 ptr_value = 0; + MemoryCopy(&ptr_value, t->src, sizeof(ptr_value)); + U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size); + str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value); + } + + // rjf: offsetification -> subtract base, write offsets + else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0) + { + U64 ptr_value = 0; + MemoryCopy(&ptr_value, t->src, sizeof(ptr_value)); + U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base); + str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value); + } + + // rjf: size-by-member (pre-header): still potentially dependent on other members which + // delimit our size, so push a new post-header task for pointer. + else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header) + { + SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1); + task->type = t->type; + task->count = t->count; + task->src = t->src; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + task->is_post_header = 1; + SLLQueuePush(first_task, last_task, task); + } + + // rjf: size-by-member (post-header): all flat parts of containing struct have been + // iterated, so now we can read the size, & descend to new task to read pointer + // destination contents + else if(t->type->count_delimiter_name.size != 0 && t->is_post_header) + { + // rjf: determine count of this pointer + U64 count = 0; + { + Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name); + MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size); + } + + // rjf: push task + SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1); + task->type = t->type->direct; + task->count = count; + task->src = *(void **)t->src; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + } + + // rjf: catch-all: write pointer value + else + { + str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count)); + } + }break; + + //- rjf: arrays -> descend to underlying type, + count + case TypeKind_Array: + { + SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1); + task->type = t->type->direct; + task->count = t->type->count; + task->src = t->src; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + }break; + + //- rjf: struct -> descend to members + case TypeKind_Struct: + { + U64 off = 0; + for(U64 idx = 0; idx < t->count; idx += 1) + { + for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1) + { + if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize) + { + continue; + } + SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1); + task->type = t->type->members[member_idx].type; + task->count = 1; + task->src = t->src + idx*t->type->size + t->type->members[member_idx].value; + task->containing_type = t->type; + task->containing_ptr = t->src; + SLLQueuePush(first_task, last_task, task); + } + } + }break; + + //- rjf: enum -> descend to basic type interpretation + case TypeKind_Enum: + { + SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1); + task->type = t->type->direct; + task->count = t->count; + task->src = t->src; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + }break; + } + } + } + String8 result = str8_serial_end(arena, &strings); + scratch_end(scratch); + return result; +} + +internal String8 +deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params) +{ + String8 result = {0}; + result.size = type->size; + result.str = push_array(arena, U8, result.size); + { + Temp scratch = scratch_begin(&arena, 1); + typedef struct DeserializeTypeTask DeserializeTypeTask; + struct DeserializeTypeTask + { + DeserializeTypeTask *next; + Type *type; + U64 count; + U8 *dst; + Type *containing_type; + U8 *containing_ptr; + B32 is_post_header; + }; + U64 read_off = 0; + DeserializeTypeTask start_task = {0, type, 1, result.str}; + DeserializeTypeTask *first_task = &start_task; + DeserializeTypeTask *last_task = first_task; + for(DeserializeTypeTask *t = first_task; t != 0; t = t->next) + { + U8 *t_src = data.str + read_off; + switch(t->type->kind) + { + //- rjf: leaf -> copy the data directly + default: + if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf) + { + MemoryCopy(t->dst, t_src, t->type->size*t->count); + read_off += t->type->size*t->count; + }break; + + //- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip + case TypeKind_Ptr: + { + // rjf: unpack info about this pointer + TypeSerializePtrRefInfo *ptr_ref_info = 0; + for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1) + { + if(params->ptr_ref_infos[idx].type == t->type->direct) + { + ptr_ref_info = ¶ms->ptr_ref_infos[idx]; + break; + } + } + + // rjf: indexification -> add base, multiply direct size + if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0) + { + U64 ptr_value = 0; + MemoryCopy(&ptr_value, t_src, sizeof(ptr_value)); + U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size; + MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value)); + read_off += sizeof(ptr_value); + } + + // rjf: offsetification -> subtract base, write offsets + else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0) + { + U64 ptr_value = 0; + MemoryCopy(&ptr_value, t_src, sizeof(ptr_value)); + U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base; + MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value)); + read_off += sizeof(ptr_value); + } + + // rjf: size-by-member (pre-header): still potentially dependent on other members which + // delimit our size, so push a new post-header task for pointer. + else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header) + { + DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1); + task->type = t->type; + task->count = t->count; + task->dst = t->dst; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + task->is_post_header = 1; + SLLQueuePush(first_task, last_task, task); + } + + // rjf: size-by-member (post-header): all flat parts of containing struct have been + // iterated, so now we can read the size, & descend to new task to read pointer + // destination contents + else if(t->type->count_delimiter_name.size != 0 && t->is_post_header) + { + // rjf: determine count of this pointer + U64 count = 0; + { + Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name); + MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size); + } + + // rjf: allocate buffer for pointer destination; write address into pointer value slot + U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size; + U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size); + MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer)); + + // rjf: push task + DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1); + task->type = t->type->direct; + task->count = count; + task->dst = ptr_dest_buffer; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + } + + // rjf: catch-all: read pointer value + else + { + MemoryCopy(t->dst, t_src, t->type->size*t->count); + read_off += t->type->size*t->count; + } + }break; + + //- rjf: arrays -> descend to underlying type, + count + case TypeKind_Array: + { + DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1); + task->type = t->type->direct; + task->count = t->type->count; + task->dst = t->dst; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + }break; + + //- rjf: struct -> descend to members + case TypeKind_Struct: + { + for(U64 idx = 0; idx < t->count; idx += 1) + { + for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1) + { + if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize) + { + continue; + } + DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1); + task->type = t->type->members[member_idx].type; + task->count = 1; + task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value; + task->containing_type = t->type; + task->containing_ptr = t->dst; + SLLQueuePush(first_task, last_task, task); + } + } + }break; + + //- rjf: enum -> descend to basic type interpretation + case TypeKind_Enum: + { + DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1); + task->type = t->type->direct; + task->count = t->count; + task->dst = t->dst; + task->containing_type = t->containing_type; + task->containing_ptr = t->containing_ptr; + SLLQueuePush(first_task, last_task, task); + }break; + } + } + if(params->advance_out != 0) + { + params->advance_out[0] = read_off; + } + scratch_end(scratch); + } + return result; +} + +internal String8 +deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params); + String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params); + scratch_end(scratch); + return data_copy; +} diff --git a/src/metagen/metagen_base/metagen_base_meta.h b/src/metagen/metagen_base/metagen_base_meta.h new file mode 100644 index 00000000..45d01e72 --- /dev/null +++ b/src/metagen/metagen_base/metagen_base_meta.h @@ -0,0 +1,298 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_META_H +#define BASE_META_H + +//////////////////////////////// +//~ rjf: Meta Markup Features + +#define EmbedFile(name, path) +#define TweakB32(name, default) (TWEAK_##name) +#define TweakF32(name, default, min, max) (TWEAK_##name) + +//////////////////////////////// +//~ rjf: Tweak Info Tables + +typedef struct TweakB32Info TweakB32Info; +struct TweakB32Info +{ + String8 name; + B32 default_value; + B32 *value_ptr; +}; + +typedef struct TweakF32Info TweakF32Info; +struct TweakF32Info +{ + String8 name; + F32 default_value; + Rng1F32 value_range; + F32 *value_ptr; +}; + +typedef struct TweakB32InfoTable TweakB32InfoTable; +struct TweakB32InfoTable +{ + TweakB32Info *v; + U64 count; +}; + +typedef struct TweakF32InfoTable TweakF32InfoTable; +struct TweakF32InfoTable +{ + TweakF32Info *v; + U64 count; +}; + +typedef struct EmbedInfo EmbedInfo; +struct EmbedInfo +{ + String8 name; + String8 *data; + U128 *hash; +}; + +typedef struct EmbedInfoTable EmbedInfoTable; +struct EmbedInfoTable +{ + EmbedInfo *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Type Info Types + +typedef enum TypeKind +{ + TypeKind_Null, + + // rjf: leaves + TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void, + TypeKind_U8, + TypeKind_U16, + TypeKind_U32, + TypeKind_U64, + TypeKind_S8, + TypeKind_S16, + TypeKind_S32, + TypeKind_S64, + TypeKind_B8, + TypeKind_B16, + TypeKind_B32, + TypeKind_B64, + TypeKind_F32, + TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64, + + // rjf: operators + TypeKind_Ptr, + TypeKind_Array, + + // rjf: user-defined-types + TypeKind_Struct, + TypeKind_Union, + TypeKind_Enum, + + TypeKind_COUNT +} +TypeKind; + +typedef U32 TypeFlags; +enum +{ + TypeFlag_IsExternal = (1<<0), + TypeFlag_IsPlainText = (1<<1), + TypeFlag_IsCodeText = (1<<2), + TypeFlag_IsPathText = (1<<3), +}; + +typedef U32 MemberFlags; +enum +{ + MemberFlag_DoNotSerialize = (1<<0), +}; + +typedef struct Type Type; +typedef struct Member Member; +struct Member +{ + String8 name; + String8 pretty_name; + Type *type; + U64 value; + MemberFlags flags; +}; + +typedef struct Type Type; +struct Type +{ + TypeKind kind; + TypeFlags flags; + U64 size; + Type *direct; + String8 name; + String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N] + U64 count; + Member *members; +}; + +//////////////////////////////// +//~ rjf: Type Serialization Parameters + +typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo; +struct TypeSerializePtrRefInfo +{ + Type *type; // pointers to this + void *indexify_base; // can be indexified using this + void *offsetify_base; // can be offsetified using this + void *nil_ptr; // is terminal if matching 0 or this +}; + +typedef struct TypeSerializeParams TypeSerializeParams; +struct TypeSerializeParams +{ + U64 *advance_out; + TypeSerializePtrRefInfo *ptr_ref_infos; + U64 ptr_ref_infos_count; +}; + +//////////////////////////////// +//~ rjf: Type Name -> Type Info + +#define type(T) (&T##__type) + +//////////////////////////////// +//~ rjf: Type Info Table Initializer Helpers + +#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__} +#define struct_members(S) read_only global Member S##__members[] = +#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__} +#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__} +#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__} + +//////////////////////////////// +//~ rjf: Globals + +read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil}; +read_only global Member member_nil = {{0}, {0}, &type_nil}; + +//////////////////////////////// +//~ rjf: Built-In Types + +//- rjf: leaves +read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")}; +read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")}; +read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")}; +read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")}; +read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")}; +read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")}; +read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")}; +read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")}; +read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")}; +read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")}; +read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")}; +read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")}; +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) +{ + member_lit_comp(Rng1U64, type(U64), min), + member_lit_comp(Rng1U64, type(U64), max), +}; +struct_type(Rng1U64); + +//- rjf: String8 +ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size")); +struct_members(String8) +{ + member_lit_comp(String8, &String8__str_ptr_type, str), + member_lit_comp(String8, type(U64), size), +}; +struct_type(String8); + +//- rjf: String8Node +extern Type String8Node__type; +Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type}; +Member String8Node__members[] = +{ + {str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)}, + {str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)}, +}; +Type String8Node__type = +{ + TypeKind_Struct, + 0, + sizeof(String8Node), + &type_nil, + str8_lit_comp("String8Node"), + {0}, + ArrayCount(String8Node__members), + String8Node__members, +}; + +//- rjf: String8List +Member String8List__members[] = +{ + {str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)}, + {str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize}, + {str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)}, + {str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)}, +}; +Type String8List__type = +{ + TypeKind_Struct, + 0, + sizeof(String8List), + &type_nil, + str8_lit_comp("String8List"), + {0}, + ArrayCount(String8List__members), + String8List__members, +}; + +//////////////////////////////// +//~ rjf: Type Info Lookups + +internal Member *member_from_name(Type *type, String8 name); +#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1) + +//////////////////////////////// +//~ rjf: Type Info * Instance Operations + +internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr); +internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params); +internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params); +internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params); +#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base)) +#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}) +#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str +#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str + +#endif // BASE_META_H diff --git a/src/metagen/metagen_base/metagen_base_profile.h b/src/metagen/metagen_base/metagen_base_profile.h index fa67b823..098270f4 100644 --- a/src/metagen/metagen_base/metagen_base_profile.h +++ b/src/metagen/metagen_base/metagen_base_profile.h @@ -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 //////////////////////////////// diff --git a/src/metagen/metagen_base/metagen_base_strings.c b/src/metagen/metagen_base/metagen_base_strings.c index 91a47562..9e42e0cd 100644 --- a/src/metagen/metagen_base/metagen_base_strings.c +++ b/src/metagen/metagen_base/metagen_base_strings.c @@ -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); @@ -500,6 +556,22 @@ s64_from_str8(String8 string, U32 radix){ return(x); } +internal U32 +u32_from_str8(String8 string, U32 radix) +{ + U64 x64 = u64_from_str8(string, radix); + U32 x32 = safe_cast_u32(x64); + return x32; +} + +internal S32 +s32_from_str8(String8 string, U32 radix) +{ + S64 x64 = s64_from_str8(string, radix); + S32 x32 = safe_cast_s32(x64); + return x32; +} + internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x){ B32 is_integer = 0; @@ -544,21 +616,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 +857,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 +1311,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 +1326,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 @@ -1346,70 +1520,127 @@ utf8_from_utf32_single(U8 *buffer, U32 character){ //~ rjf: Unicode String Conversions internal String8 -str8_from_16(Arena *arena, String16 in){ - U64 cap = in.size*3; - U8 *str = push_array_no_zero(arena, U8, cap + 1); - U16 *ptr = in.str; - U16 *opl = ptr + in.size; - U64 size = 0; - UnicodeDecode consume; - for (;ptr < opl; ptr += consume.inc){ - consume = utf16_decode(ptr, opl - ptr); - size += utf8_encode(str + size, consume.codepoint); +str8_from_16(Arena *arena, String16 in) +{ + String8 result = str8_zero(); + if(in.size) + { + U64 cap = in.size*3; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U16 *ptr = in.str; + U16 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for(;ptr < opl; ptr += consume.inc) + { + consume = utf16_decode(ptr, opl - ptr); + size += utf8_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_pop(arena, (cap - size)); + result = str8(str, size); } - str[size] = 0; - arena_pop(arena, (cap - size)); - return(str8(str, size)); + return result; } internal String16 -str16_from_8(Arena *arena, String8 in){ - U64 cap = in.size*2; - U16 *str = push_array_no_zero(arena, U16, cap + 1); - U8 *ptr = in.str; - U8 *opl = ptr + in.size; - U64 size = 0; - UnicodeDecode consume; - for (;ptr < opl; ptr += consume.inc){ - consume = utf8_decode(ptr, opl - ptr); - size += utf16_encode(str + size, consume.codepoint); +str16_from_8(Arena *arena, String8 in) +{ + String16 result = str16_zero(); + if(in.size) + { + U64 cap = in.size*2; + U16 *str = push_array_no_zero(arena, U16, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for(;ptr < opl; ptr += consume.inc) + { + consume = utf8_decode(ptr, opl - ptr); + size += utf16_encode(str + size, consume.codepoint); + } + str[size] = 0; + arena_pop(arena, (cap - size)*2); + result = str16(str, size); } - str[size] = 0; - arena_pop(arena, (cap - size)*2); - return(str16(str, size)); + return result; } internal String8 -str8_from_32(Arena *arena, String32 in){ - U64 cap = in.size*4; - U8 *str = push_array_no_zero(arena, U8, cap + 1); - U32 *ptr = in.str; - U32 *opl = ptr + in.size; - U64 size = 0; - for (;ptr < opl; ptr += 1){ - size += utf8_encode(str + size, *ptr); +str8_from_32(Arena *arena, String32 in) +{ + String8 result = str8_zero(); + if(in.size) + { + U64 cap = in.size*4; + U8 *str = push_array_no_zero(arena, U8, cap + 1); + U32 *ptr = in.str; + U32 *opl = ptr + in.size; + U64 size = 0; + for(;ptr < opl; ptr += 1) + { + size += utf8_encode(str + size, *ptr); + } + str[size] = 0; + arena_pop(arena, (cap - size)); + result = str8(str, size); } - str[size] = 0; - arena_pop(arena, (cap - size)); - return(str8(str, size)); + return result; } internal String32 -str32_from_8(Arena *arena, String8 in){ - U64 cap = in.size; - U32 *str = push_array_no_zero(arena, U32, cap + 1); - U8 *ptr = in.str; - U8 *opl = ptr + in.size; - U64 size = 0; - UnicodeDecode consume; - for (;ptr < opl; ptr += consume.inc){ - consume = utf8_decode(ptr, opl - ptr); - str[size] = consume.codepoint; - size += 1; +str32_from_8(Arena *arena, String8 in) +{ + String32 result = str32_zero(); + if(in.size) + { + U64 cap = in.size; + U32 *str = push_array_no_zero(arena, U32, cap + 1); + U8 *ptr = in.str; + U8 *opl = ptr + in.size; + U64 size = 0; + UnicodeDecode consume; + for(;ptr < opl; ptr += consume.inc) + { + consume = utf8_decode(ptr, opl - ptr); + str[size] = consume.codepoint; + size += 1; + } + str[size] = 0; + arena_pop(arena, (cap - size)*4); + result = str32(str, size); } - str[size] = 0; - arena_pop(arena, (cap - size)*4); - return(str32(str, size)); + return result; +} + +//////////////////////////////// +//~ 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; } //////////////////////////////// @@ -1444,22 +1675,18 @@ 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 -string_from_architecture(Architecture arch){ +string_from_arch(Arch arch){ local_persist String8 strings[] = { str8_lit_comp("Null"), str8_lit_comp("x64"), @@ -1468,7 +1695,7 @@ string_from_architecture(Architecture arch){ str8_lit_comp("arm32"), }; String8 result = str8_lit("error"); - if (arch < Architecture_COUNT){ + if (arch < Arch_COUNT){ result = strings[arch]; } return(result); @@ -1565,6 +1792,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 @@ -1593,6 +1892,10 @@ indented_from_string(Arena *arena, String8 string) { str8_list_pushf(scratch.arena, &indented_strings, "%.*s%S\n", (int)depth*2, indentation_bytes, line); } + if(line.size == 0 && indented_strings.node_count != 0 && off < string.size) + { + str8_list_pushf(scratch.arena, &indented_strings, "\n"); + } line_begin_off = off+1; depth = next_depth; }break; @@ -1603,6 +1906,100 @@ indented_from_string(Arena *arena, String8 string) return result; } +//////////////////////////////// +//~ rjf: Text Escaping + +internal String8 +escaped_from_raw_str8(Arena *arena, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List parts = {0}; + U64 start_split_idx = 0; + for(U64 idx = 0; idx <= string.size; idx += 1) + { + U8 byte = (idx < string.size) ? string.str[idx] : 0; + B32 split = 1; + String8 separator_replace = {0}; + switch(byte) + { + default:{split = 0;}break; + case 0: {}break; + case '\a': {separator_replace = str8_lit("\\a");}break; + case '\b': {separator_replace = str8_lit("\\b");}break; + case '\f': {separator_replace = str8_lit("\\f");}break; + case '\n': {separator_replace = str8_lit("\\n");}break; + case '\r': {separator_replace = str8_lit("\\r");}break; + case '\t': {separator_replace = str8_lit("\\t");}break; + case '\v': {separator_replace = str8_lit("\\v");}break; + case '\\': {separator_replace = str8_lit("\\\\");}break; + case '"': {separator_replace = str8_lit("\\\"");}break; + case '?': {separator_replace = str8_lit("\\?");}break; + } + if(split) + { + String8 substr = str8_substr(string, r1u64(start_split_idx, idx)); + start_split_idx = idx+1; + str8_list_push(scratch.arena, &parts, substr); + if(separator_replace.size != 0) + { + str8_list_push(scratch.arena, &parts, separator_replace); + } + } + } + StringJoin join = {0}; + String8 result = str8_list_join(arena, &parts, &join); + scratch_end(scratch); + return result; +} + +internal String8 +raw_from_escaped_str8(Arena *arena, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List strs = {0}; + U64 start = 0; + for(U64 idx = 0; idx <= string.size; idx += 1) + { + if(idx == string.size || string.str[idx] == '\\' || string.str[idx] == '\r') + { + String8 str = str8_substr(string, r1u64(start, idx)); + if(str.size != 0) + { + str8_list_push(scratch.arena, &strs, str); + } + start = idx+1; + } + if(idx < string.size && string.str[idx] == '\\') + { + U8 next_char = string.str[idx+1]; + U8 replace_byte = 0; + switch(next_char) + { + default:{}break; + case 'a': replace_byte = 0x07; break; + case 'b': replace_byte = 0x08; break; + case 'e': replace_byte = 0x1b; break; + case 'f': replace_byte = 0x0c; break; + case 'n': replace_byte = 0x0a; break; + case 'r': replace_byte = 0x0d; break; + case 't': replace_byte = 0x09; break; + case 'v': replace_byte = 0x0b; break; + case '\\':replace_byte = '\\'; break; + case '\'':replace_byte = '\''; break; + case '"': replace_byte = '"'; break; + case '?': replace_byte = '?'; break; + } + String8 replace_string = push_str8_copy(scratch.arena, str8(&replace_byte, 1)); + str8_list_push(scratch.arena, &strs, replace_string); + idx += 1; + start += 1; + } + } + String8 result = str8_list_join(arena, &strs, 0); + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: Text Wrapping @@ -1973,3 +2370,77 @@ str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out) *block_out = str8_substr(string, range); return block_out->size; } + +internal U64 +str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) + { + U8 byte = 0; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + + if(bytes_read != sizeof(byte)) + { + break; + } + + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + + cursor += bytes_read; + shift += 7u; + + if((byte & 0x80u) == 0) + { + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + +internal U64 +str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out) +{ + U64 value = 0; + U64 shift = 0; + U64 cursor = off; + for(;;) + { + U8 byte; + U64 bytes_read = str8_deserial_read_struct(string, cursor, &byte); + if(bytes_read != sizeof(byte)) + { + break; + } + + U8 val = byte & 0x7fu; + value |= ((U64)val) << shift; + + cursor += bytes_read; + shift += 7u; + + if((byte & 0x80u) == 0) + { + if(shift < sizeof(value) * 8 && (byte & 0x40u) != 0) + { + value |= -(S64)(1ull << shift); + } + break; + } + } + if(value_out != 0) + { + *value_out = value; + } + U64 bytes_read = cursor - off; + return bytes_read; +} + diff --git a/src/metagen/metagen_base/metagen_base_strings.h b/src/metagen/metagen_base/metagen_base_strings.h index c68bdff6..fc946dd8 100644 --- a/src/metagen/metagen_base/metagen_base_strings.h +++ b/src/metagen/metagen_base/metagen_base_strings.h @@ -86,6 +86,7 @@ enum typedef enum PathStyle { + PathStyle_Null, PathStyle_Relative, PathStyle_WindowsAbsolute, PathStyle_UnixAbsolute, @@ -192,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 @@ -205,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); //////////////////////////////// @@ -231,13 +235,19 @@ internal String8 push_str8f(Arena *arena, char *fmt, ...); //- rjf: string -> integer internal S64 sign_from_str8(String8 string, String8 *string_tail); internal B32 str8_is_integer(String8 string, U32 radix); + internal U64 u64_from_str8(String8 string, U32 radix); internal S64 s64_from_str8(String8 string, U32 radix); +internal U32 u32_from_str8(String8 string, U32 radix); +internal S32 s32_from_str8(String8 string, U32 radix); 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); @@ -309,13 +319,18 @@ 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 internal String8 string_from_dimension(Dimension dimension); internal String8 string_from_side(Side side); internal String8 string_from_operating_system(OperatingSystem os); -internal String8 string_from_architecture(Architecture arch); +internal String8 string_from_arch(Arch arch); //////////////////////////////// //~ rjf: Time Types -> String @@ -326,11 +341,24 @@ 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 internal String8 indented_from_string(Arena *arena, String8 string); +//////////////////////////////// +//~ rjf: Text Escaping + +internal String8 escaped_from_raw_str8(Arena *arena, String8 string); +internal String8 raw_from_escaped_str8(Arena *arena, String8 string); + //////////////////////////////// //~ rjf: Text Wrapping @@ -372,10 +400,13 @@ internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity); internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val); -internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); +internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size); +internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out); internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out); internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out); +internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out); +internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out); #define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr))) -#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr))) +#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1) #endif // BASE_STRINGS_H diff --git a/src/metagen/metagen_base/metagen_base_thread_context.h b/src/metagen/metagen_base/metagen_base_thread_context.h index 90a396fe..b2515c93 100644 --- a/src/metagen/metagen_base/metagen_base_thread_context.h +++ b/src/metagen/metagen_base/metagen_base_thread_context.h @@ -26,7 +26,7 @@ internal void tctx_init_and_equip(TCTX *tctx); internal void tctx_release(void); internal TCTX* tctx_get_equipped(void); -internal Arena* tctx_get_scratch(Arena **conflicts, U64 count); +internal Arena* tctx_get_scratch(Arena **conflicts, U64 countt); internal void tctx_set_thread_name(String8 name); internal String8 tctx_get_thread_name(void); diff --git a/src/metagen/metagen_main.c b/src/metagen/metagen_main.c index 2323a6d9..24c645b1 100644 --- a/src/metagen/metagen_main.c +++ b/src/metagen/metagen_main.c @@ -246,8 +246,7 @@ entry_point(CmdLine *cmdline) } for(String8Node *n = gen_strings.first; n != 0; n = n->next) { - String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_pushf(mg_arena, &layer->enums, "%S_%S,\n", enum_member_prefix, escaped); + str8_list_pushf(mg_arena, &layer->enums, "%S_%S,\n", enum_member_prefix, n->string); } if(enum_base_type_name.size == 0) { @@ -278,8 +277,7 @@ entry_point(CmdLine *cmdline) str8_list_pushf(mg_arena, &layer->enums, "#define %S \\\n", node->string); for(String8Node *n = gen_strings.first; n != 0; n = n->next) { - String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_pushf(mg_arena, &layer->enums, "X(%S)\\\n", escaped); + str8_list_pushf(mg_arena, &layer->enums, "X(%S)\\\n", n->string); } str8_list_push(mg_arena, &layer->enums, str8_lit("\n")); } @@ -303,8 +301,7 @@ entry_point(CmdLine *cmdline) str8_list_pushf(mg_arena, &layer->structs, "struct %S\n{\n", node->string); for(String8Node *n = gen_strings.first; n != 0; n = n->next) { - String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_pushf(mg_arena, &layer->structs, "%S;\n", escaped); + str8_list_pushf(mg_arena, &layer->structs, "%S;\n", n->string); } str8_list_pushf(mg_arena, &layer->structs, "};\n\n"); } @@ -333,8 +330,7 @@ entry_point(CmdLine *cmdline) str8_list_pushf(mg_arena, &layer->c_tables, "%S %S[%I64u] =\n{\n", element_type, node->string, gen_strings.node_count); for(String8Node *n = gen_strings.first; n != 0; n = n->next) { - String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_pushf(mg_arena, &layer->c_tables, "%S,\n", escaped); + str8_list_pushf(mg_arena, &layer->c_tables, "%S,\n", n->string); } str8_list_push(mg_arena, &layer->c_tables, str8_lit("};\n\n")); } @@ -364,8 +360,7 @@ entry_point(CmdLine *cmdline) str8_list_pushf(mg_arena, &layer->c_functions, "default:{}break;\n"); for(String8Node *n = gen_strings.first; n != 0; n = n->next) { - String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_pushf(mg_arena, &layer->c_functions, "%S;\n", escaped); + str8_list_pushf(mg_arena, &layer->c_functions, "%S;\n", n->string); } str8_list_pushf(mg_arena, &layer->c_functions, "}\n"); str8_list_pushf(mg_arena, &layer->c_functions, "return result;\n"); @@ -398,8 +393,7 @@ entry_point(CmdLine *cmdline) for(String8Node *n = gen_strings.first; n != 0; n = n->next) { String8 trimmed = str8_skip_chop_whitespace(n->string); - String8 escaped = mg_escaped_from_str8(mg_arena, trimmed); - str8_list_push(mg_arena, out, escaped); + str8_list_push(mg_arena, out, trimmed); str8_list_push(mg_arena, out, str8_lit("\n")); } } diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c index 2220b63e..23ec77cf 100644 --- a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.c @@ -150,9 +150,27 @@ os_get_current_path(Arena *arena) { char *cwdir = getcwd(0, 0); String8 string = push_str8_copy(arena, str8_cstring(cwdir)); + free(cwdir); return string; } +internal U32 +os_get_process_start_time_unix(void) +{ + Temp scratch = scratch_begin(0,0); + U64 start_time = 0; + pid_t pid = getpid(); + String8 path = push_str8f(scratch.arena, "/proc/%u", pid); + struct stat st; + int err = stat((char*)path.str, &st); + if(err == 0) + { + start_time = st.st_mtime; + } + scratch_end(scratch); + return (U32)start_time; +} + //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -162,6 +180,10 @@ internal void * os_reserve(U64 size) { void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if(result == MAP_FAILED) + { + result = 0; + } return result; } @@ -191,6 +213,10 @@ internal void * os_reserve_large(U64 size) { void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); + if(result == MAP_FAILED) + { + result = 0; + } return result; } @@ -207,12 +233,7 @@ os_commit_large(void *ptr, U64 size) internal U32 os_tid(void) { - U32 result = 0; -#if defined(SYS_gettid) - result = syscall(SYS_gettid); -#else - result = gettid(); -#endif + U32 result = gettid(); return result; } @@ -246,7 +267,7 @@ os_file_open(OS_AccessFlags flags, String8 path) Temp scratch = scratch_begin(0, 0); String8 path_copy = push_str8_copy(scratch.arena, path); int lnx_flags = 0; - if(flags & (OS_AccessFlag_Read|OS_AccessFlag_Write)) + if(flags & OS_AccessFlag_Read && flags & OS_AccessFlag_Write) { lnx_flags = O_RDWR; } @@ -262,7 +283,11 @@ os_file_open(OS_AccessFlags flags, String8 path) { lnx_flags |= O_APPEND; } - int fd = open((char *)path_copy.str, lnx_flags); + if(flags & (OS_AccessFlag_Write|OS_AccessFlag_Append)) + { + lnx_flags |= O_CREAT; + } + int fd = open((char *)path_copy.str, lnx_flags, 0755); OS_Handle handle = {0}; if(fd != -1) { @@ -285,16 +310,12 @@ os_file_read(OS_Handle file, Rng1U64 rng, void *out_data) { if(os_handle_match(file, os_handle_zero())) { return 0; } int fd = (int)file.u64[0]; - if(rng.min != 0) - { - lseek(fd, rng.min, SEEK_SET); - } U64 total_num_bytes_to_read = dim_1u64(rng); U64 total_num_bytes_read = 0; U64 total_num_bytes_left_to_read = total_num_bytes_to_read; for(;total_num_bytes_left_to_read > 0;) { - int read_result = read(fd, (U8 *)out_data + total_num_bytes_read, total_num_bytes_left_to_read); + int read_result = pread(fd, (U8 *)out_data + total_num_bytes_read, total_num_bytes_left_to_read, rng.min + total_num_bytes_read); if(read_result >= 0) { total_num_bytes_read += read_result; @@ -313,16 +334,12 @@ os_file_write(OS_Handle file, Rng1U64 rng, void *data) { if(os_handle_match(file, os_handle_zero())) { return 0; } int fd = (int)file.u64[0]; - if(rng.min != 0) - { - lseek(fd, rng.min, SEEK_SET); - } U64 total_num_bytes_to_write = dim_1u64(rng); U64 total_num_bytes_written = 0; U64 total_num_bytes_left_to_write = total_num_bytes_to_write; for(;total_num_bytes_left_to_write > 0;) { - int write_result = write(fd, (U8 *)data + total_num_bytes_written, total_num_bytes_left_to_write); + int write_result = pwrite(fd, (U8 *)data + total_num_bytes_written, total_num_bytes_left_to_write, rng.min + total_num_bytes_written); if(write_result >= 0) { total_num_bytes_written += write_result; @@ -402,25 +419,23 @@ os_copy_file_path(String8 dst, String8 src) if(!os_handle_match(src_h, os_handle_zero()) && !os_handle_match(dst_h, os_handle_zero())) { + int src_fd = (int)src_h.u64[0]; + int dst_fd = (int)dst_h.u64[0]; FileProperties src_props = os_properties_from_file(src_h); U64 size = src_props.size; U64 total_bytes_copied = 0; U64 bytes_left_to_copy = size; for(;bytes_left_to_copy > 0;) { - Temp scratch = scratch_begin(0, 0); - U64 buffer_size = Min(bytes_left_to_copy, MB(8)); - U8 *buffer = push_array_no_zero(scratch.arena, U8, buffer_size); - U64 bytes_read = os_file_read(src_h, r1u64(total_bytes_copied, total_bytes_copied+buffer_size), buffer); - U64 bytes_written = os_file_write(dst_h, r1u64(total_bytes_copied, total_bytes_copied+bytes_read), buffer); - U64 bytes_copied = Min(bytes_read, bytes_written); - bytes_left_to_copy -= bytes_copied; - total_bytes_copied += bytes_copied; - scratch_end(scratch); - if(bytes_copied == 0) + off_t sendfile_off = total_bytes_copied; + int send_result = sendfile(dst_fd, src_fd, &sendfile_off, bytes_left_to_copy); + if(send_result <= 0) { break; } + U64 bytes_copied = (U64)send_result; + bytes_left_to_copy -= bytes_copied; + total_bytes_copied += bytes_copied; } } os_file_close(src_h); @@ -428,6 +443,13 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + // TODO(rjf) + return 0; +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { @@ -455,6 +477,22 @@ os_file_path_exists(String8 path) return result; } +internal B32 +os_folder_path_exists(String8 path) +{ + Temp scratch = scratch_begin(0, 0); + B32 exists = 0; + String8 path_copy = push_str8_copy(scratch.arena, path); + DIR *handle = opendir((char*)path_copy.str); + if(handle) + { + closedir(handle); + exists = 1; + } + scratch_end(scratch); + return exists; +} + internal FileProperties os_properties_from_file_path(String8 path) { @@ -497,6 +535,10 @@ os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) if(flags & OS_AccessFlag_Read) { prot_flags |= PROT_READ; } int map_flags = MAP_PRIVATE; void *base = mmap(0, dim_1u64(range), prot_flags, map_flags, fd, range.min); + if(base == MAP_FAILED) + { + base = 0; + } return base; } @@ -589,7 +631,7 @@ os_make_directory(String8 path) Temp scratch = scratch_begin(0, 0); B32 result = 0; String8 path_copy = push_str8_copy(scratch.arena, path); - if(mkdir((char*)path_copy.str, 0777) != -1) + if(mkdir((char*)path_copy.str, 0755) != -1) { result = 1; } @@ -637,6 +679,10 @@ os_shared_memory_view_open(OS_Handle handle, Rng1U64 range) if(os_handle_match(handle, os_handle_zero())){return 0;} int id = (int)handle.u64[0]; void *base = mmap(0, dim_1u64(range), PROT_READ|PROT_WRITE, MAP_SHARED, id, range.min); + if(base == MAP_FAILED) + { + base = 0; + } return base; } @@ -744,10 +790,7 @@ os_thread_launch(OS_ThreadFunctionType *func, void *ptr, void *params) entity->thread.func = func; entity->thread.ptr = ptr; { - pthread_attr_t attr; - pthread_attr_init(&attr); - int pthread_result = pthread_create(&entity->thread.handle, &attr, os_lnx_thread_entry_point, entity); - pthread_attr_destroy(&attr); + int pthread_result = pthread_create(&entity->thread.handle, 0, os_lnx_thread_entry_point, entity); if(pthread_result == -1) { os_lnx_entity_release(entity); @@ -1025,13 +1068,26 @@ os_condition_variable_broadcast(OS_Handle cv) internal OS_Handle os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) { - NotImplemented; + OS_Handle result = {0}; + if (name.size > 0) { + // TODO: we need to allocate shared memory to store sem_t + NotImplemented; + } else { + sem_t *s = mmap(0, sizeof(*s), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + AssertAlways(s != MAP_FAILED); + int err = sem_init(s, 0, initial_count); + if (err == 0) { + result.u64[0] = (U64)s; + } + } + return result; } internal void os_semaphore_release(OS_Handle semaphore) { - NotImplemented; + int err = munmap((void*)semaphore.u64[0], sizeof(sem_t)); + AssertAlways(err == 0); } internal OS_Handle @@ -1049,13 +1105,37 @@ os_semaphore_close(OS_Handle semaphore) internal B32 os_semaphore_take(OS_Handle semaphore, U64 endt_us) { - NotImplemented; + AssertAlways(endt_us == max_U64); + for (;;) { + int err = sem_wait((sem_t*)semaphore.u64[0]); + if (err == 0) { + break; + } else { + if (errno == EAGAIN) { + continue; + } + } + InvalidPath; + break; + } + return 1; } internal void os_semaphore_drop(OS_Handle semaphore) { - NotImplemented; + for (;;) { + int err = sem_post((sem_t*)semaphore.u64[0]); + if (err == 0) { + break; + } else { + if (errno == EAGAIN) { + continue; + } + } + InvalidPath; + break; + } } //////////////////////////////// @@ -1066,7 +1146,7 @@ os_library_open(String8 path) { Temp scratch = scratch_begin(0, 0); char *path_cstr = (char *)push_str8_copy(scratch.arena, path).str; - void *so = dlopen(path_cstr, RTLD_LAZY); + void *so = dlopen(path_cstr, RTLD_LAZY|RTLD_LOCAL); OS_Handle lib = { (U64)so }; scratch_end(scratch); return lib; @@ -1130,14 +1210,11 @@ os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, v //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +internal Guid os_make_guid(void) { - U8 random_bytes[16] = {0}; - StaticAssert(sizeof(random_bytes) == sizeof(OS_Guid), os_lnx_guid_size_check); - getrandom(random_bytes, sizeof(random_bytes), 0); - OS_Guid guid = {0}; - MemoryCopy(&guid, random_bytes, sizeof(random_bytes)); + Guid guid = {0}; + getrandom(guid.v, sizeof(guid.v), 0); guid.data3 &= 0x0fff; guid.data3 |= (4 << 12); guid.data4[0] &= 0x3f; @@ -1256,5 +1333,5 @@ main(int argc, char **argv) } //- rjf: call into "real" entry point - main_thread_base_entry_point(entry_point, argv, (U64)argc); + main_thread_base_entry_point(argc, argv); } diff --git a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h index 531c6af3..e7d2ba5a 100644 --- a/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h +++ b/src/metagen/metagen_os/core/linux/metagen_os_core_linux.h @@ -8,24 +8,27 @@ //~ rjf: Includes #define _GNU_SOURCE +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +pid_t gettid(void); int pthread_setname_np(pthread_t thread, const char *name); int pthread_getname_np(pthread_t thread, char *name, size_t size); diff --git a/src/metagen/metagen_os/core/metagen_os_core.c b/src/metagen/metagen_os/core/metagen_os_core.c index a6718e32..21a0a413 100644 --- a/src/metagen/metagen_os/core/metagen_os_core.c +++ b/src/metagen/metagen_os/core/metagen_os_core.c @@ -152,22 +152,89 @@ os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) } //////////////////////////////// -//~ rjf: GUID Helpers (Helpers, Implemented Once) +//~ rjf: Process Launcher Helpers -internal String8 -os_string_from_guid(Arena *arena, OS_Guid guid) +internal OS_Handle +os_cmd_line_launch(String8 string) { - 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]); + Temp scratch = scratch_begin(0, 0); + U8 split_chars[] = {' '}; + String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0); + OS_Handle handle = {0}; + if(parts.node_count != 0) + { + // rjf: unpack exe part + String8 exe = parts.first->string; + String8 exe_folder = str8_chop_last_slash(exe); + if(exe_folder.size == 0) + { + exe_folder = os_get_current_path(scratch.arena); + } + + // rjf: find stdout delimiter + String8Node *stdout_delimiter_n = 0; + for(String8Node *n = parts.first; n != 0; n = n->next) + { + if(str8_match(n->string, str8_lit(">"), 0)) + { + stdout_delimiter_n = n; + break; + } + } + + // rjf: read stdout path + String8 stdout_path = {0}; + if(stdout_delimiter_n && stdout_delimiter_n->next) + { + stdout_path = stdout_delimiter_n->next->string; + } + + // rjf: open stdout handle + OS_Handle stdout_handle = {0}; + if(stdout_path.size != 0) + { + OS_Handle file = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Read, stdout_path); + os_file_close(file); + stdout_handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_Append|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_Inherited, stdout_path); + } + + // rjf: form command line + String8List cmdline = {0}; + for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next) + { + str8_list_push(scratch.arena, &cmdline, n->string); + } + + // rjf: launch + OS_ProcessLaunchParams params = {0}; + params.cmd_line = cmdline; + params.path = exe_folder; + params.inherit_env = 1; + params.stdout_file = stdout_handle; + handle = os_process_launch(¶ms); + + // rjf: close stdout handle + { + if(stdout_path.size != 0) + { + os_file_close(stdout_handle); + } + } + } + scratch_end(scratch); + return handle; +} + +internal OS_Handle +os_cmd_line_launchf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + OS_Handle result = os_cmd_line_launch(string); + va_end(args); + scratch_end(scratch); return result; } + diff --git a/src/metagen/metagen_os/core/metagen_os_core.h b/src/metagen/metagen_os/core/metagen_os_core.h index dcfb900d..e3a02048 100644 --- a/src/metagen/metagen_os/core/metagen_os_core.h +++ b/src/metagen/metagen_os/core/metagen_os_core.h @@ -24,6 +24,7 @@ typedef struct OS_ProcessInfo OS_ProcessInfo; struct OS_ProcessInfo { U32 pid; + B32 large_pages_allowed; String8 binary_path; String8 initial_path; String8 user_program_data_path; @@ -37,12 +38,13 @@ struct OS_ProcessInfo typedef U32 OS_AccessFlags; enum { - OS_AccessFlag_Read = (1<<0), - OS_AccessFlag_Write = (1<<1), - OS_AccessFlag_Execute = (1<<2), - OS_AccessFlag_Append = (1<<3), - OS_AccessFlag_ShareRead = (1<<4), - OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Read = (1<<0), + OS_AccessFlag_Write = (1<<1), + OS_AccessFlag_Execute = (1<<2), + OS_AccessFlag_Append = (1<<3), + OS_AccessFlag_ShareRead = (1<<4), + OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Inherited = (1<<6), }; //////////////////////////////// @@ -78,19 +80,6 @@ struct OS_FileID U64 v[3]; }; -//////////////////////////////// -//~ rjf: Process Launch Parameters - -typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams; -struct OS_ProcessLaunchParams -{ - String8List cmd_line; - String8 path; - String8List env; - B32 inherit_env; - B32 consoleless; -}; - //////////////////////////////// //~ rjf: Handle Type @@ -123,17 +112,21 @@ struct OS_HandleArray }; //////////////////////////////// -//~ rjf: Globally Unique IDs +//~ rjf: Process Launch Parameters -typedef struct OS_Guid OS_Guid; -struct OS_Guid +typedef struct OS_ProcessLaunchParams OS_ProcessLaunchParams; +struct OS_ProcessLaunchParams { - U32 data1; - U16 data2; - U16 data3; - U8 data4[8]; + String8List cmd_line; + String8 path; + String8List env; + B32 inherit_env; + B32 debug_subprocesses; + B32 consoleless; + OS_Handle stdout_file; + OS_Handle stderr_file; + OS_Handle stdin_file; }; -StaticAssert(sizeof(OS_Guid) == 16, os_guid_check); //////////////////////////////// //~ rjf: Thread Types @@ -165,16 +158,18 @@ internal S64 os_file_id_compare(OS_FileID a, OS_FileID b); internal String8 os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range); //////////////////////////////// -//~ rjf: GUID Helpers (Helpers, Implemented Once) +//~ rjf: Process Launcher Helpers -internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); +internal OS_Handle os_cmd_line_launch(String8 string); +internal OS_Handle os_cmd_line_launchf(char *fmt, ...); //////////////////////////////// //~ rjf: @os_hooks System/Process Info (Implemented Per-OS) -internal OS_SystemInfo *os_get_system_info(void); +internal OS_SystemInfo *os_get_system_info(void); internal OS_ProcessInfo *os_get_process_info(void); -internal String8 os_get_current_path(Arena *arena); +internal String8 os_get_current_path(Arena *arena); +internal U32 os_get_process_start_time_unix(void); //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -207,14 +202,18 @@ internal void os_abort(S32 exit_code); internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); internal void os_file_close(OS_Handle file); internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data); +#define os_file_read_struct(f, off, ptr) os_file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr)) internal U64 os_file_write(OS_Handle file, Rng1U64 rng, void *data); internal B32 os_file_set_times(OS_Handle file, DateTime time); internal FileProperties os_properties_from_file(OS_Handle file); internal OS_FileID os_id_from_file(OS_Handle file); +internal B32 os_file_reserve_size(OS_Handle file, U64 size); internal B32 os_delete_file_at_path(String8 path); internal B32 os_copy_file_path(String8 dst, String8 src); +internal B32 os_move_file_path(String8 dst, String8 src); internal String8 os_full_path_from_path(Arena *arena, String8 path); internal B32 os_file_path_exists(String8 path); +internal B32 os_folder_path_exists(String8 path); internal FileProperties os_properties_from_file_path(String8 path); //- rjf: file maps @@ -320,7 +319,7 @@ internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *f //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid os_make_guid(void); +internal Guid os_make_guid(void); //////////////////////////////// //~ rjf: @os_hooks Entry Points (Implemented Per-OS) diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c index 37e02710..6cc494f0 100644 --- a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.c @@ -90,6 +90,18 @@ os_w32_sleep_ms_from_endt_us(U64 endt_us) return sleep_ms; } +internal U32 +os_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; +} + //////////////////////////////// //~ rjf: Entity Functions @@ -167,6 +179,21 @@ os_get_current_path(Arena *arena) return name; } +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 os_w32_unix_time_from_file_time(start_time); + } + return 0; +} + //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -293,14 +320,19 @@ os_file_open(OS_AccessFlags flags, String8 path) DWORD access_flags = 0; DWORD share_mode = 0; DWORD creation_disposition = OPEN_EXISTING; - if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} - if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} - if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} - if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} - if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} - if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} - if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS;} - HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); + SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), 0, 0}; + if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} + if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} + if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} + if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} + if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} + if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} + if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS; access_flags |= FILE_APPEND_DATA; } + if(flags & OS_AccessFlag_Inherited) + { + security_attributes.bInheritHandle = 1; + } + HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, &security_attributes, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); if(file != INVALID_HANDLE_VALUE) { result.u64[0] = (U64)file; @@ -361,27 +393,29 @@ os_file_write(OS_Handle file, Rng1U64 rng, void *data) HANDLE win_handle = (HANDLE)file.u64[0]; U64 src_off = 0; U64 dst_off = rng.min; - U64 bytes_to_write_total = rng.max-rng.min; - U64 total_bytes_written = 0; - for(;src_off < bytes_to_write_total;) + U64 total_write_size = dim_1u64(rng); + for(;;) { - void *bytes_src = (void *)((U8 *)data + src_off); - U64 bytes_to_write_64 = (bytes_to_write_total-src_off); - U32 bytes_to_write_32 = u32_from_u64_saturate(bytes_to_write_64); - U32 bytes_written = 0; + void *bytes_src = (U8 *)data + src_off; + U64 bytes_left = total_write_size - src_off; + DWORD write_size = Min(MB(1), bytes_left); + DWORD bytes_written = 0; OVERLAPPED overlapped = {0}; - overlapped.Offset = (dst_off&0x00000000ffffffffull); + overlapped.Offset = (dst_off&0x00000000ffffffffull); overlapped.OffsetHigh = (dst_off&0xffffffff00000000ull) >> 32; - BOOL success = WriteFile(win_handle, bytes_src, bytes_to_write_32, (DWORD *)&bytes_written, &overlapped); + BOOL success = WriteFile(win_handle, bytes_src, write_size, &bytes_written, &overlapped); if(success == 0) { break; } src_off += bytes_written; dst_off += bytes_written; - total_bytes_written += bytes_written; + if(bytes_left == 0) + { + break; + } } - return total_bytes_written; + return src_off; } internal B32 @@ -435,6 +469,19 @@ os_id_from_file(OS_Handle file) return result; } +internal B32 +os_file_reserve_size(OS_Handle file, U64 size) +{ + HANDLE handle = (HANDLE)file.u64[0]; + + FILE_ALLOCATION_INFO alloc_info = {0}; + alloc_info.AllocationSize.LowPart = size & max_U32; + alloc_info.AllocationSize.HighPart = (size >> 32) & max_U32; + + BOOL is_reserved = SetFileInformationByHandle(handle, FileAllocationInfo, &alloc_info, sizeof(alloc_info)); + return is_reserved; +} + internal B32 os_delete_file_at_path(String8 path) { @@ -456,15 +503,33 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + Temp scratch = scratch_begin(0, 0); + String16 dst16 = str16_from_8(scratch.arena, dst); + String16 src16 = str16_from_8(scratch.arena, src); + B32 result = MoveFileW((WCHAR*)src16.str, (WCHAR*)dst16.str); + scratch_end(scratch); + return result; +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { Temp scratch = scratch_begin(&arena, 1); - DWORD buffer_size = MAX_PATH + 1; - U16 *buffer = push_array_no_zero(scratch.arena, U16, buffer_size); - String16 path16 = str16_from_8(scratch.arena, path); - DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, (WCHAR*)buffer, NULL); - String8 full_path = str8_from_16(arena, str16(buffer, path16_size)); + DWORD buffer_size = Max(MAX_PATH, path.size * 2) + 1; + String16 path16 = str16_from_8(scratch.arena, path); + WCHAR *buffer = push_array_no_zero(scratch.arena, WCHAR, buffer_size); + DWORD path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, buffer, NULL); + if(path16_size > buffer_size) + { + arena_pop(scratch.arena, buffer_size); + buffer_size = path16_size + 1; + buffer = push_array_no_zero(scratch.arena, WCHAR, buffer_size); + path16_size = GetFullPathNameW((WCHAR*)path16.str, buffer_size, buffer, NULL); + } + String8 full_path = str8_from_16(arena, str16((U16*)buffer, path16_size)); scratch_end(scratch); return full_path; } @@ -480,6 +545,17 @@ os_file_path_exists(String8 path) return exists; } +internal B32 +os_folder_path_exists(String8 path) +{ + Temp scratch = scratch_begin(0,0); + String16 path16 = str16_from_8(scratch.arena, path); + DWORD attributes = GetFileAttributesW((WCHAR *)path16.str); + B32 exists = (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY); + scratch_end(scratch); + return exists; +} + internal FileProperties os_properties_from_file_path(String8 path) { @@ -495,6 +571,28 @@ os_properties_from_file_path(String8 path) os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); } + else + { + Temp scratch = scratch_begin(0, 0); + WCHAR buffer[512] = {0}; + DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); + U64 last_slash_pos = 0; + for(;last_slash_pos < path.size; last_slash_pos = str8_find_needle(path, last_slash_pos+1, str8_lit("/"), StringMatchFlag_SlashInsensitive)); + String8 path_trimmed = str8_prefix(path, last_slash_pos); + for(U64 off = 0; off < (U64)length;) + { + String16 next_drive_string_16 = str16_cstring((U16 *)buffer+off); + off += next_drive_string_16.size+1; + String8 next_drive_string = str8_from_16(scratch.arena, next_drive_string_16); + next_drive_string = str8_chop_last_slash(next_drive_string); + if(str8_match(path_trimmed, next_drive_string, StringMatchFlag_CaseInsensitive)) + { + props.flags |= FilePropertyFlag_IsFolder; + break; + } + } + scratch_end(scratch); + } FindClose(handle); scratch_end(scratch); return props; @@ -704,7 +802,12 @@ internal void os_file_iter_end(OS_FileIter *iter) { OS_W32_FileIter *w32_iter = (OS_W32_FileIter*)iter->memory; - FindClose(w32_iter->handle); + HANDLE zero_handle; + MemoryZeroStruct(&zero_handle); + if(!MemoryMatchStruct(&zero_handle, &w32_iter->handle)) + { + FindClose(w32_iter->handle); + } } //- rjf: directory creation @@ -805,10 +908,8 @@ os_now_unix(void) { FILETIME file_time; GetSystemTimeAsFileTime(&file_time); - U64 win32_time = ((U64)file_time.dwHighDateTime << 32) | file_time.dwLowDateTime; - U64 unix_time64 = ((win32_time - 0x19DB1DED53E8000ULL) / 10000000); - U32 unix_time32 = (U32)unix_time64; - return unix_time32; + U32 unix_time = os_w32_unix_time_from_file_time(file_time); + return unix_time; } internal DateTime @@ -926,9 +1027,31 @@ os_process_launch(OS_ProcessLaunchParams *params) } //- rjf: launch + BOOL inherit_handles = 0; STARTUPINFOW startup_info = {sizeof(startup_info)}; + if(!os_handle_match(params->stdout_file, os_handle_zero())) + { + HANDLE stdout_handle = (HANDLE)params->stdout_file.u64[0]; + startup_info.hStdOutput = stdout_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } + if(!os_handle_match(params->stderr_file, os_handle_zero())) + { + HANDLE stderr_handle = (HANDLE)params->stderr_file.u64[0]; + startup_info.hStdError = stderr_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } + if(!os_handle_match(params->stdin_file, os_handle_zero())) + { + HANDLE stdin_handle = (HANDLE)params->stdin_file.u64[0]; + startup_info.hStdInput = stdin_handle; + startup_info.dwFlags |= STARTF_USESTDHANDLES; + inherit_handles = 1; + } PROCESS_INFORMATION process_info = {0}; - if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, inherit_handles, creation_flags, use_null_env_arg ? 0 : (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) { result.u64[0] = (U64)process_info.hProcess; CloseHandle(process_info.hThread); @@ -977,8 +1100,9 @@ os_thread_join(OS_Handle handle, U64 endt_us) if(entity != 0) { wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms); + CloseHandle(entity->thread.handle); + os_w32_entity_release(entity); } - os_w32_entity_release(entity); return (wait_result == WAIT_OBJECT_0); } @@ -986,7 +1110,11 @@ internal void os_thread_detach(OS_Handle thread) { OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(thread.u64[0]); - os_w32_entity_release(entity); + if(entity != 0) + { + CloseHandle(entity->thread.handle); + os_w32_entity_release(entity); + } } //////////////////////////////// @@ -1255,10 +1383,10 @@ os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *fail_handler, v //////////////////////////////// //~ rjf: @os_hooks GUIDs (Implemented Per-OS) -internal OS_Guid +internal Guid os_make_guid(void) { - OS_Guid result; MemoryZeroStruct(&result); + Guid result; MemoryZeroStruct(&result); UUID uuid; RPC_STATUS rpc_status = UuidCreate(&uuid); if(rpc_status == RPC_S_OK) @@ -1344,8 +1472,12 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) HANDLE thread = GetCurrentThread(); CONTEXT* context = exception_ptrs->ContextRecord; + WCHAR module_path[MAX_PATH]; + GetModuleFileNameW(NULL, module_path, ArrayCount(module_path)); + PathRemoveFileSpecW(module_path); + dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - if(dbg_SymInitializeW(process, L"", TRUE)) + if(dbg_SymInitializeW(process, module_path, TRUE)) { // check that raddbg.pdb file is good B32 raddbg_pdb_valid = 0; @@ -1384,7 +1516,7 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) frame.AddrStack.Offset = context->Sp; frame.AddrStack.Mode = AddrModeFlat; #else -# error Architecture not supported! +# error Arch not supported! #endif for(U32 idx=0; ;idx++) @@ -1488,129 +1620,60 @@ w32_entry_point_caller(int argc, WCHAR **wargv) { SetUnhandledExceptionFilter(&win32_exception_filter); - //- rjf: do OS layer initialization + //- rjf: dynamically load windows functions which are not guaranteed + // in all SDKs { - // rjf: dynamically load windows functions which are not guaranteed - // in all SDKs + HMODULE module = LoadLibraryA("kernel32.dll"); + w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription"); + FreeLibrary(module); + } + + //- rjf: try to allow large pages if we can + B32 large_pages_allowed = 0; + { + HANDLE token; + if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { - HMODULE module = LoadLibraryA("kernel32.dll"); - w32_SetThreadDescription_func = (W32_SetThreadDescription_Type *)GetProcAddress(module, "SetThreadDescription"); - FreeLibrary(module); - } - - // rjf: try to enable large pages if we can - { - HANDLE token; - if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) + LUID luid; + if(LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) { - 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 = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0); - } - CloseHandle(token); + TOKEN_PRIVILEGES priv; + priv.PrivilegeCount = 1; + priv.Privileges[0].Luid = luid; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + large_pages_allowed = !!AdjustTokenPrivileges(token, 0, &priv, sizeof(priv), 0, 0); } + CloseHandle(token); } - - // rjf: get system info - SYSTEM_INFO sysinfo = {0}; - GetSystemInfo(&sysinfo); - - // rjf: set up non-dynamically-alloc'd state - // - // (we need to set up some basics before this layer can supply - // memory allocation primitives) + } + + //- rjf: get system info + SYSTEM_INFO sysinfo = {0}; + GetSystemInfo(&sysinfo); + + //- rjf: set up non-dynamically-alloc'd state + // + // (we need to set up some basics before this layer can supply + // memory allocation primitives) + { + os_w32_state.microsecond_resolution = 1; + LARGE_INTEGER large_int_resolution; + if(QueryPerformanceFrequency(&large_int_resolution)) { - os_w32_state.microsecond_resolution = 1; - LARGE_INTEGER large_int_resolution; - if(QueryPerformanceFrequency(&large_int_resolution)) - { - os_w32_state.microsecond_resolution = large_int_resolution.QuadPart; - } + os_w32_state.microsecond_resolution = large_int_resolution.QuadPart; } - { - OS_SystemInfo *info = &os_w32_state.system_info; - info->logical_processor_count = (U64)sysinfo.dwNumberOfProcessors; - info->page_size = sysinfo.dwPageSize; - info->large_page_size = GetLargePageMinimum(); - info->allocation_granularity = sysinfo.dwAllocationGranularity; - } - { - OS_ProcessInfo *info = &os_w32_state.process_info; - info->pid = GetCurrentProcessId(); - } - - // rjf: set up thread context - local_persist TCTX tctx; - tctx_init_and_equip(&tctx); - - // rjf: set up dynamically-alloc'd state - Arena *arena = arena_alloc(); - { - os_w32_state.arena = arena; - { - OS_SystemInfo *info = &os_w32_state.system_info; - U8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; - DWORD size = MAX_COMPUTERNAME_LENGTH + 1; - if(GetComputerNameA((char*)buffer, &size)) - { - info->machine_name = push_str8_copy(arena, str8(buffer, size)); - } - } - } - { - OS_ProcessInfo *info = &os_w32_state.process_info; - { - Temp scratch = scratch_begin(0, 0); - DWORD size = KB(32); - U16 *buffer = push_array_no_zero(scratch.arena, U16, size); - DWORD length = GetModuleFileNameW(0, (WCHAR*)buffer, size); - String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); - String8 name_chopped = str8_chop_last_slash(name8); - info->binary_path = push_str8_copy(arena, name_chopped); - scratch_end(scratch); - } - info->initial_path = os_get_current_path(arena); - { - Temp scratch = scratch_begin(0, 0); - U64 size = KB(32); - U16 *buffer = push_array_no_zero(scratch.arena, U16, size); - if(SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))) - { - info->user_program_data_path = str8_from_16(arena, str16_cstring(buffer)); - } - scratch_end(scratch); - } - { - WCHAR *this_proc_env = GetEnvironmentStringsW(); - U64 start_idx = 0; - for(U64 idx = 0;; idx += 1) - { - if(this_proc_env[idx] == 0) - { - if(start_idx == idx) - { - break; - } - else - { - String16 string16 = str16((U16 *)this_proc_env + start_idx, idx - start_idx); - String8 string = str8_from_16(arena, string16); - str8_list_push(arena, &info->environment, string); - start_idx = idx+1; - } - } - } - } - } - - // rjf: set up entity storage - InitializeCriticalSection(&os_w32_state.entity_mutex); - os_w32_state.entity_arena = arena_alloc(); + } + { + OS_SystemInfo *info = &os_w32_state.system_info; + info->logical_processor_count = (U64)sysinfo.dwNumberOfProcessors; + info->page_size = sysinfo.dwPageSize; + info->large_page_size = GetLargePageMinimum(); + info->allocation_granularity = sysinfo.dwAllocationGranularity; + } + { + OS_ProcessInfo *info = &os_w32_state.process_info; + info->large_pages_allowed = large_pages_allowed; + info->pid = GetCurrentProcessId(); } //- rjf: extract arguments @@ -1620,15 +1683,91 @@ w32_entry_point_caller(int argc, WCHAR **wargv) { String16 arg16 = str16_cstring((U16 *)wargv[i]); String8 arg8 = str8_from_16(args_arena, arg16); - if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) + if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive) || + str8_match(arg8, str8_lit("-quiet"), StringMatchFlag_CaseInsensitive)) { win32_g_is_quiet = 1; } + if(str8_match(arg8, str8_lit("--large_pages"), StringMatchFlag_CaseInsensitive) || + str8_match(arg8, str8_lit("-large_pages"), StringMatchFlag_CaseInsensitive)) + { + arena_default_flags = ArenaFlag_LargePages; + arena_default_reserve_size = Max(MB(64), os_w32_state.system_info.large_page_size); + arena_default_commit_size = arena_default_reserve_size; + } argv[i] = (char *)arg8.str; } + //- rjf: set up thread context + local_persist TCTX tctx; + tctx_init_and_equip(&tctx); + + //- rjf: set up dynamically-alloc'd state + Arena *arena = arena_alloc(); + { + os_w32_state.arena = arena; + { + OS_SystemInfo *info = &os_w32_state.system_info; + U8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD size = MAX_COMPUTERNAME_LENGTH + 1; + if(GetComputerNameA((char*)buffer, &size)) + { + info->machine_name = push_str8_copy(arena, str8(buffer, size)); + } + } + } + { + OS_ProcessInfo *info = &os_w32_state.process_info; + { + Temp scratch = scratch_begin(0, 0); + DWORD size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + DWORD length = GetModuleFileNameW(0, (WCHAR*)buffer, size); + String8 name8 = str8_from_16(scratch.arena, str16(buffer, length)); + String8 name_chopped = str8_chop_last_slash(name8); + info->binary_path = push_str8_copy(arena, name_chopped); + scratch_end(scratch); + } + info->initial_path = os_get_current_path(arena); + { + Temp scratch = scratch_begin(0, 0); + U64 size = KB(32); + U16 *buffer = push_array_no_zero(scratch.arena, U16, size); + if(SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))) + { + info->user_program_data_path = str8_from_16(arena, str16_cstring(buffer)); + } + scratch_end(scratch); + } + { + WCHAR *this_proc_env = GetEnvironmentStringsW(); + U64 start_idx = 0; + for(U64 idx = 0;; idx += 1) + { + if(this_proc_env[idx] == 0) + { + if(start_idx == idx) + { + break; + } + else + { + String16 string16 = str16((U16 *)this_proc_env + start_idx, idx - start_idx); + String8 string = str8_from_16(arena, string16); + str8_list_push(arena, &info->environment, string); + start_idx = idx+1; + } + } + } + } + } + + //- rjf: set up entity storage + InitializeCriticalSection(&os_w32_state.entity_mutex); + os_w32_state.entity_arena = arena_alloc(); + //- rjf: call into "real" entry point - main_thread_base_entry_point(entry_point, argv, (U64)argc); + main_thread_base_entry_point(argc, argv); } #if BUILD_CONSOLE_INTERFACE diff --git a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h index a8c031fd..9a8f0d12 100644 --- a/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h +++ b/src/metagen/metagen_os/core/win32/metagen_os_core_win32.h @@ -7,7 +7,6 @@ //////////////////////////////// //~ rjf: Includes / Libraries -#define WIN32_LEAN_AND_MEAN #include #include #include diff --git a/src/metagen/metagen_os/metagen_os_inc.h b/src/metagen/metagen_os/metagen_os_inc.h index f8c8e06c..b2d96f02 100644 --- a/src/metagen/metagen_os/metagen_os_inc.h +++ b/src/metagen/metagen_os/metagen_os_inc.h @@ -8,10 +8,6 @@ # define OS_FEATURE_GRAPHICAL 0 #endif -#if !defined(OS_GFX_STUB) -# define OS_GFX_STUB 0 -#endif - #include "metagen/metagen_os/core/metagen_os_core.h" #if OS_WINDOWS diff --git a/src/msf/msf.c b/src/msf/msf.c index f78cec82..116918c8 100644 --- a/src/msf/msf.c +++ b/src/msf/msf.c @@ -1,4 +1,16 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +internal B32 +msf_check_magic_20(String8 data) +{ + B32 is_msf = data.size >= sizeof(msf_msf20_magic) && str8_match(data, str8_lit(msf_msf20_magic), StringMatchFlag_RightSideSloppy); + return is_msf; +} +internal B32 +msf_check_magic_70(String8 data) +{ + B32 is_msf = data.size >= sizeof(msf_msf70_magic) && str8_match(data, str8_lit(msf_msf70_magic), StringMatchFlag_RightSideSloppy); + return is_msf; +} diff --git a/src/msf/msf.h b/src/msf/msf.h index f18d8204..34bc9960 100644 --- a/src/msf/msf.h +++ b/src/msf/msf.h @@ -52,4 +52,9 @@ struct MSF_Header70 MSF_PageNumber root_pn; }; +//////////////////////////////// + +internal B32 msf_check_magic_20(String8 data); +internal B32 msf_check_magic_70(String8 data); + #endif // MSF_H diff --git a/src/msf/msf_parse.c b/src/msf/msf_parse.c index 79d00fd1..941f5d40 100644 --- a/src/msf/msf_parse.c +++ b/src/msf/msf_parse.c @@ -13,11 +13,9 @@ msf_raw_stream_table_from_data(Arena *arena, String8 msf_data) //- determine msf type U32 index_size = 0; - if (msf_data.size >= sizeof(msf_msf20_magic) && - str8_match(msf_data, str8_lit(msf_msf20_magic), StringMatchFlag_RightSideSloppy)) { + if (msf_check_magic_20(msf_data)) { index_size = 2; - } else if (msf_data.size >= sizeof(msf_msf70_magic) && - str8_match(msf_data, str8_lit(msf_msf70_magic), StringMatchFlag_RightSideSloppy)) { + } else if (msf_check_magic_70(msf_data)) { index_size = 4; } diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 54c38c44..72136675 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -1,2723 +1,3053 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -/* -** Program to run in debugger organized to provide tests for -** stepping, breakpoints, evaluation, cross-module calls. -*/ - -#include "lib_raddbg_markup/raddbg_markup.h" - -//////////////////////////////// -// NOTE(allen): System For DLL Testing - -typedef void TestFunction(void); - -static void mule_init(void); -static TestFunction* mule_get_module_function(char *name); - -#if _WIN32 - -#include - -HMODULE mule_dll = 0; - -static void -mule_init(void){ - mule_dll = LoadLibraryA("mule_module.dll"); -} - -static TestFunction* -mule_get_module_function(char *name){ - TestFunction *result = (TestFunction*)GetProcAddress(mule_dll, name); - return(result); -} - -#else - -static void -mule_init(void){ - // TODO(allen): implement -} - -static TestFunction* -mule_get_module_function(char *name){ - // TODO(allen): implement - return(0); -} - -#endif - - -//////////////////////////////// -// NOTE(nick): Entry Point - -int -mule_main(int argc, char **argv); - -#if _WIN32 -#include -#include -int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){ - int argc = __argc; - char **argv = __argv; - int result = mule_main(argc, argv); - return(result); -} -#else -int main(int argc, char **argv){ - return(mule_main(argc, argv)); -} -#endif - -//////////////////////////////// -// NOTE(nick): BSS section test - -#if defined(__clang__) -# pragma clang section bss="muleBSS" -#elif defined(_MSC_VER) -// NOTE(nick): clang-cl is borken it allocates memory and sets Initialized Flag on the seciton. -// This is was reported by Jeff => https://bugs.llvm.org/show_bug.cgi?id=47939 -// -// This is still unresolved, last checked Sep 11, 2023. -# pragma bss_seg("muleBSS") -#else -# error "bss not defined" -#endif -char global_variable_in_bss[4096*10000]; - -//////////////////////////////// -// NOTE(allen): Inline Stepping (Built In Separate Unit) - -extern unsigned int fixed_frac_bits; -unsigned int inline_stepping_tests(void); - - -//////////////////////////////// -// NOTE(rjf): -O2 Optimized Code (Built In Separate Unit) - -void optimized_build_eval_tests(void); -void optimized_struct_parameters_eval_tests(void); - -//////////////////////////////// -// NOTE(allen): Type Coverage Eval - -#include - -struct Basics{ - char a; - unsigned char b; - short c; - unsigned short d; - int e; - unsigned int f; - long long g; - unsigned long long h; - float i; - double j; - - int z; -}; - -struct Basics_Stdint{ - int8_t a; - uint8_t b; - int16_t c; - uint16_t d; - int32_t e; - uint32_t f; - int64_t g; - uint64_t h; - float i; - double j; -}; - -struct Pair{ - int x; - float y; -}; - -struct Fixed_Array{ - Pair pairs[10]; - int count; -}; - -struct Dynamic_Array{ - Pair *pairs; - int count; -}; - -struct Struct_With_Embedded_Arrays{ - int x; - float y; - Pair pairs[10]; - char z; -}; - -typedef unsigned int Custom_Index_Type; - -typedef void Function_No_Params_Type(void); -typedef void Function_Few_Params_Type(Pair *pairs, int count, Function_No_Params_Type *no_params_type); - -static Function_No_Params_Type *ty_no_params = 0; -static Function_Few_Params_Type *ty_few_params = 0; - -struct Callback{ - Function_Few_Params_Type *few_params; - Function_No_Params_Type *no_params; - Pair pair; -}; - -union Vector_R2{ - struct{ - float x; - float y; - }; - float v[2]; -}; - -enum Kind{ - Kind_None, - Kind_First, - Kind_Second, - Kind_Third, - Kind_Fourth, - Kind_COUNT, -}; - -enum Flag{ - Flag_None = 0, - Flag_First = 1, - Flag_Second = 2, - Flag_Third = 4, - Flag_Fourth = 8, - Flag_AllMoreNarrow = 0xFF, - Flag_AllNarrow = 0xFFFF, - Flag_All = 0xFFFFFFFF, -}; - -struct Has_Enums{ - Kind kind; - Flag flags; -}; - -struct Discriminated_Union{ - Kind kind; - union{ - struct{ - int x; - int y; - Vector_R2 vector; - } first; - Pair second; - struct{ - Function_Few_Params_Type *few_params; - Pair pairs[4]; - } third; - struct{ - Kind sub_kind; - Flag flags; - } fourth; - }; -}; - -struct Linked_List{ - Linked_List *next; - Linked_List *prev; - int x; -}; - -enum{ - Anonymous_A, - Anonymous_B, - Anonymous_C, - Anonymous_D, -}; - -typedef Kind Alias1; -typedef Flag Alias2; -typedef Has_Enums Alias3; -typedef Discriminated_Union Alias4; - -struct Has_A_Pre_Forward_Reference{ - struct Gets_Referenced_Forwardly *pointer; -}; - -struct Gets_Referenced_Forwardly{ - int x; - int y; -}; - -struct Has_A_Post_Forward_Reference{ - struct Gets_Referenced_Forwardly value; -}; - -struct TypeWithMemberFunction -{ - int x; - int y; - int z; - char *name; - __declspec(noinline) void SetInfo(int _x, int _y, char *_name) - { - x = _x; - y = _y; - z = 0; - name = _name; - OutputDebugStringA("setting info\n"); - } -}; - -static void -no_params1(void){ - -} - -static void -few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){ - -} - -static 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}; - - char string[] = "Hello World!"; - char longer_text[] = - "Suppose there was some text\n" - "With multiple lines in it\r\n" - "\t> What ways might it be rendered?\n" - "\t> How would it deal with line endings?\r\n"; - wchar_t a_wide_string[] = - L"This is a string, but instead of being encoded in a stream of bytes,\n" - L"it is encoded in a stream of 2-byte packages!\n"; - - void *pointer = &basics; - Basics *pointer_to_basics = &basics; - Basics **pointer_to_pointer_to_basics = &pointer_to_basics; - - Fixed_Array fixed = { - { - { 3, 4.f}, - { 5, 6.f}, - { 7, 8.f}, - { 9, 10.f}, - {11, 12.f}, - {13, 14.f}, - {15, 16.f}, - {17, 18.f}, - {19, 20.f}, - }, - 9 - }; - Pair memory_[] = { - {100, 1.f}, - {101, 2.f}, - {102, 4.f}, - {103, 8.f}, - {104, 16.f}, - {105, 32.f}, - }; - Dynamic_Array dynamic = { - memory_, - 6 - }; - - raddbg_pin(basics); - raddbg_pin(fixed); - raddbg_pin(pointer); - - Struct_With_Embedded_Arrays swea = {0}; - { - swea.x = 4; - swea.y = 23.5f; - swea.pairs[0].x = 100; - swea.pairs[0].y = 123.f; - swea.pairs[2].x = 300; - swea.pairs[2].y = 323.f; - swea.pairs[5].x = 600; - swea.pairs[5].y = 623.f; - swea.z = 'z'; - } - - Struct_With_Embedded_Arrays *swea_ptr = &swea; - int access_via_ptr_member = swea_ptr->x; - - Custom_Index_Type custom_index = 42; - Custom_Index_Type more_custom_indices[] = { - 04,13,22,31,40 - }; - - Function_No_Params_Type *ptr_no_params = no_params1; - Function_No_Params_Type **ptr_ptr_no_params = &ptr_no_params; - Function_Few_Params_Type *ptr_few_params = few_params1; - Function_Few_Params_Type **ptr_ptr_few_params = &ptr_few_params; - Callback callback = {few_params1, no_params1, {1, 2.f}}; - - Vector_R2 vector = {1.f, 2.f}; - - Has_Enums has_enums = {(Kind)4, (Flag)7}; - - Discriminated_Union discriminated_union = {Kind_First}; - discriminated_union.first.x = 16; - discriminated_union.first.y = 8; - discriminated_union.first.vector.x = 4.f; - discriminated_union.first.vector.y = 2.f; - - Linked_List list = {&list, &list, 0}; - - Alias1 a1 = has_enums.kind; - Alias2 a2 = has_enums.flags; - Alias3 a3 = has_enums; - Alias4 a4 = discriminated_union; - - Has_A_Pre_Forward_Reference r1 = {0}; - Has_A_Post_Forward_Reference r2 = {0}; - - Basics &basics_ref = basics; - const Basics *basics_const_ptr = &basics; - const Basics &basics_const_ref = basics; - - union - { - int x; - char y[4]; - } integer_slicing = {123456789}; - - typedef struct stks - { - void *left; - size_t len; - } stks; - stks stks_test[256] = {0}; - stks *stks_first = &stks_test[0]; - stks *stks_ptr = stks_first + 8; - - TypeWithMemberFunction twmf = {0}; - twmf.SetInfo(123, 456, "foobar"); - - TestFunction *function = mule_get_module_function("dll_type_eval_tests"); - function(); - - int abc = 0; - for(int i = 0; i < 1000; i += 1) - { - if(i == 500) - { - abc+= 1; - } - int a = i + abc; - int b = a*5; - } - - char *names[] = - { - "samwise gamgee", "mithrandir", "grima wormtongue", "theodred", "theoden", "eomer", "eowyn", - "arwen", "sauron", "baggins", "proudfoot", "hardbottle", "bag end", "hobbiton", - "bree", "imladris", "isengard", "moria", "mount doom", "helm's deep", "bracegirdle", - "buckleberry ferry", "amun sul", "frodo", "bilbo", "buckland", "fangorn", "elrond", - "numenor", "treebeard", "shadowfax", "brego", "erod", "azufel", "dunedain", - "saruman", "aragorn", "gandalf", "meriadoc brandybuck", "peregrine took", "faramir", "boromir", - "ecthelion", "denethor", "mithrandil", "isildur", "haldir", "elessar", "elendil", - "dead marsh", "rohan", "gondor", "anarion", "earendil", "cirith ungol", "minas morghul", - "minas tirith", "barad-dur", "rivendell", "pellenor", "ithilien", "anduril", "narsil", - "edoras", "mordor", "osgiliath", - }; - - for(int i = 0; i < sizeof(names)/sizeof(names[0]); i += 1) - { - OutputDebugStringA(names[i]); - OutputDebugStringA("\n"); - } - - const int32_t x1 = 3; - const int32_t y1 = -10; - const int32_t z1 = x1 + y1; - - int x = (int)(Anonymous_D); -} - -//////////////////////////////// -// NOTE(allen): Mutating Variables Eval - -static const int con_some_constant = 4; -static const float con_some_constant_f = 0.04f; - -static int mut_x = 0; -static int mut_y; -static int mut_xarray[4] = {0, 1, 2, 3}; -static int *mut_xptr; - -static float mut_f = 0; -static float mut_g; -static float mut_farray[4] = {0.5f, 1.5f, 2.5f, 3.5f}; -static float *mut_fptr; - -static float mut_arrayarray[3][3]; - -static Linked_List mut_link; - -static void -mutate_in_function(int *array, int count){ - for (int i = 0; i < count; i += 1){ - array[i] += 1; - } - - for (int i = 0; i < 4; i += 1){ - mut_farray[i] += 1.f; - } -} - -static void -mutating_variables_eval_tests(void){ - //////////////////////////////// - // NOTE(allen): Basics - - int array_literal[10] = { - 10, 20, 30, 40, 50, 60, 70, 80, 90, - }; - - Basics struct_literal = { - -1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001, - }; - - array_literal[0] = struct_literal.e = 9; - - int x = mut_x; - int y = x + 10 + con_some_constant; - mut_y = y; - mut_xarray[0] += 0; - mut_xarray[1] += x; - mut_xarray[2] += y; - mut_xarray[3] += x + y; - - mut_xptr = &mut_xarray[2]; - - *mut_xptr -= (y - x)/2; - *(mut_xptr - 1) += 11; - - float f = mut_f + .333f + con_some_constant_f; - float g = f + 10.1f; - mut_g = g; - mut_farray[0] += 0.000001f; - mut_farray[1] += f; - mut_farray[2] += g; - mut_farray[3] += f + g; - - mut_fptr = &mut_farray[3]; - - *mut_fptr -= (g - f)*0.5f; - *(mut_fptr - 1) += 1.f; - - float a = 0.777f; - for (int i = 0; i < 3; i += 1){ - float b = a*a - 1.f; - for (int j = 0; j < 3; j += 1){ - mut_arrayarray[i][j] = b; - b += 0.111f; - } - a += 0.333f; - } - - //////////////////////////////// - // NOTE(allen): Changes in functions - - mutate_in_function(array_literal, 10); - - mutate_in_function(array_literal, 10); - - //////////////////////////////// - // NOTE(allen): Changes through pointers - - Basics basic = struct_literal; - Basics advanced = struct_literal; - - Basics *struct_pointer = &basic; - - basic.a += 1; - advanced.a += 1; - struct_pointer->a += 1; - - struct_pointer = &advanced; - - basic.b += 1; - advanced.b += 1; - struct_pointer->b += 1; - - Linked_List links[5]; - for (int i = 0; i < 5; i += 1){ - links[i].next = &links[i + 1]; - links[i].prev = &links[i - 1]; - links[i].x = i; - } - links[0].prev = 0; - links[4].next = &mut_link; - mut_link.prev = &links[4]; - mut_link.next = 0; - mut_link.x = 1000; - - Linked_List *link_ptr = links; - - link_ptr = link_ptr->next; - - link_ptr = &links[4]; - link_ptr = &mut_link; - - Linked_List sentinel = {0}; - sentinel.x = -1; - sentinel.next = &links[0]; - links[0].prev = &sentinel; - sentinel.prev = &mut_link; - mut_link.next = &sentinel; - - link_ptr = &sentinel; -} - -//////////////////////////////// -// NOTE(allen): Global Eval - -struct NestedNodeInner{ - unsigned int small0; - unsigned int small1; - unsigned int big0; - unsigned int big1; -}; - -struct NestedNodeOuter{ - NestedNodeOuter *next; - NestedNodeInner *inner_nodes; - unsigned int inner_node_count; -}; - -static void -nested_types_eval_tests(void){ - // doing some setup - NestedNodeOuter *outer1 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); - NestedNodeOuter *outer2 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); - NestedNodeOuter *outer3 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); - - outer1->next = outer2; - outer2->next = outer3; - outer3->next = 0; - - outer1->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); - outer1->inner_node_count = 10; - - outer2->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); - outer2->inner_node_count = 10; - - outer3->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); - outer3->inner_node_count = 10; - - for (unsigned int i = 0; i < 10; i += 1){ - outer1->inner_nodes[i].small0 = i; - outer1->inner_nodes[i].small1 = 2*i; - outer1->inner_nodes[i].big0 = 0xFFFFFF + 0xF*i; - outer1->inner_nodes[i].big1 = 0xFFFFFF + 0xFF*i; - - outer2->inner_nodes[i].small0 = 1 + i; - outer2->inner_nodes[i].small1 = 3*i; - outer2->inner_nodes[i].big0 = 0x1000000 + 0x10*i; - outer2->inner_nodes[i].big1 = 0x1000000 + 0x101*i; - - outer3->inner_nodes[i].small0 = 2 + i; - outer3->inner_nodes[i].small1 = 4*i; - outer3->inner_nodes[i].big0 = 0x8000000 + 0xF0*i; - outer3->inner_nodes[i].big1 = 0x8000000 + 0xF0F*i; - } - - // okay eval it here - int x = 0; -} - -//////////////////////////////// -// NOTE(rjf): Struct Parameters Eval - -static void -struct_parameter_helper(Basics basics) -{ - basics.a += 1; - basics.a += 1; - basics.a += 1; -} - -static void -struct_parameters_eval_tests(void) -{ - Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; - struct_parameter_helper(basics); -} - -//////////////////////////////// -// NOTE(allen): Global Eval - -static int g_abc = 100; -static float g_xyz = 21.f; -static Alias1 g_kind = Kind_First; - -// TODO(allen): more global test types - -static void -complicated_global_mutation(int *x){ - *x = (int)g_xyz; -} - -static void -cross_unit_global_mutation(void){ - fixed_frac_bits = 10; -} - -static void -global_eval_tests(void){ - g_abc = 11*11; - g_xyz = (float)g_abc - 21.f; - - int z = g_abc; - complicated_global_mutation(&z); - - complicated_global_mutation(&g_abc); - - if (g_kind == Kind_First){ - g_abc -= 1; - g_kind = Kind_None; - } - - cross_unit_global_mutation(); - - static int l_abc = 200; - static float l_xyz = 42.f; - static Alias1 l_kind = Kind_Second; - - l_abc = g_abc*2; - l_xyz = g_xyz*2; - l_kind = (Alias1)(g_kind + 1); -} - -//////////////////////////////// -// NOTE(allen): Return Eval - -static int -complicated_return_expression(void){ - int x = 171717; - return((x % 13) <= 5?(x % 19)*11:(x - 500)%200); -} - -static void -return_eval_tests(void){ - complicated_return_expression(); -} - -//////////////////////////////// -// NOTE(allen): TLS Eval - -#if _WIN32 -# define thread_var __declspec(thread) -#else -# define thread_var __thread -#endif - -thread_var int tls_a = 100; -thread_var int tls_b = 999; - -static void -tls_eval_tests(void){ - tls_a = (tls_a + tls_b)/2; - tls_b = tls_b - tls_a; - - TestFunction *dll_tls_eval_test = mule_get_module_function("dll_tls_eval_test"); - if (dll_tls_eval_test != 0){ - dll_tls_eval_test(); - } -} - -//////////////////////////////// -// NOTE(allen): Complicated Type Coverage Eval - -struct Complicated_Type_Members{ - int x600[2][2][2][2]; - int *x601[2][2][2][2]; - int (*x602)[2][2][2][2]; - int (*x603[2])[2][2][2]; - int (*(*x604[2])[2])[2][2]; - int (*(*(*x605[2])[2])[2])[2]; - - int (*x33[2])(void); - int (*x34[3])(void); - int (*x35[2][2])(void); - - int (*(*z33)(void))[2]; - int (*(*z34)(void))[3]; - int (*(*z35)(void))[2][2]; - - int (*(*f2)(void))(void); - int (*(*(*f3)(void))(void))(void); - int (*(*f4)(int))(void); - int (*(*f5)(void))(int); - int (*(*f6)(int))(int); - int (*(*(*f7_growing)(char))(short))(int); - int (*(*(*f7_shrinking)(int))(short))(char); -}; - -static void -complicated_type_coverage_tests(void){ - Complicated_Type_Members m = {0}; - - int x1 = {0}; - int *x2 = {0}; - int **x3 = {0}; - - int x4a[2] = {0}; - int *x4[2] = {0}; - int x5a[3] = {0}; - int *x5[3] = {0}; - int *x6[2][2] = {0}; - int (*x7)[2] = {0}; - int (*x8)[3] = {0}; - int (*x9)[2][2] = {0}; - - int x600[2][2][2][2] = {0}; - int *x601[2][2][2][2] = {0}; - int (*x602)[2][2][2][2] = {0}; - int (*x603[2])[2][2][2] = {0}; - int (*(*x604[2])[2])[2][2] = {0}; - int (*(*(*x605[2])[2])[2])[2] = {0}; - - int x606_growing [2][3][4][5] = {0}; - int x606_shrinking[5][4][3][2] = {0}; - - int (*(*(*x607_growing [2])[3])[4])[5] = {0}; - int (*(*(*x607_shrinking[5])[4])[3])[2] = {0}; - - int **x10[2] = {0}; - int **x11[3] = {0}; - int **x12[2][2] = {0}; - int *(*x13)[2] = {0}; - int *(*x14)[3] = {0}; - int *(*x15)[2][2] = {0}; - int **x16[2] = {0}; - int **x17[3] = {0}; - int **x18[2][2] = {0}; - - int (*y1[2])[2] = {0}; - int (*y2[3])[2] = {0}; - int (*y3[2][2])[2] = {0}; - int (*y4[2])[3] = {0}; - int (*y5[3])[3] = {0}; - int (*y6[2][2])[3] = {0}; - int (*y7[2])[2][2] = {0}; - int (*y8[3])[2][2] = {0}; - int (*y9[2][2])[2][2] = {0}; - - int (*x19)(void) = {0}; - int (*x20)(int) = {0}; - int (*x21)(int, int) = {0}; - int (*x22)(int*, int) = {0}; - int (*x23)(int**, int) = {0}; - int (*x24)(int**, int*) = {0}; - int (*x25)(int**, int**) = {0}; - - int *(*x26)(void) = {0}; - int *(*x27)(int) = {0}; - int *(*x28)(int, int) = {0}; - int *(*x29)(int*, int) = {0}; - int *(*x30)(int**, int) = {0}; - int *(*x31)(int**, int*) = {0}; - int *(*x32)(int**, int**) = {0}; - - int (*x33[2])(void) = {0}; - int (*x34[3])(void) = {0}; - int (*x35[2][2])(void) = {0}; - - int (*x36[2])(int) = {0}; - int (*x37[3])(int) = {0}; - int (*x38[2][2])(int) = {0}; - - int (*x39[2])(int, int) = {0}; - int (*x40[3])(int, int) = {0}; - int (*x41[2][2])(int, int) = {0}; - - int (*x42[2])(int*, int) = {0}; - int (*x43[3])(int*, int) = {0}; - int (*x44[2][2])(int*, int) = {0}; - - int (*x45[2])(int**, int) = {0}; - int (*x46[3])(int**, int) = {0}; - int (*x47[2][2])(int**, int) = {0}; - - int (*x48[2])(int**, int*) = {0}; - int (*x49[3])(int**, int*) = {0}; - int (*x50[2][2])(int**, int*) = {0}; - - int (*x51[2])(int**, int**) = {0}; - int (*x52[3])(int**, int**) = {0}; - int (*x53[2][2])(int**, int**) = {0}; - - int (*(*z33)(void))[2] = {0}; - int (*(*z34)(void))[3] = {0}; - int (*(*z35)(void))[2][2] = {0}; - - int (*(*z36)(int))[2] = {0}; - int (*(*z37)(int))[3] = {0}; - int (*(*z38)(int))[2][2] = {0}; - - int (*(*z39)(int, int))[2] = {0}; - int (*(*z40)(int, int))[3] = {0}; - int (*(*z41)(int, int))[2][2] = {0}; - - int (*(*z42)(int*, int))[2] = {0}; - int (*(*z43)(int*, int))[3] = {0}; - int (*(*z44)(int*, int))[2][2] = {0}; - - int (*(*z45)(int**, int))[2] = {0}; - int (*(*z46)(int**, int))[3] = {0}; - int (*(*z47)(int**, int))[2][2] = {0}; - - int (*(*z48)(int**, int*))[2] = {0}; - int (*(*z49)(int**, int*))[3] = {0}; - int (*(*z50)(int**, int*))[2][2] = {0}; - - int (*(*z51)(int**, int**))[2] = {0}; - int (*(*z52)(int**, int**))[3] = {0}; - int (*(*z53)(int**, int**))[2][2] = {0}; - - int (*(*z303[2])(void)) = {0}; - int (*(*z304[3])(void)) = {0}; - int (*(*z305[2][2])(void)) = {0}; - - int (*(*z306[2])(int)) = {0}; - int (*(*z307[3])(int)) = {0}; - int (*(*z308[2][2])(int)) = {0}; - - int (*(*z309[2])(int, int)) = {0}; - int (*(*z400[3])(int, int)) = {0}; - int (*(*z401[2][2])(int, int)) = {0}; - - int (*(*z402[2])(int*, int)) = {0}; - int (*(*z403[3])(int*, int)) = {0}; - int (*(*z404[2][2])(int*, int)) = {0}; - - int (*(*z405[2])(int**, int)) = {0}; - int (*(*z406[3])(int**, int)) = {0}; - int (*(*z407[2][2])(int**, int)) = {0}; - - int (*(*z408[2])(int**, int*)) = {0}; - int (*(*z409[3])(int**, int*)) = {0}; - int (*(*z500[2][2])(int**, int*)) = {0}; - - int (*(*z501[2])(int**, int**)) = {0}; - int (*(*z502[3])(int**, int**)) = {0}; - int (*(*z503[2][2])(int**, int**)) = {0}; - - int (*(*f2)(void))(void) = {0}; - int (*(*(*f3)(void))(void))(void) = {0}; - int (*(*f4)(int))(void) = {0}; - int (*(*f5)(void))(int) = {0}; - int (*(*f6)(int))(int) = {0}; - int (*(*(*f7_growing)(char))(short))(int) = {0}; - int (*(*(*f7_shrinking)(int))(short))(char) = {0}; - - int (*f8)(int (*)(void)) = {0}; - int (*f9)(void (*)(int)) = {0}; - void (*f10)(int (*)(int)) = {0}; - int (*f11)(int, int (*)(void)) = {0}; - int (*f12)(int (*)(void), int) = {0}; - int (*f13)(int (*)(void), int (*)(void)) = {0}; - - int (*f14)(int (*)(void)) = {0}; - int (*f15)(int (*)(int (*)(void))) = {0}; - int (*f16)(int (*)(int (*)(int (*)(void)))) = {0}; - int (*f17)(int (*)(int (*)(int (*)(int (*)(void))))) = {0}; - - int (*f18)(int (*)(void)) = {0}; - int (*f19)(int (*(*)(void))(void)) = {0}; - int (*f20)(int (*(*(*)(void))(void))(void)) = {0}; - int (*f21)(int (*(*(*(*)(void))(void))(void))(void)) = {0}; - - int (*(*(*(*f22)(void))(void))(void))(void) = {0}; - int (*(*(*(*f23)(int [2]))(void))(void))(void) = {0}; - int (*(*(*(*f24)(int *[2]))(int [3]))(void))(void) = {0}; - int (*(*(*(*f25)(int (*)[2]))(int *[3]))(int [4]))(void) = {0}; - int (*(*(*(*f26)(int **(**)[2]))(int (*)[3]))(int *[4]))(int [5]) = {0}; - - int x = 0; -} - -//////////////////////////////// -// NOTE(allen): Extended Type Coverage Eval - -template -struct Template_Example{ - X x; - int y; -}; - -template -struct Template_Example2{ - X x; - Y y; -}; - -template -struct Template_Example3{ - X x; - Y y; - Template_Example3(X x, Y y) - { - this->x = x; - this->y = y; - } - ~Template_Example3() - { - int x = 2; - int y = 5; - int z = x + y; - } -}; - -struct SingleInheritanceBase -{ - int x; - int y; -}; - -struct SingleInheritanceDerived : SingleInheritanceBase -{ - int z; - int w; -}; - -struct Has_Members{ - int a; - int b; - uint64_t c; - uint64_t d; - Basics bas; - - int w(void){ return a; } - int x(void){ return b; } - uint64_t y(void){ return c; } - uint64_t z(void){ return d; } - Basics bas_f(void){ return bas; } -}; - -struct Has_Static_Members{ - int a; - int b; - static uint64_t c; - static uint64_t d; - - int w(void){ return a; } - int x(void){ return b; } - static uint64_t y(void){ return c; } - static uint64_t z(void){ return d; } -}; - -uint64_t Has_Static_Members::c = 0; -uint64_t Has_Static_Members::d = 0; - -struct Pointer_To_Member{ - int Has_Members::*member_ptr_int; - uint64_t Has_Members::*member_ptr_u64; - Basics Has_Members::*member_ptr_bas; - - int (Has_Members::*method_ptr_int)(void); - uint64_t (Has_Members::*method_ptr_u64)(void); - Basics (Has_Members::*method_ptr_bas)(void); -}; - -struct Has_Sub_Types{ - struct Sub_Type1{ - int x; - int y; - }; - - struct Sub_Type2{ - float x; - float y; - }; - - Sub_Type1 a; - Sub_Type2 b; -}; - -struct Conflicting_Type_Names{ - struct Sub_Type1{ - uint64_t z; - }; - - struct Sub_Type2{ - int64_t z; - }; - - Sub_Type1 a; - Sub_Type2 b; -}; - -struct Has_Private_Sub_Types{ - Has_Private_Sub_Types(char x1, char y1, - float x2, int y2, - int x3, float y3){ - this->a.x = x1; - this->a.y = y1; - this->b.x = x2; - this->b.y = y2; - this->c.x = x3; - this->c.y = y3; - } - - struct Public_Sub_Type{ - char x; - char y; - }; - Public_Sub_Type a; - - protected: - struct Protected_Sub_Type{ - float x; - int y; - }; - Protected_Sub_Type b; - - private: - struct Private_Sub_Type{ - int x; - float y; - }; - Private_Sub_Type c; -}; - -struct Vtable_Parent{ - virtual void a_virtual_function(void) = 0; - virtual void b_virtual_function(void) = 0; - virtual void c_virtual_function(void) = 0; - - void a_virtual_function(int r){ - for (int i = 0; i < r; i += 1){ - a_virtual_function(); - } - } -}; - -struct Vtable_Child : Vtable_Parent{ - int x; - int y; - - Vtable_Child(int a, int b){ - x = a; - y = b; - } - virtual void a_virtual_function(void){ - x = 0; - }; - virtual void b_virtual_function(void){ - y = 0; - }; - virtual void c_virtual_function(void){ - x = y; - }; -}; - -struct Vinheritance_Base{ - int x; - int y; - - virtual void a_virtual_function(void){ - x = 0; - }; - virtual void b_virtual_function(void){ - y = 0; - }; - virtual void x_virtual_function(void){ - y = x; - }; -}; - -struct Vinheritance_MidLeft : virtual Vinheritance_Base{ - float left; - - virtual void c1_virtual_function(void){ - left = 0; - }; - virtual void c2_virtual_function(void){ - left = 0; - }; -}; - -struct Vinheritance_MidRight : virtual Vinheritance_Base{ - float right; - - virtual void d_virtual_function(void){ - right = 0; - }; -}; - -struct Vinheritance_Child : Vinheritance_MidLeft, Vinheritance_MidRight{ - char *name; - - virtual void a_virtual_function(void){ - x = 1; - }; - virtual void c1_virtual_function(void){ - left = 1; - }; -}; - -struct Minheritance_Base{ - int x; - int y; -}; - -struct Minheritance_MidLeft : Minheritance_Base{ - float left; -}; - -struct Minheritance_MidRight : Minheritance_Base{ - float right; -}; - -struct Minheritance_Child : Minheritance_MidLeft, Minheritance_MidRight{ - char *name; -}; - -struct Pure -{ - virtual ~Pure() = default; - virtual void Foo() = 0; -}; - -struct PureChild : Pure -{ - virtual ~PureChild() = default; - virtual void Foo() {a += 1;} - double a = 0; -}; - -struct Base -{ - int x; - int y; - int z; - virtual ~Base() = default; - virtual void Foo() = 0; -}; - -struct Derived : Base -{ - int r; - int g; - int b; - int a; - virtual ~Derived() = default; - virtual void Foo() {a += 1;} -}; - -struct DerivedA : Base -{ - float a; - float b; - virtual void Foo() {a += 1;} - virtual ~DerivedA() = default; -}; - -struct DerivedB : Base -{ - double c; - double d; - virtual void Foo() {c += 1;} - virtual ~DerivedB() = default; -}; - -struct NonVirtualBase -{ - int x; - int y; - int z; -}; - -struct NonVirtualDerived : NonVirtualBase -{ - int r; - int g; - int b; - int a; -}; - -struct OverloadedMethods{ - int x; - int cool_method(void){ - return(x); - } - int cool_method(int z){ - int r = x; - x = z; - return(r); - } - void cool_method(int y, int z){ - if (x < z){ - x = y; - } - else{ - x = z; - } - } -}; - -struct HasStaticConstMembers -{ - int a; - int b; - static int c; - static int d; - static const int e = 789; - static const int f = 101112; -}; - -int HasStaticConstMembers::c = 123; -int HasStaticConstMembers::d = 456; - -struct Has_A_Constructor{ - int n; - int d; - Has_A_Constructor(int a, int b){ - int gcd = 1; - { - int x = a; - int y = b; - if (x < y){ - y = a; - x = b; - } - for (;y > 0;){ - int z = x%y; - x = y; - y = z; - } - gcd = x; - } - n = a/gcd; - d = b/gcd; - } - - static int N; - static int D; - ~Has_A_Constructor(){ - int m = N*d + n*D; - int e = d*D; - N = m; - D = d; - } -}; - -int Has_A_Constructor::N = 0; -int Has_A_Constructor::D = 1; - -struct Constructor_Gotcha_Test{ - int x; - int y; - void Constructor_Gotcha(void){ - x = y = 0; - } -}; - -struct Has_A_Friend{ - friend struct Modifies_Other; - int get_x(void){ return x; } - int get_y(void){ return y; } - - private: - int x; - int y; -}; - -struct Modifies_Other{ - int x; - int y; - - void talk_to_friend(Has_A_Friend *other){ - other->x = y; - other->y = x; - } -}; - -namespace UserNamespace{ - namespace SubA{ - struct Foo{ - int x; - int y; - }; - }; - namespace SubB{ - struct Foo{ - float u; - float v; - }; - }; - - SubA::Foo foo_a = {10, 20}; - SubB::Foo foo_b = {0.1f, 0.05f}; - - static void namespaced_function(void){ - foo_a.x = (int)(foo_a.y*foo_b.u); - foo_b.v = (float)(foo_a.x*foo_b.v); - } -}; - -static void -call_with_pass_by_reference(int &x){ - x += 1; -} - -static void -call_with_pass_by_const_reference(const int &x){ - int y = x; -} - -static void -extended_type_coverage_eval_tests(void){ - //////////////////////////////// - // NOTE(allen): Extensions to base type system. - { - int x = 0; - const int *x_ptr = &x; - int *const x_cptr = &x; - - call_with_pass_by_reference(x); - - call_with_pass_by_const_reference(x); - } - - //////////////////////////////// - // NOTE(allen): Extensions to user defined types - { - Template_Example temp_f = {1.f, 2}; - Template_Example temp_v = {(void*)&temp_f, 2}; - Template_Example > temp_tf = {temp_f, 2}; - Template_Example2 temp_if = {2, 1.f}; - Template_Example3 temp3_if(2, 1.f); - Template_Example3 temp3_vi((void *)&temp3_if, 1.f); - Template_Example3> temp3_itif(123, temp_if); - - SingleInheritanceDerived sid; - sid.x = 123; - sid.y = 456; - sid.z = 789; - sid.w = 999; - - Pointer_To_Member pointer_to_member = { - &Has_Members::a, &Has_Members::c, &Has_Members::bas, - &Has_Members::x, &Has_Members::z, &Has_Members::bas_f, - }; - - Has_Static_Members has_static_members = { 10, 20 }; - Has_Static_Members::c = 100; - Has_Static_Members::d = 110; - has_static_members.x(); - has_static_members.y(); - has_static_members.z(); - has_static_members.w(); - - Has_Sub_Types has_sub_types = { - {100, 200}, - {.1f, .2f}, - }; - - Conflicting_Type_Names conflicting_type_names = { - {10}, {-20}, - }; - - Has_Private_Sub_Types has_private_sub_types(1, 2, 4, 8, 16, 32); - - Vtable_Child vtable_child(1, 2); - vtable_child.a_virtual_function(); - - Vinheritance_Child vinheritance_child; - vinheritance_child.name = "foobar"; - vinheritance_child.left = 10.5f; - vinheritance_child.right = 13.0f; - vinheritance_child.x = -1; - vinheritance_child.y = -1; - - Minheritance_Child minheritance_child; - minheritance_child.name = "foobar"; - minheritance_child.left = 10.5f; - minheritance_child.right = 13.0f; - minheritance_child.Minheritance_MidLeft::x = -1; - minheritance_child.Minheritance_MidLeft::y = -1; - minheritance_child.Minheritance_MidRight::x = +1; - minheritance_child.Minheritance_MidRight::y = +1; - - Pure *child = new PureChild(); - child->Foo(); - child->Foo(); - child->Foo(); - delete child; - - Base *derived = new Derived(); - derived->Foo(); - derived->Foo(); - derived->Foo(); - delete derived; - - NonVirtualBase *non_virtual_derived = new NonVirtualDerived(); - non_virtual_derived->x += 1; - non_virtual_derived->x += 1; - non_virtual_derived->x += 1; - - Base *base_array[1024] = {0}; - for(int i = 0; i < sizeof(base_array)/sizeof(base_array[0]); i += 1) - { - if((i & 1) == 1) - { - base_array[i] = new DerivedA(); - } - else - { - base_array[i] = new DerivedB(); - } - } - - OverloadedMethods overloaded_methods; - { - overloaded_methods.x = 0; - int a = overloaded_methods.cool_method(); - overloaded_methods.cool_method(-10, 100); - int b = overloaded_methods.cool_method(100); - overloaded_methods.cool_method(b*2, a*2); - int c = overloaded_methods.cool_method(a + b); - int z = c; - } - - Has_A_Constructor construct_me(360, 25); - - Has_A_Friend has_a_friend; - - Modifies_Other modifies_other; - modifies_other.x = 57; - modifies_other.y = 66; - - modifies_other.talk_to_friend(&has_a_friend); - - int x = has_a_friend.get_x(); - int y = has_a_friend.get_y(); - int z = x; - - HasStaticConstMembers static_const_members = {0}; - static_const_members.a = 123 + HasStaticConstMembers::c * HasStaticConstMembers::e; - static_const_members.b = 456 + HasStaticConstMembers::d * HasStaticConstMembers::f; - } - - //////////////////////////////// - // NOTE(allen): Namespaces - { - UserNamespace::namespaced_function(); - } -} - -//////////////////////////////// -//~ rjf: Templated Function Eval Tests - -typedef struct TemplateArg TemplateArg; -struct TemplateArg -{ - int x; - int y; - int z; - float a; - float b; - float c; - char *name; -}; - -template static T -templated_factorial(T t) -{ - T result = t; - if(t > 1) - { - result *= templated_factorial(t-1); - } - return result; -} - -template static T -compute_template_arg_info(T t) -{ - int sum = t.x + t.y + t.z; - int size = sizeof(t); - float sum_f = t.a + t.b + t.c; - OutputDebugStringA(t.name); - return t; -} - -static void -templated_function_eval_tests(void) -{ - int int_factorial = templated_factorial(10); - float float_factorial = templated_factorial(10); - TemplateArg arg = {1, 2, 3, 4.f, 5.f, 6.f, "my template arg"}; - compute_template_arg_info(arg); - int x = 0; -} - -//////////////////////////////// -//~ NOTE(allen): C Type Coverage - -extern "C"{ -#include "mule_c.h" -} - -//////////////////////////////// -//~ rjf: Basic Inline Line Info Tests - -#if defined(_MSC_VER) -# define FORCE_INLINE __forceinline -#elif defined(__clang__) -# define FORCE_INLINE __attribute__((always_inline)) -#else -# error need force inline for this compiler -#endif - -static FORCE_INLINE void -basic_inlinee(int inlinee_param_x, int inlinee_param_y, int inlinee_param_z) -{ - OutputDebugStringA("A\n"); - OutputDebugStringA("B\n"); - OutputDebugStringA("C\n"); - OutputDebugStringA("D\n"); -} - -static void -basic_inline_tests(void) -{ - OutputDebugStringA("{\n"); - basic_inlinee(12, 34, 56); - OutputDebugStringA("}\n"); -} - -//////////////////////////////// -//~ rjf: Fancy Visualization Eval Tests - -static unsigned int -mule_bswap_u32(unsigned int x) -{ - unsigned int result = (((x & 0xFF000000) >> 24) | - ((x & 0x00FF0000) >> 8) | - ((x & 0x0000FF00) << 8) | - ((x & 0x000000FF) << 24)); - return result; -} - -static void -fancy_viz_eval_tests(void) -{ - //- rjf: windows -> GetLastError -#if _WIN32 - DWORD error_code = 0; - SetLastError(1234); - error_code = GetLastError(); - SetLastError(4567); - error_code = GetLastError(); - (void)error_code; -#endif - - //- rjf: colors - float example_color_4f32[4] = {1.00f, 0.85f, 0.25f, 1.00f}; - unsigned int example_color_u32 = 0xff6f30ff; - struct {float r, g, b, a;} example_color_struct = {0.50f, 0.95f, 0.75f, 1.00f}; - int x0 = 0; - - //- rjf: multiline text - char *long_string = ("This is an example of some very long text with line breaks\n" - "in it. This is a very common kind of data which is inspected\n" - "in the debugger while programming, and it is often a pain\n" - "when it is poorly supported.\n"); - char *code_string = ("#include \n" - "\n" - "int main(int argc, char**argv)\n" - "{\n" - " printf(\"Hello, World!\\n\");\n" - " return 0;\n" - "}\n\n"); - int x1 = 0; - raddbg_pin(long_string, "text"); - raddbg_pin(code_string, "text: (lang:c)"); - raddbg_pin(fancy_viz_eval_tests, "disasm: (arch:x64)"); - - //- rjf: bitmaps - unsigned int background_color = 0x00000000; - unsigned int main_color = 0xff2424ff; - unsigned int shine_color = 0xff5693ff; - unsigned int shadow_color = 0xff238faf; - unsigned int bg = mule_bswap_u32(background_color); - unsigned int cl = mule_bswap_u32(main_color); - unsigned int sn = mule_bswap_u32(shine_color); - unsigned int sh = mule_bswap_u32(shadow_color); - unsigned int bitmap[] = - { - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, cl, cl, bg, cl, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, cl, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, cl, sn, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, sh, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, sh, cl, cl, cl, sh, sh, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, sh, sh, sh, bg, bg, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, - bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, - }; - raddbg_pin(bitmap, "bitmap:(w:18, h:18)"); - for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) - { - unsigned int r = bitmap[i]&0x000000ff; - unsigned int a = bitmap[i]&0xff000000; - bitmap[i] = bitmap[i]>>8; - bitmap[i] &= ~0xffff0000; - bitmap[i] |= (r<<16); - bitmap[i] |= (a); - } - for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) - { - unsigned int r = bitmap[i]&0x000000ff; - unsigned int a = bitmap[i]&0xff000000; - bitmap[i] = bitmap[i]>>8; - bitmap[i] &= ~0xffff0000; - bitmap[i] |= (r<<16); - bitmap[i] |= (a); - } - for(int i = 0; i < sizeof(bitmap)/sizeof(bitmap[0]); i += 1) - { - unsigned int r = bitmap[i]&0x000000ff; - unsigned int a = bitmap[i]&0xff000000; - bitmap[i] = bitmap[i]>>8; - bitmap[i] &= ~0xffff0000; - bitmap[i] |= (r<<16); - bitmap[i] |= (a); - } - int x2 = 0; - - //- rjf: 3D geometry - float vertex_data[] = // pos.x, pos.y, pos.z, nor.x, nor.y, nor.z, tex.u, tex.v, col.r, col.g, col.b, ... - { - -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 2.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 8.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 8.0f, 0.973f, 0.480f, 0.002f, - -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 10.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 10.0f, 0.973f, 0.480f, 0.002f, - 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 10.0f, 0.973f, 0.480f, 0.002f, - 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 2.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 2.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 8.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 8.0f, 0.612f, 0.000f, 0.069f, - 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 10.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 10.0f, 0.612f, 0.000f, 0.069f, - -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 10.0f, 0.612f, 0.000f, 0.069f, - -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 2.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 2.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 8.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 8.0f, 0.000f, 0.254f, 0.637f, - -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 10.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 10.0f, 0.000f, 0.254f, 0.637f, - 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 10.0f, 0.000f, 0.254f, 0.637f, - -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 2.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 2.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 8.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 8.0f, 0.001f, 0.447f, 0.067f, - -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 10.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 10.0f, 0.001f, 0.447f, 0.067f, - 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 10.0f, 0.001f, 0.447f, 0.067f, - -0.6f, 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - -0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, - 1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, - 0.6f, 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - 0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, - -1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, - -0.6f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, - -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - 0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, - }; - unsigned int index_data[] = - { - 0, 1, 9, 9, 8, 0, 1, 2, 5, 5, 4, 1, 6, 7, 10, 10, 9, 6, 2, 3, 11, 11, 10, 2, - 12, 13, 21, 21, 20, 12, 13, 14, 17, 17, 16, 13, 18, 19, 22, 22, 21, 18, 14, 15, 23, 23, 22, 14, - 24, 25, 33, 33, 32, 24, 25, 26, 29, 29, 28, 25, 30, 31, 34, 34, 33, 30, 26, 27, 35, 35, 34, 26, - 36, 37, 45, 45, 44, 36, 37, 38, 41, 41, 40, 37, 42, 43, 46, 46, 45, 42, 38, 39, 47, 47, 46, 38, - 48, 49, 57, 57, 56, 48, 49, 50, 53, 53, 52, 49, 54, 55, 58, 58, 57, 54, 50, 51, 59, 59, 58, 50, - 60, 61, 69, 69, 68, 60, 61, 62, 65, 65, 64, 61, 66, 67, 70, 70, 69, 66, 62, 63, 71, 71, 70, 62, - 72, 73, 74, 74, 75, 72, 76, 77, 78, 78, 79, 76, 80, 81, 82, 82, 83, 80, 84, 85, 86, 86, 87, 84, - 88, 89, 90, 90, 91, 88, 92, 93, 94, 94, 95, 92, 96, 97, 98, 98, 99, 96, 100, 101, 102, 102, 103, 100, - 104, 105, 106, 106, 107, 104, 108, 109, 110, 110, 111, 108, 112, 113, 114, 114, 115, 112, 116, 117, 118, 118, 119, 116, - 120, 121, 122, 122, 123, 120, 124, 125, 126, 126, 127, 124, 128, 129, 130, 130, 131, 128, 132, 133, 134, 134, 135, 132, - 136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148, - 152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164, - }; - raddbg_pin(index_data, "geo3d: { count:(sizeof index_data/4), vtx:(vertex_data), vtx_size:(sizeof vertex_data) }"); - int x3 = 0; -} - -//////////////////////////////// -// NOTE(allen): Function Overload Resolution - -static int -overloaded_function(float y){ - int r = (int)(y + 0.5f); - return(r); -} - -static int -overloaded_function(float y, int x){ - int r = overloaded_function(y) + x; - return(r); -} - -static int -overloaded_function(int x){ - float y = (float)x; - int r = overloaded_function(y, 1); - return(r); -} - -//////////////////////////////// -// NOTE(allen): Control Flow Stepping - -static void -control_flow_stepping_tests(void){ - { - int a = 1; - if (a < 1){ - a += 1; - } - if (a < 2){ - a += 2; - } - } - - { - int a = 1; - if (a < 1) - { - a += 1; - } - if (a < 2) - { - a += 2; - } - } - - { - int a = 1; - if (a < 1) - a += 1; - if (a < 2) - a += 2; - } - - { - int a = 1; - int b = 2; - if (a <= b){ - if (a == b){ - b += 1; - } - else{ - a += 1; - } - } - else{ - if (a%2){ - a = b; - } - else{ - a = b - 1; - } - } - } - - { - int a = 1; - int b = 2; - if (a <= b) - { - if (a == b) - { - b += 1; - } - else - { - a += 1; - } - } - else - { - if (a%2) - { - a = b; - } - else - { - a = b - 1; - } - } - } - - { - int a = 1; - int b = 2; - if (a <= b) - if (a == b) - b += 1; - else - a += 1; - else - if (a%2) - a = b; - else - a = b - 1; - } - - { - int x = 0; - for (int i = 0; i < 10; i += 1){ - x += i; - } - } - - { - int x = 0; - for (int i = 0; i < 10; i += 1) - { - x += i; - } - } - - { - int x = 0; - for (int i = 0; i < 10; i += 1) - x += i; - } - - { - int x = 0; - for (int i = 0; i < 10; i += 1) x += i; - } - - { - int a = 1; - for (;a < 10;){ - switch (a){ - case 0: case 1: case 2: - { - a += 2; - }break; - - default: - case 4: - case 5: - { - a += 1; - }break; - - case 6: a += 1; break; - case 7: a += 1; - case 8: - case 9: a += 1; - } - } - } - - { - int i = 0; - while (i < 5){ - i += 1; - } - - while (i < 10) - { - i += 1; - } - - while (i < 15) - i += 1; - - while (i < 20) i += 1; - } - - { - int i = 0; - do - { - i += 1; - } while (i < 10); - } - - { - int i = 17; - - check_again: - if (i <= 1) goto done; - if ((i&1) == 0) goto even_case; - - // odd_case: - i = 3*i + 1; - - even_case: - i /= 2; - goto check_again; - - done:; - } - - { - int x = 15; - label_same_line:; x -= 1; if(x > 0) { goto label_same_line; } else { goto end_label_same_line; } - } - end_label_same_line:; -} - -//////////////////////////////// -// NOTE(allen): Indirect Call/Jump Stepping Tests - -typedef int FunctionType(int); - -static int -function_foo(int a){ - if (a < 1){ - a += 1; - } - if (a < 2){ - a += 2; - } - return(a); -} - -static int -function_bar(int x){ - for (int i = 0; i < 10; i += 1){ - x += i; - } - return(x); -} - - -static void -indirect_call_jump_stepping_tests(void){ - int z = 1; - FunctionType *ptr = function_foo; - z = ptr(z); - if ((z & 1) == 0){ - ptr = function_bar; - } - z = ptr(z); - - switch (z&7){ - case 0: - { - z += 2; - ptr = function_bar; - }break; - - case 1: - { - z += 1; - ptr = function_bar; - }break; - - case 2: - { - z *= 2; - ptr = function_bar; - }break; - - case 3: - { - z -= 10; - ptr = function_foo; - }break; - - case 4: - { - z -= 5; - ptr = function_foo; - }break; - - case 5: - { - z = z ^ 0x10; - ptr = function_foo; - }break; - - case 6: - { - z = z & ~0x10; - ptr = function_foo; - }break; - - case 7: - { - z = z | 0x10; - ptr = function_foo; - }break; - } - - z = ptr(z); -} - -//////////////////////////////// -// NOTE(rjf): alloca (Variable-Width Stack Changes) Stepping Tests - -static void -alloca_stepping_tests(void) -{ - int x = 1; - int y = 3; - int z = 5; - -#if _WIN32 - int *mem = (int *)_alloca((x+y+z)*sizeof(int)); - mem[0] = x; - mem[1] = y; - mem[2] = z; -#else - int *mem = (int *)__builtin_alloca((x+y+z)*sizeof(int)); - mem[0] = x; - mem[1] = y; - mem[2] = z; -#endif -} - -//////////////////////////////// -// NOTE(allen): Overloaded Line Stepping - -static int -function_get_integer(void){ - return(1); -} - -static void -function_with_multiple_parameters(int x, int y){ - x += y; -} - -static int -recursive_single_line(int x){ return(x <= 1?0:x + recursive_single_line(x/2)); } - -static int shared_1(int x) { return(x); } static int shared_2(int x) { return(1 + shared_1(x)); } - -static void -overloaded_line_stepping_tests(void){ - function_with_multiple_parameters(function_get_integer(), function_get_integer()); - function_with_multiple_parameters(function_get_integer(), function_get_integer()); - function_with_multiple_parameters(function_get_integer(), function_get_integer()); - - recursive_single_line(50); - recursive_single_line(50); - recursive_single_line(50); - - shared_2(5); - shared_2(5); - shared_2(5); - - function_get_integer(); shared_1(1); shared_1(2); - - if ((shared_2(10) && shared_2(-1)) || - shared_2(function_get_integer())){ - int x = 0; - } - else{ - int y = 0; - } -} - -//////////////////////////////// -// NOTE(allen): Long Jump Stepping - -#include - -static jmp_buf global_jump_buffer; -static int global_jump_x; - -static void -long_jump_from_function(void){ - int spin = 0; - for (; spin < 5; spin += 1); - longjmp(global_jump_buffer, 2); - global_jump_x = spin; -} - -static void -long_jump_wrapped_in_function(void){ - global_jump_x = 0; - int val = setjmp(global_jump_buffer); - if (val == 0){ - global_jump_x = 1; - longjmp(global_jump_buffer, 1); - } - else if (val == 1){ - if (global_jump_x == 1){ - global_jump_x = 2; - long_jump_from_function(); - } - } - else if (val == 2){ - global_jump_x = 3; - } -} - -static void -long_jump_stepping_tests(void){ - - long_jump_wrapped_in_function(); - - long_jump_wrapped_in_function(); - - long_jump_wrapped_in_function(); - -} - -//////////////////////////////// -// NOTE(allen): Recursion Stepping - -static int -recursive_call(int x){ - if (x <= 1){ - return(x); - } - - int r1 = recursive_call(x - 1); - int r2 = recursive_call(x - 2); - return(r1 + r2); -} - -static int -tail_recursive_call(int x, int m){ - if (x <= 1){ - return(m); - } - return(tail_recursive_call(x - 1, x*m)); -} - -static void -recursion_stepping_tests(void){ - - recursive_call(4); - - recursive_call(4); - - tail_recursive_call(5, 1); - - tail_recursive_call(5, 1); - -} - -//////////////////////////////// -// NOTE(rjf): Debug Strings - -static void -debug_string_tests(void) -{ -#if _WIN32 - for(int i = 0; i < 100; i += 1) - { - OutputDebugStringA("Hello, World!\n"); - } - char message[65409+1]; - memset(&message[0], '=', sizeof(message)); - for(int i = 1; i < sizeof(message); i += 128) - { - message[i] = '\n'; - } - message[sizeof(message) - 1] = 0; - OutputDebugStringA(message); -#endif -} - -//////////////////////////////// -//~ rjf: Interrupt Stepping Tests - -#include - -static void -interrupt_stepping_tests(void) -{ - __debugbreak(); - __debugbreak(); - __debugbreak(); - __debugbreak(); - for(int i = 0; i < 1000; i += 1) - { - if(i == 999) - { - __debugbreak(); - } - } - for(int i = 0; i < 1000; i += 1) - { - if(i == 999) - { - assert(0); - } - } - int x = 0; -} - -//////////////////////////////// -//~ rjf: JIT Stepping Tests - -static void -jit_stepping_tests(void) -{ - OutputDebugString("A\n"); - VOID *code = VirtualAlloc(0, 0x1000, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); - *((uint32_t*)code) = 0xC39090CC; - ((void (__fastcall *)()) code)(); - OutputDebugString("B\n"); -} - -//////////////////////////////// -// NOTE(allen): Exception Stepping - -int *global_null_read_pointer = 0; -static void -trip(void){ - *global_null_read_pointer = 0; -} - -static void -cpp_exception_in_function(void){ - int v = 0; - try{ - throw 1; - } - catch (...){ - v = 1; - } -} - -static void -cpp_throw_in_function(void){ - throw 1; -} - -static void -win32_exception_in_function(void){ -#if _WIN32 - int v = 0; - __try{ - trip(); - v = 1; - } - __except (EXCEPTION_EXECUTE_HANDLER){ - v = 2; - } - - v = 3; - __try{ - trip(); - v = 4; - } - __except (EXCEPTION_EXECUTE_HANDLER){ - v = 5; - } -#endif -} - -static void -cpp_recursive_exception(int x){ - try{ - if (x > 1){ - throw 1; - } - } - catch (...){ - x -= 1; - cpp_recursive_exception(x); - x += 1; - } -} - -static void -win32_recursive_exception(int x){ -#if _WIN32 - __try{ - if (x > 1){ - throw 1; - } - } - __except (EXCEPTION_EXECUTE_HANDLER){ - x -= 1; - win32_recursive_exception(x); - x += 1; - } -#endif -} - -static void -exception_stepping_tests(void){ - { - int v = 0; - try{ - throw 1; - } - catch (...){ - v = 1; - } - } - - { - int v = 0; - try{ - cpp_throw_in_function(); - } - catch (...){ - v = 1; - } - } - - cpp_exception_in_function(); - cpp_exception_in_function(); - -#if _WIN32 - win32_exception_in_function(); - win32_exception_in_function(); -#endif - - // NOTE(allen): Exception in catch tests - { - int v = 0; - try{ - v = 1; - throw 1; - } - catch (...){ - try{ - v = 2; - throw 2; - } - catch (...){ - v = 3; - } - } - } - - { - int v = 0; - try{ - v = 1; - throw 1; - } - catch (...){ - cpp_exception_in_function(); - } - } - -#if _WIN32 - { - int v = 0; - try{ - v = 1; - throw 1; - } - catch (...){ - win32_exception_in_function(); - } - } -#endif - - cpp_recursive_exception(4); - cpp_recursive_exception(4); - cpp_recursive_exception(4); - -#if _WIN32 - win32_recursive_exception(4); - win32_recursive_exception(4); - win32_recursive_exception(4); -#endif - - // NOTE(allen): Try in try tests - { - int v = 0; - try{ - try{ - v = 1; - throw 1; - } - catch (...){ - v = 2; - } - throw 2; - } - catch (...){ - v = 3; - } - } - - { - int v = 0; - try{ - try{ - v = 1; - cpp_throw_in_function(); - } - catch (...){ - v = 2; - } - throw 2; - } - catch (...){ - v = 3; - } - } - - { - int v = 0; - try{ - cpp_exception_in_function(); - throw 2; - } - catch (...){ - v = 3; - } - } - -#if _WIN32 - { - int v = 0; - try{ - win32_exception_in_function(); - throw 2; - } - catch (...){ - v = 3; - } - } -#endif - -} - -typedef void (*callback_t)(int a); -static void -dynamic_step_test(void){ -#if _WIN32 -#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( _M_AMD64 ) - void *page = VirtualAlloc(0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); - char *ptr = (char*)page; - *ptr++ = 0x51; // push rcx - *ptr++ = 0x59; // pop rcx - *ptr++ = 0xC3; // ret - callback_t cb = (callback_t)page; - cb(1); -#endif -#endif -} - -//////////////////////////////// - -int -mule_main(int argc, char** argv){ - mule_init(); - - // NOTE(allen): Eval Tests - type_coverage_eval_tests(); - - mutating_variables_eval_tests(); - - nested_types_eval_tests(); - - struct_parameters_eval_tests(); - - global_eval_tests(); - - return_eval_tests(); - - tls_eval_tests(); - - complicated_type_coverage_tests(); - - extended_type_coverage_eval_tests(); - - templated_function_eval_tests(); - - c_type_coverage_eval_tests(); - - c_type_with_bitfield_usage(); - - optimized_build_eval_tests(); - - optimized_struct_parameters_eval_tests(); - - fancy_viz_eval_tests(); - - // NOTE(allen): Stepping Tests - control_flow_stepping_tests(); - - indirect_call_jump_stepping_tests(); - - alloca_stepping_tests(); - - basic_inline_tests(); - - inline_stepping_tests(); - - overloaded_line_stepping_tests(); - - overloaded_function(100); - - dynamic_step_test(); - - long_jump_stepping_tests(); - - recursion_stepping_tests(); - - debug_string_tests(); - - jit_stepping_tests(); - - interrupt_stepping_tests(); - - exception_stepping_tests(); - - return(0); -} - - +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +/* +** Program to run in debugger organized to provide tests for +** stepping, breakpoints, evaluation, cross-module calls. +*/ + +#include +#include +#include +#if !_WIN32 +# define RADDBG_MARKUP_STUBS +#endif +#define RADDBG_MARKUP_IMPLEMENTATION +#include "lib_raddbg_markup/raddbg_markup.h" + +//////////////////////////////// +// NOTE(allen): System For DLL Testing + +typedef void TestFunction(void); + +static void mule_init(void); +static TestFunction* mule_get_module_function(char *name); + +#if _WIN32 + +#include + +HMODULE mule_dll = 0; + +static void +mule_init(void){ + mule_dll = LoadLibraryA("mule_module.dll"); +} + +static TestFunction* +mule_get_module_function(char *name){ + TestFunction *result = (TestFunction*)GetProcAddress(mule_dll, name); + return(result); +} + +#else + +static void +mule_init(void){ + // TODO(allen): implement +} + +static TestFunction* +mule_get_module_function(char *name){ + // TODO(allen): implement + return(0); +} + +#endif + + +//////////////////////////////// +// NOTE(nick): Entry Point + +int +mule_main(int argc, char **argv); + +#if _WIN32 +#include +#include +int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){ + int argc = __argc; + char **argv = __argv; + int result = mule_main(argc, argv); + return(result); +} +#else +int main(int argc, char **argv){ + return(mule_main(argc, argv)); +} +#endif + +//////////////////////////////// +// NOTE(nick): BSS section test + +#if defined(__clang__) +# pragma clang section bss="muleBSS" +#elif defined(_MSC_VER) +// NOTE(nick): clang-cl is borken it allocates memory and sets Initialized Flag on the seciton. +// This is was reported by Jeff => https://bugs.llvm.org/show_bug.cgi?id=47939 +// +// This is still unresolved, last checked Sep 11, 2023. +# pragma bss_seg("muleBSS") +#else +# error "bss not defined" +#endif +char global_variable_in_bss[4096*10000]; + +//////////////////////////////// +// NOTE(allen): Inline Stepping (Built In Separate Unit) + +extern unsigned int fixed_frac_bits; +unsigned int inline_stepping_tests(void); + + +//////////////////////////////// +// NOTE(rjf): -O2 Optimized Code (Built In Separate Unit) + +void optimized_build_eval_tests(void); +void optimized_struct_parameters_eval_tests(void); + +//////////////////////////////// +// NOTE(allen): Type Coverage Eval + +#include + +struct Basics +{ + char a; + unsigned char b; + short c; + unsigned short d; + int e; + unsigned int f; + long long g; + unsigned long long h; + float i; + double j; + int z; +}; + +struct Basics_Stdint +{ + int8_t a; + uint8_t b; + int16_t c; + uint16_t d; + int32_t e; + uint32_t f; + int64_t g; + uint64_t h; + float i; + double j; +}; + +struct Pair +{ + int x; + float y; +}; + +struct Fixed_Array +{ + Pair pairs[10]; + int count; +}; + +struct Dynamic_Array +{ + Pair *pairs; + int count; +}; +raddbg_type_view(Dynamic_Array, slice($)); + +struct Struct_With_Embedded_Arrays +{ + int x; + float y; + Pair pairs[10]; + char z; +}; + +typedef unsigned int Custom_Index_Type; + +typedef void Function_No_Params_Type(void); +typedef void Function_Few_Params_Type(Pair *pairs, int count, Function_No_Params_Type *no_params_type); + +static Function_No_Params_Type *ty_no_params = 0; +static Function_Few_Params_Type *ty_few_params = 0; + +struct Callback{ + Function_Few_Params_Type *few_params; + Function_No_Params_Type *no_params; + Pair pair; +}; + +union Vector_R2 +{ + struct + { + float x; + float y; + }; + float v[2]; +}; +raddbg_type_view(Vector_R2, rows($, x, y)); + +typedef union Matrix4x4F32 Matrix4x4F32; +union Matrix4x4F32 +{ + float elements[4][4]; +}; +raddbg_type_view(Matrix4x4F32, columns($.elements, $[0], $[1], $[2], $[3])); + +union PackedF16 +{ + uint16_t v; + struct + { + uint16_t mantissa : 10; + uint16_t exponent : 5; + uint16_t sign : 1; + }; +}; +raddbg_type_view(PackedF16, + exponent == 0 ? (0.00006103515625f*mantissa/1024.f) : + (exponent == 31 && mantissa == 0 && sign == 1) ? "-infinity" : + (exponent == 31 && mantissa == 0 && sign == 1) ? "+infinity" : + (exponent == 31) ? "NaN" : + (exponent < 15) ? (1.f/(1<<(15 - exponent)) * (sign * -2 + 1.f) * (1.f + mantissa/1024.f)) : + (exponent > 15) ? ((1<<(exponent-15)) * (sign * -2 + 1.f) * (1.f + mantissa/1024.f)) : + ((sign * -2 + 1) * 1.f + mantissa/1024.f)); + +enum Kind +{ + Kind_Negative = -1, + Kind_None, + Kind_First, + Kind_Second, + Kind_Third, + Kind_Fourth, + Kind_COUNT, +}; + +enum Flag +{ + Flag_None = 0, + Flag_First = 1, + Flag_Second = 2, + Flag_Third = 4, + Flag_Fourth = 8, + Flag_AllMoreNarrow = 0xFF, + Flag_AllNarrow = 0xFFFF, + Flag_All = 0xFFFFFFFF, +}; + +struct Has_Enums +{ + Kind kind; + Flag flags; +}; + +struct Discriminated_Union +{ + Kind kind; + union + { + struct + { + int x; + int y; + Vector_R2 vector; + } first; + Pair second; + struct + { + Function_Few_Params_Type *few_params; + Pair pairs[4]; + } third; + struct + { + Kind sub_kind; + Flag flags; + } fourth; + }; +}; +raddbg_type_view(Discriminated_Union, + kind == Kind.First ? first : + kind == Kind.Second ? second : + kind == Kind.Third ? third : + kind == Kind.Fourth ? fourth : + $); + +struct Crazy_Union +{ + Kind kind; + union + { + struct + { + int first_and_third__x; + int first_and_third__y; + int first_and_third__z; + } first_and_third; + struct + { + char *second__name; + Pair second__pairs[16]; + } second; + }; + union + { + struct + { + char *first__name; + int first__x; + } first; + struct + { + char *third__name; + Function_Few_Params_Type *third__few_params; + } third; + }; +}; +raddbg_type_view(Crazy_Union, + kind == Kind.First ? rows($, first_and_third, first) : + kind == Kind.Second ? rows($, second) : + kind == Kind.Third ? rows($, first_and_third, third) : + kind == Kind.Fourth ? kind : + $); + +struct Linked_List{ + Linked_List *next; + Linked_List *prev; + int x; +}; + +enum{ + Anonymous_A, + Anonymous_B, + Anonymous_C, + Anonymous_D, +}; + +typedef Kind Alias1; +typedef Flag Alias2; +typedef Has_Enums Alias3; +typedef Discriminated_Union Alias4; + +struct Has_A_Pre_Forward_Reference{ + struct Gets_Referenced_Forwardly *pointer; +}; + +struct Gets_Referenced_Forwardly{ + int x; + int y; +}; + +struct Has_A_Post_Forward_Reference{ + struct Gets_Referenced_Forwardly value; +}; + +struct TypeWithMemberFunction +{ + int x; + int y; + int z; + char *name; + __declspec(noinline) void SetInfo(int _x, int _y, char *_name) + { + x = _x; + y = _y; + z = 0; + name = _name; + OutputDebugStringA("setting info\n"); + } +}; + +static void +no_params1(void){ + +} + +static void +few_params1(Pair *pairs, int count, Function_No_Params_Type *no_params_type){ + +} + +static 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}; + + char string[] = "Hello World!"; + char longer_text[] = + "Suppose there was some text\n" + "With multiple lines in it\r\n" + "\t> What ways might it be rendered?\n" + "\t> How would it deal with line endings?\r\n"; + wchar_t a_wide_string[] = + L"This is a string, but instead of being encoded in a stream of bytes,\n" + L"it is encoded in a stream of 2-byte packages!\n"; + + const char *const_string = "Hello, World!"; + const char const_string_array[] = "Hello, World!"; + const char *const const_ptr_const_string = "Hello, World!"; + + void *pointer = &basics; + Basics *pointer_to_basics = &basics; + Basics **pointer_to_pointer_to_basics = &pointer_to_basics; + + Fixed_Array fixed = + { + { + { 3, 4.f}, + { 5, 6.f}, + { 7, 8.f}, + { 9, 10.f}, + {11, 12.f}, + {13, 14.f}, + {15, 16.f}, + {17, 18.f}, + {19, 20.f}, + }, + 9 + }; + Pair memory_[] = + { + {100, 1.f}, + {101, 2.f}, + {102, 4.f}, + {103, 8.f}, + {104, 16.f}, + {105, 32.f}, + }; + Dynamic_Array dynamic = + { + memory_, + 6 + }; + + raddbg_pin(columns(sequence(6), fixed.pairs[$], memory_[$])); + raddbg_pin(basics); + raddbg_pin(fixed); + raddbg_pin(pointer); + raddbg_pin(dynamic); + + Struct_With_Embedded_Arrays swea = {0}; + { + swea.x = 4; + swea.y = 23.5f; + swea.pairs[0].x = 100; + swea.pairs[0].y = 123.f; + swea.pairs[2].x = 300; + swea.pairs[2].y = 323.f; + swea.pairs[5].x = 600; + swea.pairs[5].y = 623.f; + swea.z = 'z'; + } + + Struct_With_Embedded_Arrays *swea_ptr = &swea; + int access_via_ptr_member = swea_ptr->x; + + Custom_Index_Type custom_index = 42; + Custom_Index_Type more_custom_indices[] = { + 04,13,22,31,40 + }; + + Function_No_Params_Type *ptr_no_params = no_params1; + Function_No_Params_Type **ptr_ptr_no_params = &ptr_no_params; + Function_Few_Params_Type *ptr_few_params = few_params1; + Function_Few_Params_Type **ptr_ptr_few_params = &ptr_few_params; + Callback callback = {few_params1, no_params1, {1, 2.f}}; + + Matrix4x4F32 matrix = + { + { + {1.f, 0.f, 0.f, 0.f}, + {0.f, 1.f, 0.f, 0.f}, + {0.f, 0.f, 1.f, 0.f}, + {0.f, 0.f, 0.f, 1.f}, + } + }; + + Vector_R2 vector = {1.f, 2.f}; + + Has_Enums has_enums = {(Kind)4, (Flag)7}; + + Crazy_Union crazy_union = {}; + + crazy_union.kind = Kind_First; + crazy_union.kind = Kind_Second; + crazy_union.kind = Kind_Third; + crazy_union.kind = Kind_Fourth; + + Discriminated_Union discriminated_union = {}; + + discriminated_union.kind = Kind_First; + discriminated_union.first.x = 16; + discriminated_union.first.y = 8; + discriminated_union.first.vector.x = 4.f; + discriminated_union.first.vector.y = 2.f; + + discriminated_union.kind = Kind_Second; + discriminated_union.second.x = 123; + discriminated_union.second.y = 3.14f; + + discriminated_union.kind = Kind_Third; + discriminated_union.third.few_params = few_params1; + discriminated_union.third.pairs[0] = memory_[0]; + discriminated_union.third.pairs[1] = memory_[1]; + discriminated_union.third.pairs[2] = memory_[2]; + discriminated_union.third.pairs[3] = memory_[3]; + + discriminated_union.kind = Kind_Fourth; + discriminated_union.fourth.sub_kind = Kind_First; + discriminated_union.fourth.flags = (Flag)7; + + Linked_List list = {&list, &list, 0}; + + Alias1 a1 = has_enums.kind; + Alias2 a2 = has_enums.flags; + Alias3 a3 = has_enums; + Alias4 a4 = discriminated_union; + + Has_A_Pre_Forward_Reference r1 = {0}; + Has_A_Post_Forward_Reference r2 = {0}; + + Basics &basics_ref = basics; + const Basics *basics_const_ptr = &basics; + const Basics &basics_const_ref = basics; + + union + { + int x; + char y[4]; + } integer_slicing = {123456789}; + + typedef struct stks + { + void *left; + size_t len; + } stks; + stks stks_test[256] = {0}; + stks *stks_first = &stks_test[0]; + stks *stks_ptr = stks_first + 8; + + TypeWithMemberFunction twmf = {0}; + twmf.SetInfo(123, 456, "foobar"); + + TestFunction *function = mule_get_module_function("dll_type_eval_tests"); + function(); + + int abc = 0; + for(int i = 0; i < 1000; i += 1) + { + if(i == 500) + { + abc+= 1; + } + int a = i + abc; + int b = a*5; + } + + char *names[] = + { + "samwise gamgee", "mithrandir", "grima wormtongue", "theodred", "theoden", "eomer", "eowyn", + "arwen", "sauron", "baggins", "proudfoot", "hardbottle", "bag end", "hobbiton", + "bree", "imladris", "isengard", "moria", "mount doom", "helm's deep", "bracegirdle", + "buckleberry ferry", "amun sul", "frodo", "bilbo", "buckland", "fangorn", "elrond", + "numenor", "treebeard", "shadowfax", "brego", "erod", "azufel", "dunedain", + "saruman", "aragorn", "gandalf", "meriadoc brandybuck", "peregrine took", "faramir", "boromir", + "ecthelion", "denethor", "mithrandil", "isildur", "haldir", "elessar", "elendil", + "dead marsh", "rohan", "gondor", "anarion", "earendil", "cirith ungol", "minas morghul", + "minas tirith", "barad-dur", "rivendell", "pellenor", "ithilien", "anduril", "narsil", + "edoras", "mordor", "osgiliath", + }; + + for(int i = 0; i < sizeof(names)/sizeof(names[0]); i += 1) + { + OutputDebugStringA(names[i]); + OutputDebugStringA("\n"); + } + + const int32_t x1 = 3; + const int32_t y1 = -10; + const int32_t z1 = x1 + y1; + + std::string small_cplusplus_string = "smallstr"; + std::string cplusplus_string = "This is a C++ string!"; + + std::vector int_vector; + int_vector.push_back(1); + int_vector.push_back(2); + int_vector.push_back(3); + int_vector.push_back(4); + int_vector.push_back(5); + int_vector.push_back(6); + int_vector.push_back(7); + + int x = (int)(Anonymous_D); +} + +//////////////////////////////// +// NOTE(allen): Mutating Variables Eval + +static const int con_some_constant = 4; +static const float con_some_constant_f = 0.04f; + +static int mut_x = 0; +static int mut_y; +static int mut_xarray[4] = {0, 1, 2, 3}; +static int *mut_xptr; + +static float mut_f = 0; +static float mut_g; +static float mut_farray[4] = {0.5f, 1.5f, 2.5f, 3.5f}; +static float *mut_fptr; + +static float mut_arrayarray[3][3]; + +static Linked_List mut_link; + +static void +mutate_in_function(int *array, int count){ + for (int i = 0; i < count; i += 1){ + array[i] += 1; + } + + for (int i = 0; i < 4; i += 1){ + mut_farray[i] += 1.f; + } +} + +static void +mutating_variables_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Basics + + int array_literal[10] = { + 10, 20, 30, 40, 50, 60, 70, 80, 90, + }; + + Basics struct_literal = { + -1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001, + }; + + array_literal[0] = struct_literal.e = 9; + + int x = mut_x; + int y = x + 10 + con_some_constant; + mut_y = y; + mut_xarray[0] += 0; + mut_xarray[1] += x; + mut_xarray[2] += y; + mut_xarray[3] += x + y; + + mut_xptr = &mut_xarray[2]; + + *mut_xptr -= (y - x)/2; + *(mut_xptr - 1) += 11; + + float f = mut_f + .333f + con_some_constant_f; + float g = f + 10.1f; + mut_g = g; + mut_farray[0] += 0.000001f; + mut_farray[1] += f; + mut_farray[2] += g; + mut_farray[3] += f + g; + + mut_fptr = &mut_farray[3]; + + *mut_fptr -= (g - f)*0.5f; + *(mut_fptr - 1) += 1.f; + + float a = 0.777f; + for (int i = 0; i < 3; i += 1){ + float b = a*a - 1.f; + for (int j = 0; j < 3; j += 1){ + mut_arrayarray[i][j] = b; + b += 0.111f; + } + a += 0.333f; + } + + //////////////////////////////// + // NOTE(allen): Changes in functions + + mutate_in_function(array_literal, 10); + + mutate_in_function(array_literal, 10); + + //////////////////////////////// + // NOTE(allen): Changes through pointers + + Basics basic = struct_literal; + Basics advanced = struct_literal; + + Basics *struct_pointer = &basic; + + basic.a += 1; + advanced.a += 1; + struct_pointer->a += 1; + + struct_pointer = &advanced; + + basic.b += 1; + advanced.b += 1; + struct_pointer->b += 1; + + Linked_List links[5]; + for (int i = 0; i < 5; i += 1){ + links[i].next = &links[i + 1]; + links[i].prev = &links[i - 1]; + links[i].x = i; + } + links[0].prev = 0; + links[4].next = &mut_link; + mut_link.prev = &links[4]; + mut_link.next = 0; + mut_link.x = 1000; + + Linked_List *link_ptr = links; + + link_ptr = link_ptr->next; + + link_ptr = &links[4]; + link_ptr = &mut_link; + + Linked_List sentinel = {0}; + sentinel.x = -1; + sentinel.next = &links[0]; + links[0].prev = &sentinel; + sentinel.prev = &mut_link; + mut_link.next = &sentinel; + + link_ptr = &sentinel; +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +struct NestedNodeInner{ + unsigned int small0; + unsigned int small1; + unsigned int big0; + unsigned int big1; +}; + +struct NestedNodeOuter{ + NestedNodeOuter *next; + NestedNodeInner *inner_nodes; + unsigned int inner_node_count; +}; + +static void +nested_types_eval_tests(void){ + // doing some setup + NestedNodeOuter *outer1 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer2 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + NestedNodeOuter *outer3 = (NestedNodeOuter*)malloc(sizeof(NestedNodeOuter)); + + outer1->next = outer2; + outer2->next = outer3; + outer3->next = 0; + + outer1->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer1->inner_node_count = 10; + + outer2->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer2->inner_node_count = 10; + + outer3->inner_nodes = (NestedNodeInner*)malloc(sizeof(NestedNodeInner)*10); + outer3->inner_node_count = 10; + + for (unsigned int i = 0; i < 10; i += 1){ + outer1->inner_nodes[i].small0 = i; + outer1->inner_nodes[i].small1 = 2*i; + outer1->inner_nodes[i].big0 = 0xFFFFFF + 0xF*i; + outer1->inner_nodes[i].big1 = 0xFFFFFF + 0xFF*i; + + outer2->inner_nodes[i].small0 = 1 + i; + outer2->inner_nodes[i].small1 = 3*i; + outer2->inner_nodes[i].big0 = 0x1000000 + 0x10*i; + outer2->inner_nodes[i].big1 = 0x1000000 + 0x101*i; + + outer3->inner_nodes[i].small0 = 2 + i; + outer3->inner_nodes[i].small1 = 4*i; + outer3->inner_nodes[i].big0 = 0x8000000 + 0xF0*i; + outer3->inner_nodes[i].big1 = 0x8000000 + 0xF0F*i; + } + + // okay eval it here + int x = 0; +} + +//////////////////////////////// +// NOTE(rjf): Struct Parameters Eval + +static void +struct_parameter_helper(Basics basics) +{ + basics.a += 1; + basics.a += 1; + basics.a += 1; +} + +static void +struct_parameters_eval_tests(void) +{ + Basics basics = {-1, 1, -2, 2, -4, 4, -8, 8, 1.5f, 1.50000000000001}; + struct_parameter_helper(basics); +} + +//////////////////////////////// +// NOTE(allen): Global Eval + +static int g_abc = 100; +static float g_xyz = 21.f; +static Alias1 g_kind = Kind_First; + +// TODO(allen): more global test types + +static void +complicated_global_mutation(int *x){ + *x = (int)g_xyz; +} + +static void +cross_unit_global_mutation(void){ + fixed_frac_bits = 10; +} + +static void +global_eval_tests(void){ + g_abc = 11*11; + g_xyz = (float)g_abc - 21.f; + + int z = g_abc; + complicated_global_mutation(&z); + + complicated_global_mutation(&g_abc); + + if (g_kind == Kind_First){ + g_abc -= 1; + g_kind = Kind_None; + } + + cross_unit_global_mutation(); + + static int l_abc = 200; + static float l_xyz = 42.f; + static Alias1 l_kind = Kind_Second; + + l_abc = g_abc*2; + l_xyz = g_xyz*2; + l_kind = (Alias1)(g_kind + 1); +} + +//////////////////////////////// +// NOTE(allen): Return Eval + +static int +complicated_return_expression(void){ + int x = 171717; + return((x % 13) <= 5?(x % 19)*11:(x - 500)%200); +} + +static void +return_eval_tests(void){ + complicated_return_expression(); +} + +//////////////////////////////// +// NOTE(allen): TLS Eval + +#if _WIN32 +# define thread_var __declspec(thread) +#else +# define thread_var __thread +#endif + +thread_var int tls_a = 100; +thread_var int tls_b = 999; + +static void +tls_eval_tests(void){ + tls_a = (tls_a + tls_b)/2; + tls_b = tls_b - tls_a; + + TestFunction *dll_tls_eval_test = mule_get_module_function("dll_tls_eval_test"); + if (dll_tls_eval_test != 0){ + dll_tls_eval_test(); + } +} + +//////////////////////////////// +// NOTE(allen): Complicated Type Coverage Eval + +struct Complicated_Type_Members{ + int x600[2][2][2][2]; + int *x601[2][2][2][2]; + int (*x602)[2][2][2][2]; + int (*x603[2])[2][2][2]; + int (*(*x604[2])[2])[2][2]; + int (*(*(*x605[2])[2])[2])[2]; + + int (*x33[2])(void); + int (*x34[3])(void); + int (*x35[2][2])(void); + + int (*(*z33)(void))[2]; + int (*(*z34)(void))[3]; + int (*(*z35)(void))[2][2]; + + int (*(*f2)(void))(void); + int (*(*(*f3)(void))(void))(void); + int (*(*f4)(int))(void); + int (*(*f5)(void))(int); + int (*(*f6)(int))(int); + int (*(*(*f7_growing)(char))(short))(int); + int (*(*(*f7_shrinking)(int))(short))(char); +}; + +static void +complicated_type_coverage_tests(void){ + Complicated_Type_Members m = {0}; + + int x1 = {0}; + int *x2 = {0}; + int **x3 = {0}; + + int x4a[2] = {0}; + int *x4[2] = {0}; + int x5a[3] = {0}; + int *x5[3] = {0}; + int *x6[2][2] = {0}; + int (*x7)[2] = {0}; + int (*x8)[3] = {0}; + int (*x9)[2][2] = {0}; + + int x600[2][2][2][2] = {0}; + int *x601[2][2][2][2] = {0}; + int (*x602)[2][2][2][2] = {0}; + int (*x603[2])[2][2][2] = {0}; + int (*(*x604[2])[2])[2][2] = {0}; + int (*(*(*x605[2])[2])[2])[2] = {0}; + + int x606_growing [2][3][4][5] = {0}; + int x606_shrinking[5][4][3][2] = {0}; + + int (*(*(*x607_growing [2])[3])[4])[5] = {0}; + int (*(*(*x607_shrinking[5])[4])[3])[2] = {0}; + + int **x10[2] = {0}; + int **x11[3] = {0}; + int **x12[2][2] = {0}; + int *(*x13)[2] = {0}; + int *(*x14)[3] = {0}; + int *(*x15)[2][2] = {0}; + int **x16[2] = {0}; + int **x17[3] = {0}; + int **x18[2][2] = {0}; + + int (*y1[2])[2] = {0}; + int (*y2[3])[2] = {0}; + int (*y3[2][2])[2] = {0}; + int (*y4[2])[3] = {0}; + int (*y5[3])[3] = {0}; + int (*y6[2][2])[3] = {0}; + int (*y7[2])[2][2] = {0}; + int (*y8[3])[2][2] = {0}; + int (*y9[2][2])[2][2] = {0}; + + int (*x19)(void) = {0}; + int (*x20)(int) = {0}; + int (*x21)(int, int) = {0}; + int (*x22)(int*, int) = {0}; + int (*x23)(int**, int) = {0}; + int (*x24)(int**, int*) = {0}; + int (*x25)(int**, int**) = {0}; + + int *(*x26)(void) = {0}; + int *(*x27)(int) = {0}; + int *(*x28)(int, int) = {0}; + int *(*x29)(int*, int) = {0}; + int *(*x30)(int**, int) = {0}; + int *(*x31)(int**, int*) = {0}; + int *(*x32)(int**, int**) = {0}; + + int (*x33[2])(void) = {0}; + int (*x34[3])(void) = {0}; + int (*x35[2][2])(void) = {0}; + + int (*x36[2])(int) = {0}; + int (*x37[3])(int) = {0}; + int (*x38[2][2])(int) = {0}; + + int (*x39[2])(int, int) = {0}; + int (*x40[3])(int, int) = {0}; + int (*x41[2][2])(int, int) = {0}; + + int (*x42[2])(int*, int) = {0}; + int (*x43[3])(int*, int) = {0}; + int (*x44[2][2])(int*, int) = {0}; + + int (*x45[2])(int**, int) = {0}; + int (*x46[3])(int**, int) = {0}; + int (*x47[2][2])(int**, int) = {0}; + + int (*x48[2])(int**, int*) = {0}; + int (*x49[3])(int**, int*) = {0}; + int (*x50[2][2])(int**, int*) = {0}; + + int (*x51[2])(int**, int**) = {0}; + int (*x52[3])(int**, int**) = {0}; + int (*x53[2][2])(int**, int**) = {0}; + + int (*(*z33)(void))[2] = {0}; + int (*(*z34)(void))[3] = {0}; + int (*(*z35)(void))[2][2] = {0}; + + int (*(*z36)(int))[2] = {0}; + int (*(*z37)(int))[3] = {0}; + int (*(*z38)(int))[2][2] = {0}; + + int (*(*z39)(int, int))[2] = {0}; + int (*(*z40)(int, int))[3] = {0}; + int (*(*z41)(int, int))[2][2] = {0}; + + int (*(*z42)(int*, int))[2] = {0}; + int (*(*z43)(int*, int))[3] = {0}; + int (*(*z44)(int*, int))[2][2] = {0}; + + int (*(*z45)(int**, int))[2] = {0}; + int (*(*z46)(int**, int))[3] = {0}; + int (*(*z47)(int**, int))[2][2] = {0}; + + int (*(*z48)(int**, int*))[2] = {0}; + int (*(*z49)(int**, int*))[3] = {0}; + int (*(*z50)(int**, int*))[2][2] = {0}; + + int (*(*z51)(int**, int**))[2] = {0}; + int (*(*z52)(int**, int**))[3] = {0}; + int (*(*z53)(int**, int**))[2][2] = {0}; + + int (*(*z303[2])(void)) = {0}; + int (*(*z304[3])(void)) = {0}; + int (*(*z305[2][2])(void)) = {0}; + + int (*(*z306[2])(int)) = {0}; + int (*(*z307[3])(int)) = {0}; + int (*(*z308[2][2])(int)) = {0}; + + int (*(*z309[2])(int, int)) = {0}; + int (*(*z400[3])(int, int)) = {0}; + int (*(*z401[2][2])(int, int)) = {0}; + + int (*(*z402[2])(int*, int)) = {0}; + int (*(*z403[3])(int*, int)) = {0}; + int (*(*z404[2][2])(int*, int)) = {0}; + + int (*(*z405[2])(int**, int)) = {0}; + int (*(*z406[3])(int**, int)) = {0}; + int (*(*z407[2][2])(int**, int)) = {0}; + + int (*(*z408[2])(int**, int*)) = {0}; + int (*(*z409[3])(int**, int*)) = {0}; + int (*(*z500[2][2])(int**, int*)) = {0}; + + int (*(*z501[2])(int**, int**)) = {0}; + int (*(*z502[3])(int**, int**)) = {0}; + int (*(*z503[2][2])(int**, int**)) = {0}; + + int (*(*f2)(void))(void) = {0}; + int (*(*(*f3)(void))(void))(void) = {0}; + int (*(*f4)(int))(void) = {0}; + int (*(*f5)(void))(int) = {0}; + int (*(*f6)(int))(int) = {0}; + int (*(*(*f7_growing)(char))(short))(int) = {0}; + int (*(*(*f7_shrinking)(int))(short))(char) = {0}; + + int (*f8)(int (*)(void)) = {0}; + int (*f9)(void (*)(int)) = {0}; + void (*f10)(int (*)(int)) = {0}; + int (*f11)(int, int (*)(void)) = {0}; + int (*f12)(int (*)(void), int) = {0}; + int (*f13)(int (*)(void), int (*)(void)) = {0}; + + int (*f14)(int (*)(void)) = {0}; + int (*f15)(int (*)(int (*)(void))) = {0}; + int (*f16)(int (*)(int (*)(int (*)(void)))) = {0}; + int (*f17)(int (*)(int (*)(int (*)(int (*)(void))))) = {0}; + + int (*f18)(int (*)(void)) = {0}; + int (*f19)(int (*(*)(void))(void)) = {0}; + int (*f20)(int (*(*(*)(void))(void))(void)) = {0}; + int (*f21)(int (*(*(*(*)(void))(void))(void))(void)) = {0}; + + int (*(*(*(*f22)(void))(void))(void))(void) = {0}; + int (*(*(*(*f23)(int [2]))(void))(void))(void) = {0}; + int (*(*(*(*f24)(int *[2]))(int [3]))(void))(void) = {0}; + int (*(*(*(*f25)(int (*)[2]))(int *[3]))(int [4]))(void) = {0}; + int (*(*(*(*f26)(int **(**)[2]))(int (*)[3]))(int *[4]))(int [5]) = {0}; + + int x = 0; +} + +//////////////////////////////// +// NOTE(allen): Extended Type Coverage Eval + +template +struct Template_Example{ + X x; + int y; +}; + +template +struct Template_Example2{ + X x; + Y y; +}; + +template +struct Template_Example3{ + X x; + Y y; + Template_Example3(X x, Y y) + { + this->x = x; + this->y = y; + } + ~Template_Example3() + { + int x = 2; + int y = 5; + int z = x + y; + } +}; + +struct SingleInheritanceBase +{ + int x; + int y; +}; + +struct SingleInheritanceDerived : SingleInheritanceBase +{ + int z; + int w; +}; + +struct Has_Members{ + int a; + int b; + uint64_t c; + uint64_t d; + Basics bas; + + int w(void){ return a; } + int x(void){ return b; } + uint64_t y(void){ return c; } + uint64_t z(void){ return d; } + Basics bas_f(void){ return bas; } +}; + +struct Has_Static_Members{ + int a; + int b; + static uint64_t c; + static uint64_t d; + + int w(void){ return a; } + int x(void){ return b; } + static uint64_t y(void){ return c; } + static uint64_t z(void){ return d; } +}; + +uint64_t Has_Static_Members::c = 0; +uint64_t Has_Static_Members::d = 0; + +struct Pointer_To_Member{ + int Has_Members::*member_ptr_int; + uint64_t Has_Members::*member_ptr_u64; + Basics Has_Members::*member_ptr_bas; + + int (Has_Members::*method_ptr_int)(void); + uint64_t (Has_Members::*method_ptr_u64)(void); + Basics (Has_Members::*method_ptr_bas)(void); +}; + +struct Has_Sub_Types{ + struct Sub_Type1{ + int x; + int y; + }; + + struct Sub_Type2{ + float x; + float y; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Conflicting_Type_Names{ + struct Sub_Type1{ + uint64_t z; + }; + + struct Sub_Type2{ + int64_t z; + }; + + Sub_Type1 a; + Sub_Type2 b; +}; + +struct Has_Private_Sub_Types{ + Has_Private_Sub_Types(char x1, char y1, + float x2, int y2, + int x3, float y3){ + this->a.x = x1; + this->a.y = y1; + this->b.x = x2; + this->b.y = y2; + this->c.x = x3; + this->c.y = y3; + } + + struct Public_Sub_Type{ + char x; + char y; + }; + Public_Sub_Type a; + + protected: + struct Protected_Sub_Type{ + float x; + int y; + }; + Protected_Sub_Type b; + + private: + struct Private_Sub_Type{ + int x; + float y; + }; + Private_Sub_Type c; +}; + +struct Vtable_Parent{ + virtual void a_virtual_function(void) = 0; + virtual void b_virtual_function(void) = 0; + virtual void c_virtual_function(void) = 0; + + void a_virtual_function(int r){ + for (int i = 0; i < r; i += 1){ + a_virtual_function(); + } + } +}; + +struct Vtable_Child : Vtable_Parent{ + int x; + int y; + + Vtable_Child(int a, int b){ + x = a; + y = b; + } + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void c_virtual_function(void){ + x = y; + }; +}; + +struct Vinheritance_Base{ + int x; + int y; + + virtual void a_virtual_function(void){ + x = 0; + }; + virtual void b_virtual_function(void){ + y = 0; + }; + virtual void x_virtual_function(void){ + y = x; + }; +}; + +struct Vinheritance_MidLeft : virtual Vinheritance_Base{ + float left; + + virtual void c1_virtual_function(void){ + left = 0; + }; + virtual void c2_virtual_function(void){ + left = 0; + }; +}; + +struct Vinheritance_MidRight : virtual Vinheritance_Base{ + float right; + + virtual void d_virtual_function(void){ + right = 0; + }; +}; + +struct Vinheritance_Child : Vinheritance_MidLeft, Vinheritance_MidRight{ + char *name; + + virtual void a_virtual_function(void){ + x = 1; + }; + virtual void c1_virtual_function(void){ + left = 1; + }; +}; + +struct Minheritance_Base{ + int x; + int y; +}; + +struct Minheritance_MidLeft : Minheritance_Base{ + float left; +}; + +struct Minheritance_MidRight : Minheritance_Base{ + float right; +}; + +struct Minheritance_Child : Minheritance_MidLeft, Minheritance_MidRight{ + char *name; +}; + +struct Pure +{ + virtual ~Pure() = default; + virtual void Foo() = 0; +}; + +struct PureChild : Pure +{ + virtual ~PureChild() = default; + virtual void Foo() {a += 1;} + double a = 0; +}; + +struct Base +{ + int x; + int y; + int z; + Base(){x = 1; y = 2; z = 3;} + virtual ~Base() = default; + virtual void Foo() = 0; +}; + +struct Derived : Base +{ + int r; + int g; + int b; + int a; + virtual ~Derived() = default; + virtual void Foo() + { + x += 1; + y += 1; + y += 1; + z += 1; + z += 1; + z += 1; + a += 1; + a += 1; + a += 1; + a += 1; + } +}; + +struct DerivedA : Base +{ + float a; + float b; + DerivedA() {a = 123.f; b = 123.f;} + virtual void Foo() {a += 1;} + virtual ~DerivedA() = default; +}; + +struct DerivedB : Base +{ + double c; + double d; + DerivedB() {c = 123.0; d = 123.0;} + virtual void Foo() {c += 1;} + virtual ~DerivedB() = default; +}; + +struct NonVirtualBase +{ + int x; + int y; + int z; +}; + +struct NonVirtualDerived : NonVirtualBase +{ + int r; + int g; + int b; + int a; +}; + +struct OverloadedMethods{ + int x; + int cool_method(void){ + return(x); + } + int cool_method(int z){ + int r = x; + x = z; + return(r); + } + void cool_method(int y, int z){ + if (x < z){ + x = y; + } + else{ + x = z; + } + } +}; + +struct HasStaticConstMembers +{ + int a; + int b; + static int c; + static int d; + static const int e = 789; + static const int f = 101112; +}; + +int HasStaticConstMembers::c = 123; +int HasStaticConstMembers::d = 456; + +struct Has_A_Constructor{ + int n; + int d; + Has_A_Constructor(int a, int b){ + int gcd = 1; + { + int x = a; + int y = b; + if (x < y){ + y = a; + x = b; + } + for (;y > 0;){ + int z = x%y; + x = y; + y = z; + } + gcd = x; + } + n = a/gcd; + d = b/gcd; + } + + static int N; + static int D; + ~Has_A_Constructor(){ + int m = N*d + n*D; + int e = d*D; + N = m; + D = d; + } +}; + +int Has_A_Constructor::N = 0; +int Has_A_Constructor::D = 1; + +struct Constructor_Gotcha_Test{ + int x; + int y; + void Constructor_Gotcha(void){ + x = y = 0; + } +}; + +struct Has_A_Friend{ + friend struct Modifies_Other; + int get_x(void){ return x; } + int get_y(void){ return y; } + + private: + int x; + int y; +}; + +struct Modifies_Other{ + int x; + int y; + + void talk_to_friend(Has_A_Friend *other){ + other->x = y; + other->y = x; + } +}; + +namespace UserNamespace{ + namespace SubA{ + struct Foo{ + int x; + int y; + }; + }; + namespace SubB{ + struct Foo{ + float u; + float v; + }; + }; + + SubA::Foo foo_a = {10, 20}; + SubB::Foo foo_b = {0.1f, 0.05f}; + + static void namespaced_function(void){ + foo_a.x = (int)(foo_a.y*foo_b.u); + foo_b.v = (float)(foo_a.x*foo_b.v); + } +}; + +static void +call_with_pass_by_reference(int &x){ + x += 1; +} + +static void +call_with_pass_by_const_reference(const int &x){ + int y = x; +} + +static void +extended_type_coverage_eval_tests(void){ + //////////////////////////////// + // NOTE(allen): Extensions to base type system. + { + int x = 0; + const int *x_ptr = &x; + int *const x_cptr = &x; + + call_with_pass_by_reference(x); + + call_with_pass_by_const_reference(x); + } + + //////////////////////////////// + // NOTE(allen): Extensions to user defined types + { + Template_Example temp_f = {1.f, 2}; + Template_Example temp_v = {(void*)&temp_f, 2}; + Template_Example > temp_tf = {temp_f, 2}; + Template_Example2 temp_if = {2, 1.f}; + Template_Example3 temp3_if(2, 1.f); + Template_Example3 temp3_vi((void *)&temp3_if, 1.f); + Template_Example3> temp3_itif(123, temp_if); + + SingleInheritanceDerived sid; + sid.x = 123; + sid.y = 456; + sid.z = 789; + sid.w = 999; + + Pointer_To_Member pointer_to_member = { + &Has_Members::a, &Has_Members::c, &Has_Members::bas, + &Has_Members::x, &Has_Members::z, &Has_Members::bas_f, + }; + + Has_Static_Members has_static_members = { 10, 20 }; + Has_Static_Members::c = 100; + Has_Static_Members::d = 110; + has_static_members.x(); + has_static_members.y(); + has_static_members.z(); + has_static_members.w(); + + Has_Sub_Types has_sub_types = { + {100, 200}, + {.1f, .2f}, + }; + + Conflicting_Type_Names conflicting_type_names = { + {10}, {-20}, + }; + + Has_Private_Sub_Types has_private_sub_types(1, 2, 4, 8, 16, 32); + + Vtable_Child vtable_child(1, 2); + vtable_child.a_virtual_function(); + + Vinheritance_Child vinheritance_child; + vinheritance_child.name = "foobar"; + vinheritance_child.left = 10.5f; + vinheritance_child.right = 13.0f; + vinheritance_child.x = -1; + vinheritance_child.y = -1; + + Minheritance_Child minheritance_child; + minheritance_child.name = "foobar"; + minheritance_child.left = 10.5f; + minheritance_child.right = 13.0f; + minheritance_child.Minheritance_MidLeft::x = -1; + minheritance_child.Minheritance_MidLeft::y = -1; + minheritance_child.Minheritance_MidRight::x = +1; + minheritance_child.Minheritance_MidRight::y = +1; + + Pure *child = new PureChild(); + child->Foo(); + child->Foo(); + child->Foo(); + delete child; + + Base *derived = new Derived(); + derived->Foo(); + derived->Foo(); + derived->Foo(); + delete derived; + + NonVirtualBase *non_virtual_derived = new NonVirtualDerived(); + non_virtual_derived->x += 1; + non_virtual_derived->x += 1; + non_virtual_derived->x += 1; + + std::unique_ptr ridiculous_cplusplus_base_class = std::make_unique(); + + std::vector> ridiculous_cplusplus_array; + for(int i = 0; i < 1024; i += 1) + { + if((i & 1) == 1) + { + ridiculous_cplusplus_array.push_back(std::make_unique()); + } + else + { + ridiculous_cplusplus_array.push_back(std::make_unique()); + } + } + + Base *base_array[1024] = {0}; + for(int i = 0; i < sizeof(base_array)/sizeof(base_array[0]); i += 1) + { + if((i & 1) == 1) + { + base_array[i] = new DerivedA(); + } + else + { + base_array[i] = new DerivedB(); + } + } + + OverloadedMethods overloaded_methods; + { + overloaded_methods.x = 0; + int a = overloaded_methods.cool_method(); + overloaded_methods.cool_method(-10, 100); + int b = overloaded_methods.cool_method(100); + overloaded_methods.cool_method(b*2, a*2); + int c = overloaded_methods.cool_method(a + b); + int z = c; + } + + Has_A_Constructor construct_me(360, 25); + + Has_A_Friend has_a_friend; + + Modifies_Other modifies_other; + modifies_other.x = 57; + modifies_other.y = 66; + + modifies_other.talk_to_friend(&has_a_friend); + + int x = has_a_friend.get_x(); + int y = has_a_friend.get_y(); + int z = x; + + HasStaticConstMembers static_const_members = {0}; + static_const_members.a = 123 + HasStaticConstMembers::c * HasStaticConstMembers::e; + static_const_members.b = 456 + HasStaticConstMembers::d * HasStaticConstMembers::f; + } + + //////////////////////////////// + // NOTE(allen): Namespaces + { + UserNamespace::namespaced_function(); + } +} + +//////////////////////////////// +//~ rjf: Templated Function Eval Tests + +typedef struct TemplateArg TemplateArg; +struct TemplateArg +{ + int x; + int y; + int z; + float a; + float b; + float c; + char *name; +}; + +template static T +templated_factorial(T t) +{ + T result = t; + if(t > 1) + { + result *= templated_factorial(t-1); + } + return result; +} + +template static T +compute_template_arg_info(T t) +{ + int sum = t.x + t.y + t.z; + int size = sizeof(t); + float sum_f = t.a + t.b + t.c; + OutputDebugStringA(t.name); + return t; +} + +static void +templated_function_eval_tests(void) +{ + int int_factorial = templated_factorial(10); + float float_factorial = templated_factorial(10); + TemplateArg arg = {1, 2, 3, 4.f, 5.f, 6.f, "my template arg"}; + compute_template_arg_info(arg); + int x = 0; +} + +//////////////////////////////// +//~ NOTE(allen): C Type Coverage + +extern "C"{ +#include "mule_c.h" +} + +//////////////////////////////// +//~ rjf: Basic Inline Line Info Tests + +#if defined(_MSC_VER) +# define FORCE_INLINE __forceinline +#elif defined(__clang__) +# define FORCE_INLINE __attribute__((always_inline)) +#else +# error need force inline for this compiler +#endif + +static FORCE_INLINE void +basic_inlinee(int inlinee_param_x, int inlinee_param_y, int inlinee_param_z) +{ + OutputDebugStringA("A\n"); + OutputDebugStringA("B\n"); + OutputDebugStringA("C\n"); + OutputDebugStringA("D\n"); +} + +static void +basic_inline_tests(void) +{ + OutputDebugStringA("{\n"); + basic_inlinee(12, 34, 56); + OutputDebugStringA("}\n"); +} + +//////////////////////////////// +//~ rjf: Fancy Visualization Eval Tests + +struct Bitmap +{ + unsigned char *base; + int width; + int height; +}; +raddbg_type_view(Bitmap, bitmap(base, width, height)); + +static unsigned int +mule_bswap_u32(unsigned int x) +{ + unsigned int result = (((x & 0xFF000000) >> 24) | + ((x & 0x00FF0000) >> 8) | + ((x & 0x0000FF00) << 8) | + ((x & 0x000000FF) << 24)); + return result; +} + +static void +fancy_viz_eval_tests(void) +{ + //- rjf: windows -> GetLastError +#if _WIN32 + DWORD error_code = 0; + SetLastError(1234); + error_code = GetLastError(); + SetLastError(4567); + error_code = GetLastError(); + (void)error_code; +#endif + + //- rjf: booleans (checkboxes) + bool bool1 = 0; raddbg_pin(bool1); + bool bool2 = 1; raddbg_pin(bool2); + bool bool3 = 0; raddbg_pin(bool3); + + //- rjf: sliders + float slide1 = 500.f; raddbg_pin(range1(slide1, 0, 1000)); + double slide2 = 0.75; raddbg_pin(range1(slide2, 0, 1.0)); + int slide3 = 25; raddbg_pin(range1(slide3, 0, 100)); + + //- rjf: colors + float example_color_4f32[4] = {1.00f, 0.85f, 0.25f, 1.00f}; + unsigned int example_color_u32 = 0xff6f30ff; + struct {float r, g, b, a;} example_color_struct = {0.50f, 0.95f, 0.75f, 1.00f}; + int x0 = 0; + raddbg_pin(color(example_color_4f32)); + raddbg_pin(color(example_color_u32)); + raddbg_pin(color(example_color_struct)); + + //- rjf: multiline text + char *long_string = ("This is an example of some very long text with line breaks\n" + "in it. This is a very common kind of data which is inspected\n" + "in the debugger while programming, and it is often a pain\n" + "when it is poorly supported.\n"); + char *code_string = ("#include \n" + "\n" + "int main(int argc, char**argv)\n" + "{\n" + " printf(\"Hello, World!\\n\");\n" + " return 0;\n" + "}\n\n"); + int x1 = 0; + raddbg_pin(text(long_string)); + raddbg_pin(text(code_string, lang=c)); + raddbg_pin(disasm(fancy_viz_eval_tests)); + + //- rjf: half-floats + PackedF16 f16s[] = + { + {0x0001}, // ~0.000000059604645 + {0x03ff}, // ~0.000060975552 + {0x0400}, // ~0.00006103515625 + {0x3555}, // ~0.33325195 + {0x3bff}, // ~0.99951172 + {0x3c00}, // 1 + {0x3c01}, // 1.00097656 + {0x7bff}, // 65504, + {0x7c00}, // +inf + {0xfc00}, // -inf + }; + + //- rjf: table index lookups + struct + { + char *name; + int x; + int y; + int z; + } + nodes[] = + { + {"---", 1, 7, 3}, + {"---", 5, 4, 2}, + {"second", 12, 41, 22}, + {"---", 8, 9, 1}, + {"---", 1, 1, 1}, + {"first", 50, 50, 50}, + {"fourth", 7, 7, 7}, + {"---", 7, 12, 1}, + {"third", 27, 43, 41}, + {"---", 2, 17, 50}, + }; + int node_indices[] = + { + 5, 2, 8, 6 + }; + raddbg_pin(columns(node_indices, nodes[$])); + + //- rjf: bitmaps + unsigned int background_color = 0x00000000; + unsigned int main_color = 0xff2424ff; + unsigned int shine_color = 0xff5693ff; + unsigned int shadow_color = 0xff238faf; + unsigned int bg = mule_bswap_u32(background_color); + unsigned int cl = mule_bswap_u32(main_color); + unsigned int sn = mule_bswap_u32(shine_color); + unsigned int sh = mule_bswap_u32(shadow_color); + unsigned int pixels[] = + { + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, cl, cl, bg, cl, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, cl, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, cl, cl, cl, bg, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, cl, sn, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, sn, cl, cl, cl, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, sh, cl, cl, cl, sh, sh, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, sh, sh, sh, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, bg, + }; + raddbg_pin(bitmap(pixels, 18, 18)); + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + for(int i = 0; i < sizeof(pixels)/sizeof(pixels[0]); i += 1) + { + unsigned int r = pixels[i]&0x000000ff; + unsigned int a = pixels[i]&0xff000000; + pixels[i] = pixels[i]>>8; + pixels[i] &= ~0xffff0000; + pixels[i] |= (r<<16); + pixels[i] |= (a); + } + int x2 = 0; + + //- rjf: type-viewed bitmaps + Bitmap foo = {(unsigned char *)&pixels[0], 18, 18}; + raddbg_pin(foo); + + //- rjf: name collisions with debugger rules + Function_Few_Params_Type *raw = 0; + char *text = "some_important_text_here\n"; + Bitmap bitmap = foo; + int x3 = 0; + + //- rjf: 3D geometry + float vertex_data[] = // pos.x, pos.y, pos.z, nor.x, nor.y, nor.z, tex.u, tex.v, col.r, col.g, col.b, ... + { + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 2.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 2.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 8.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 8.0f, 0.973f, 0.480f, 0.002f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 2.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 8.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 10.0f, 10.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 2.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 2.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 8.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 8.0f, 0.612f, 0.000f, 0.069f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 2.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 8.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 10.0f, 10.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 2.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 8.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 2.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 8.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 10.0f, 10.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 2.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 2.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 2.0f, 8.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 1.0f, 0.0f, 8.0f, 8.0f, 0.000f, 0.254f, 0.637f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 2.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 8.0f, 10.0f, 0.000f, 0.254f, 0.637f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 10.0f, 10.0f, 0.000f, 0.254f, 0.637f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 2.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 2.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 2.0f, 8.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, -1.0f, 0.0f, 8.0f, 8.0f, 0.001f, 0.447f, 0.067f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 2.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 8.0f, 10.0f, 0.001f, 0.447f, 0.067f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 10.0f, 10.0f, 0.001f, 0.447f, 0.067f, + -0.6f, 0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, -0.6f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + -0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.973f, 0.480f, 0.002f, + 1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.897f, 0.163f, 0.011f, + 0.6f, 0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, -0.6f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + 0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.612f, 0.000f, 0.069f, + -1.0f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, 0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, -0.6f, -0.6f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, 0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -1.0f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 0.6f, -0.6f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.127f, 0.116f, 0.408f, + -0.6f, 1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + 0.6f, 0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.000f, 0.254f, 0.637f, + -0.6f, -0.6f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, -0.6f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + -0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -0.6f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + 0.6f, -1.0f, 0.6f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.001f, 0.447f, 0.067f, + }; + unsigned int index_data[] = + { + 0, 1, 9, 9, 8, 0, 1, 2, 5, 5, 4, 1, 6, 7, 10, 10, 9, 6, 2, 3, 11, 11, 10, 2, + 12, 13, 21, 21, 20, 12, 13, 14, 17, 17, 16, 13, 18, 19, 22, 22, 21, 18, 14, 15, 23, 23, 22, 14, + 24, 25, 33, 33, 32, 24, 25, 26, 29, 29, 28, 25, 30, 31, 34, 34, 33, 30, 26, 27, 35, 35, 34, 26, + 36, 37, 45, 45, 44, 36, 37, 38, 41, 41, 40, 37, 42, 43, 46, 46, 45, 42, 38, 39, 47, 47, 46, 38, + 48, 49, 57, 57, 56, 48, 49, 50, 53, 53, 52, 49, 54, 55, 58, 58, 57, 54, 50, 51, 59, 59, 58, 50, + 60, 61, 69, 69, 68, 60, 61, 62, 65, 65, 64, 61, 66, 67, 70, 70, 69, 66, 62, 63, 71, 71, 70, 62, + 72, 73, 74, 74, 75, 72, 76, 77, 78, 78, 79, 76, 80, 81, 82, 82, 83, 80, 84, 85, 86, 86, 87, 84, + 88, 89, 90, 90, 91, 88, 92, 93, 94, 94, 95, 92, 96, 97, 98, 98, 99, 96, 100, 101, 102, 102, 103, 100, + 104, 105, 106, 106, 107, 104, 108, 109, 110, 110, 111, 108, 112, 113, 114, 114, 115, 112, 116, 117, 118, 118, 119, 116, + 120, 121, 122, 122, 123, 120, 124, 125, 126, 126, 127, 124, 128, 129, 130, 130, 131, 128, 132, 133, 134, 134, 135, 132, + 136, 137, 138, 138, 139, 136, 140, 141, 142, 142, 143, 140, 144, 145, 146, 146, 147, 144, 148, 149, 150, 150, 151, 148, + 152, 153, 154, 154, 155, 152, 156, 157, 158, 158, 159, 156, 160, 161, 162, 162, 163, 160, 164, 165, 166, 166, 167, 164, + }; + int count = (sizeof index_data/4); + float *vtx = vertex_data; + int vtx_size = sizeof vertex_data; + raddbg_pin(geo3d(index_data, count = count, vtx = vtx, vtx_size = vtx_size)); + int x4 = 0; +} + +//////////////////////////////// +//~ rjf: Markup Tests + +static void +markup_tests(void) +{ + int x = 0; + raddbg_add_breakpoint(&x, sizeof(x), 0, 1, 0); + for(int i = 0; i < 10000; i += 1) + { + if(i == 5000) + { + x += 1; + } + } + raddbg_remove_breakpoint(&x, sizeof(x), 0, 1, 0); +} + +//////////////////////////////// +//~ NOTE(allen): Function Overload Resolution + +static int +overloaded_function(float y){ + int r = (int)(y + 0.5f); + return(r); +} + +static int +overloaded_function(float y, int x){ + int r = overloaded_function(y) + x; + return(r); +} + +static int +overloaded_function(int x){ + float y = (float)x; + int r = overloaded_function(y, 1); + return(r); +} + +//////////////////////////////// +// NOTE(allen): Control Flow Stepping + +static void +control_flow_stepping_tests(void){ + { + int a = 1; + if (a < 1){ + a += 1; + } + if (a < 2){ + a += 2; + } + } + + { + int a = 1; + if (a < 1) + { + a += 1; + } + if (a < 2) + { + a += 2; + } + } + + { + int a = 1; + if (a < 1) + a += 1; + if (a < 2) + a += 2; + } + + { + int a = 1; + int b = 2; + if (a <= b){ + if (a == b){ + b += 1; + } + else{ + a += 1; + } + } + else{ + if (a%2){ + a = b; + } + else{ + a = b - 1; + } + } + } + + { + int a = 1; + int b = 2; + if (a <= b) + { + if (a == b) + { + b += 1; + } + else + { + a += 1; + } + } + else + { + if (a%2) + { + a = b; + } + else + { + a = b - 1; + } + } + } + + { + int a = 1; + int b = 2; + if (a <= b) + if (a == b) + b += 1; + else + a += 1; + else + if (a%2) + a = b; + else + a = b - 1; + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1){ + x += i; + } + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) + { + x += i; + } + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) + x += i; + } + + { + int x = 0; + for (int i = 0; i < 10; i += 1) x += i; + } + + { + int a = 1; + for (;a < 10;){ + switch (a){ + case 0: case 1: case 2: + { + a += 2; + }break; + + default: + case 4: + case 5: + { + a += 1; + }break; + + case 6: a += 1; break; + case 7: a += 1; + case 8: + case 9: a += 1; + } + } + } + + { + int i = 0; + while (i < 5){ + i += 1; + } + + while (i < 10) + { + i += 1; + } + + while (i < 15) + i += 1; + + while (i < 20) i += 1; + } + + { + int i = 0; + do + { + i += 1; + } while (i < 10); + } + + { + int i = 17; + + check_again: + if (i <= 1) goto done; + if ((i&1) == 0) goto even_case; + + // odd_case: + i = 3*i + 1; + + even_case: + i /= 2; + goto check_again; + + done:; + } + + { + int x = 15; + label_same_line:; x -= 1; if(x > 0) { goto label_same_line; } else { goto end_label_same_line; } + } + end_label_same_line:; +} + +//////////////////////////////// +// NOTE(allen): Indirect Call/Jump Stepping Tests + +typedef int FunctionType(int); + +static int +function_foo(int a){ + if (a < 1){ + a += 1; + } + if (a < 2){ + a += 2; + } + return(a); +} + +static int +function_bar(int x){ + for (int i = 0; i < 10; i += 1){ + x += i; + } + return(x); +} + + +static void +indirect_call_jump_stepping_tests(void){ + int z = 1; + FunctionType *ptr = function_foo; + z = ptr(z); + if ((z & 1) == 0){ + ptr = function_bar; + } + z = ptr(z); + + switch (z&7){ + case 0: + { + z += 2; + ptr = function_bar; + }break; + + case 1: + { + z += 1; + ptr = function_bar; + }break; + + case 2: + { + z *= 2; + ptr = function_bar; + }break; + + case 3: + { + z -= 10; + ptr = function_foo; + }break; + + case 4: + { + z -= 5; + ptr = function_foo; + }break; + + case 5: + { + z = z ^ 0x10; + ptr = function_foo; + }break; + + case 6: + { + z = z & ~0x10; + ptr = function_foo; + }break; + + case 7: + { + z = z | 0x10; + ptr = function_foo; + }break; + } + + z = ptr(z); +} + +//////////////////////////////// +// NOTE(rjf): alloca (Variable-Width Stack Changes) Stepping Tests + +static void +alloca_stepping_tests(void) +{ + int x = 1; + int y = 3; + int z = 5; + +#if _WIN32 + int *mem = (int *)_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#else + int *mem = (int *)__builtin_alloca((x+y+z)*sizeof(int)); + mem[0] = x; + mem[1] = y; + mem[2] = z; +#endif +} + +//////////////////////////////// +// NOTE(allen): Overloaded Line Stepping + +static int +function_get_integer(void){ + return(1); +} + +static void +function_with_multiple_parameters(int x, int y){ + x += y; +} + +static int +recursive_single_line(int x){ return(x <= 1?0:x + recursive_single_line(x/2)); } + +static int shared_1(int x) { return(x); } static int shared_2(int x) { return(1 + shared_1(x)); } + +static void +overloaded_line_stepping_tests(void){ + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + function_with_multiple_parameters(function_get_integer(), function_get_integer()); + + recursive_single_line(50); + recursive_single_line(50); + recursive_single_line(50); + + shared_2(5); + shared_2(5); + shared_2(5); + + function_get_integer(); shared_1(1); shared_1(2); + + if ((shared_2(10) && shared_2(-1)) || + shared_2(function_get_integer())){ + int x = 0; + } + else{ + int y = 0; + } +} + +//////////////////////////////// +// NOTE(allen): Long Jump Stepping + +#include + +static jmp_buf global_jump_buffer; +static int global_jump_x; + +static void +long_jump_from_function(void){ + int spin = 0; + for (; spin < 5; spin += 1); + longjmp(global_jump_buffer, 2); + global_jump_x = spin; +} + +static void +long_jump_wrapped_in_function(void){ + global_jump_x = 0; + int val = setjmp(global_jump_buffer); + if (val == 0){ + global_jump_x = 1; + longjmp(global_jump_buffer, 1); + } + else if (val == 1){ + if (global_jump_x == 1){ + global_jump_x = 2; + long_jump_from_function(); + } + } + else if (val == 2){ + global_jump_x = 3; + } +} + +static void +long_jump_stepping_tests(void){ + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + + long_jump_wrapped_in_function(); + +} + +//////////////////////////////// +// NOTE(allen): Recursion Stepping + +static int +recursive_call(int x){ + if (x <= 1){ + return(x); + } + + int r1 = recursive_call(x - 1); + int r2 = recursive_call(x - 2); + return(r1 + r2); +} + +static int +tail_recursive_call(int x, int m){ + if (x <= 1){ + return(m); + } + return(tail_recursive_call(x - 1, x*m)); +} + +static void +recursion_stepping_tests(void){ + + recursive_call(4); + + recursive_call(4); + + tail_recursive_call(5, 1); + + tail_recursive_call(5, 1); + +} + +//////////////////////////////// +// NOTE(rjf): Debug Strings + +static void +debug_string_tests(void) +{ + for(int i = 0; i < 100; i += 1) + { + printf("here is a number: %i\n", i); + fflush(stdout); + } +#if _WIN32 + for(int i = 0; i < 100; i += 1) + { + OutputDebugStringA("Hello, World!\n"); + } + char message[65409+1]; + memset(&message[0], '=', sizeof(message)); + for(int i = 1; i < sizeof(message); i += 128) + { + message[i] = '\n'; + } + message[sizeof(message) - 1] = 0; + OutputDebugStringA(message); +#endif +} + +//////////////////////////////// +//~ rjf: Thread Name Test + +#if _WIN32 +DWORD dummy_thread(void *p) +{ + Sleep(10); + return 0; +} +#endif + +static void +thread_name_tests(void) +{ +#if _WIN32 + DWORD id = 0; + HANDLE h = CreateThread(0, 0, dummy_thread, 0, CREATE_SUSPENDED, &id); + raddbg_thread_id_name(id, "dummy_thread"); + raddbg_thread_id_color_u32(id, 0xff1f23ff); + ResumeThread(h); + WaitForSingleObject(h, INFINITE); +#endif +} + +//////////////////////////////// +//~ rjf: Interrupt Stepping Tests + +#include + +static void +interrupt_stepping_tests(void) +{ + __debugbreak(); + __debugbreak(); + __debugbreak(); + __debugbreak(); + for(int i = 0; i < 1000; i += 1) + { + if(i == 999) + { + __debugbreak(); + } + } + for(int i = 0; i < 1000; i += 1) + { + if(i == 999) + { + assert(0); + } + } + int x = 0; +} + +//////////////////////////////// +//~ rjf: JIT Stepping Tests + +static void +jit_stepping_tests(void) +{ + OutputDebugString("A\n"); + VOID *code = VirtualAlloc(0, 0x1000, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); + *((uint32_t*)code) = 0xC39090CC; + ((void (__fastcall *)()) code)(); + OutputDebugString("B\n"); +} + +//////////////////////////////// +// NOTE(allen): Exception Stepping + +static void +exception_filter_test(void) +{ + __try + { + RaiseException(0xc0000095, 0, 0, 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + OutputDebugStringA("did an exception\n"); + } +} + +int *global_null_read_pointer = 0; +static void +trip(void){ + *global_null_read_pointer = 0; +} + +static void +cpp_exception_in_function(void){ + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } +} + +static void +cpp_throw_in_function(void){ + throw 1; +} + +static void +win32_exception_in_function(void){ +#if _WIN32 + int v = 0; + __try{ + trip(); + v = 1; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 2; + } + + v = 3; + __try{ + trip(); + v = 4; + } + __except (EXCEPTION_EXECUTE_HANDLER){ + v = 5; + } +#endif +} + +static void +cpp_recursive_exception(int x){ + try{ + if (x > 1){ + throw 1; + } + } + catch (...){ + x -= 1; + cpp_recursive_exception(x); + x += 1; + } +} + +static void +win32_recursive_exception(int x){ +#if _WIN32 + __try{ + if (x > 1){ + throw 1; + } + } + __except (EXCEPTION_EXECUTE_HANDLER){ + x -= 1; + win32_recursive_exception(x); + x += 1; + } +#endif +} + +static void +exception_stepping_tests(void){ + { + int v = 0; + try{ + throw 1; + } + catch (...){ + v = 1; + } + } + + { + int v = 0; + try{ + cpp_throw_in_function(); + } + catch (...){ + v = 1; + } + } + + cpp_exception_in_function(); + cpp_exception_in_function(); + +#if _WIN32 + win32_exception_in_function(); + win32_exception_in_function(); +#endif + + // NOTE(allen): Exception in catch tests + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + try{ + v = 2; + throw 2; + } + catch (...){ + v = 3; + } + } + } + + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + cpp_exception_in_function(); + } + } + +#if _WIN32 + { + int v = 0; + try{ + v = 1; + throw 1; + } + catch (...){ + win32_exception_in_function(); + } + } +#endif + + cpp_recursive_exception(4); + cpp_recursive_exception(4); + cpp_recursive_exception(4); + +#if _WIN32 + win32_recursive_exception(4); + win32_recursive_exception(4); + win32_recursive_exception(4); +#endif + + // NOTE(allen): Try in try tests + { + int v = 0; + try{ + try{ + v = 1; + throw 1; + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + try{ + v = 1; + cpp_throw_in_function(); + } + catch (...){ + v = 2; + } + throw 2; + } + catch (...){ + v = 3; + } + } + + { + int v = 0; + try{ + cpp_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } + +#if _WIN32 + { + int v = 0; + try{ + win32_exception_in_function(); + throw 2; + } + catch (...){ + v = 3; + } + } +#endif + +} + +typedef void (*callback_t)(int a); +static void +dynamic_step_test(void){ +#if _WIN32 +#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( _M_AMD64 ) + void *page = VirtualAlloc(0, 4096, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); + char *ptr = (char*)page; + *ptr++ = 0x51; // push rcx + *ptr++ = 0x59; // pop rcx + *ptr++ = 0xC3; // ret + callback_t cb = (callback_t)page; + cb(1); +#endif +#endif +} + +//////////////////////////////// + +raddbg_entry_point(mule_main); + +int +mule_main(int argc, char** argv) +{ + raddbg_thread_name("mule_main_thread"); + raddbg_thread_color_rgba(0.4f, 0.9f, 0.2f, 1); + if(raddbg_is_attached()) + { + raddbg_log("raddbg is attached!\n"); + } + + mule_init(); + + // NOTE(allen): Eval Tests + type_coverage_eval_tests(); + + mutating_variables_eval_tests(); + + nested_types_eval_tests(); + + struct_parameters_eval_tests(); + + global_eval_tests(); + + return_eval_tests(); + + tls_eval_tests(); + + complicated_type_coverage_tests(); + + extended_type_coverage_eval_tests(); + + templated_function_eval_tests(); + + c_type_coverage_eval_tests(); + + c_type_with_bitfield_usage(); + + optimized_build_eval_tests(); + + optimized_struct_parameters_eval_tests(); + + fancy_viz_eval_tests(); + + exception_filter_test(); + + markup_tests(); + + // NOTE(allen): Stepping Tests + control_flow_stepping_tests(); + + indirect_call_jump_stepping_tests(); + + alloca_stepping_tests(); + + basic_inline_tests(); + + inline_stepping_tests(); + + overloaded_line_stepping_tests(); + + overloaded_function(100); + + dynamic_step_test(); + + long_jump_stepping_tests(); + + recursion_stepping_tests(); + + debug_string_tests(); + + thread_name_tests(); + + jit_stepping_tests(); + + interrupt_stepping_tests(); + + exception_stepping_tests(); + + return(0); +} diff --git a/src/mutable_text/mutable_text.c b/src/mutable_text/mutable_text.c index 61b6dc9b..94549be7 100644 --- a/src/mutable_text/mutable_text.c +++ b/src/mutable_text/mutable_text.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xb8a06bff + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -35,9 +38,10 @@ mtx_init(void) //~ rjf: Buffer Operations internal void -mtx_push_op(U128 buffer_key, MTX_Op op) +mtx_push_op(HS_Key buffer_key, MTX_Op op) { - MTX_MutThread *thread = &mtx_shared->mut_threads[buffer_key.u64[1]%mtx_shared->mut_threads_count]; + U64 hash = hs_little_hash_from_data(str8_struct(&buffer_key)); + MTX_MutThread *thread = &mtx_shared->mut_threads[hash%mtx_shared->mut_threads_count]; mtx_enqueue_op(thread, buffer_key, op); } @@ -45,7 +49,7 @@ mtx_push_op(U128 buffer_key, MTX_Op op) //~ rjf: Mutation Threads internal void -mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op) +mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op) { // TODO(rjf): if op.replace is too big, need to split into multiple edits OS_MutexScope(thread->mutex) for(;;) @@ -67,7 +71,7 @@ mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op) } internal void -mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out) +mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out) { OS_MutexScope(thread->mutex) for(;;) { @@ -97,7 +101,7 @@ mtx_mut_thread__entry_point(void *p) HS_Scope *hs_scope = hs_scope_open(); //- rjf: get next op - U128 buffer_key = {0}; + HS_Key buffer_key = {0}; MTX_Op op = {0}; mtx_dequeue_op(scratch.arena, mut_thread, &buffer_key, &op); diff --git a/src/mutable_text/mutable_text.h b/src/mutable_text/mutable_text.h index 505caac6..1614ae48 100644 --- a/src/mutable_text/mutable_text.h +++ b/src/mutable_text/mutable_text.h @@ -84,13 +84,13 @@ internal void mtx_init(void); //////////////////////////////// //~ rjf: Buffer Operations -internal void mtx_push_op(U128 buffer_key, MTX_Op op); +internal void mtx_push_op(HS_Key buffer_key, MTX_Op op); //////////////////////////////// //~ rjf: Mutation Threads -internal void mtx_enqueue_op(MTX_MutThread *thread, U128 buffer_key, MTX_Op op); -internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, U128 *buffer_key_out, MTX_Op *op_out); +internal void mtx_enqueue_op(MTX_MutThread *thread, HS_Key buffer_key, MTX_Op op); +internal void mtx_dequeue_op(Arena *arena, MTX_MutThread *thread, HS_Key *buffer_key_out, MTX_Op *op_out); internal void mtx_mut_thread__entry_point(void *p); #endif // MUTABLE_TEXT_H diff --git a/src/natvis/base.natvis b/src/natvis/base.natvis index ad19ed09..644b583c 100644 --- a/src/natvis/base.natvis +++ b/src/natvis/base.natvis @@ -147,6 +147,10 @@ + + + + {{ count={count} first={first} }} count @@ -158,4 +162,32 @@ + + + + + + + + + + + chunk_count + + + + + + idx = 0 + + + node->v[idx] + idx += 1 + + node = node->next + + + + + diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 3b2c73b1..a44072f7 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -443,6 +443,13 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + // TODO(rjf) + return 0; +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { @@ -562,7 +569,7 @@ os_file_iter_next(Arena *arena, OS_FileIter *iter, OS_FileInfo *info_out) { B32 good = 0; OS_LNX_FileIter *lnx_iter = (OS_LNX_FileIter *)iter->memory; - for(;;) + for(;lnx_iter->dir != 0;) { // rjf: get next entry lnx_iter->dp = readdir(lnx_iter->dir); @@ -1064,7 +1071,7 @@ os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name) OS_Handle result = {0}; if (name.size > 0) { // TODO: we need to allocate shared memory to store sem_t - NotImplemented; + // NotImplemented; } else { sem_t *s = mmap(0, sizeof(*s), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); AssertAlways(s != MAP_FAILED); diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 5f09ca8b..369070e1 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -38,13 +38,13 @@ struct OS_ProcessInfo typedef U32 OS_AccessFlags; enum { - OS_AccessFlag_Read = (1<<0), - OS_AccessFlag_Write = (1<<1), - OS_AccessFlag_Execute = (1<<2), - OS_AccessFlag_Append = (1<<3), - OS_AccessFlag_ShareRead = (1<<4), - OS_AccessFlag_ShareWrite = (1<<5), - OS_AccessFlag_Inherited = (1<<6), + OS_AccessFlag_Read = (1<<0), + OS_AccessFlag_Write = (1<<1), + OS_AccessFlag_Execute = (1<<2), + OS_AccessFlag_Append = (1<<3), + OS_AccessFlag_ShareRead = (1<<4), + OS_AccessFlag_ShareWrite = (1<<5), + OS_AccessFlag_Inherited = (1<<6), }; //////////////////////////////// @@ -202,12 +202,15 @@ internal void os_abort(S32 exit_code); internal OS_Handle os_file_open(OS_AccessFlags flags, String8 path); internal void os_file_close(OS_Handle file); internal U64 os_file_read(OS_Handle file, Rng1U64 rng, void *out_data); +#define os_file_read_struct(f, off, ptr) os_file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr)) internal U64 os_file_write(OS_Handle file, Rng1U64 rng, void *data); internal B32 os_file_set_times(OS_Handle file, DateTime time); internal FileProperties os_properties_from_file(OS_Handle file); internal OS_FileID os_id_from_file(OS_Handle file); +internal B32 os_file_reserve_size(OS_Handle file, U64 size); internal B32 os_delete_file_at_path(String8 path); internal B32 os_copy_file_path(String8 dst, String8 src); +internal B32 os_move_file_path(String8 dst, String8 src); internal String8 os_full_path_from_path(Arena *arena, String8 path); internal B32 os_file_path_exists(String8 path); internal B32 os_folder_path_exists(String8 path); @@ -326,6 +329,7 @@ internal Guid os_make_guid(void); // into the standard codebase program entry points, named "entry_point". #if BUILD_ENTRY_DEFINING_UNIT +raddbg_entry_point(entry_point); internal void entry_point(CmdLine *cmdline); #endif diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index 6a0e0281..ed69e685 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -321,13 +321,13 @@ os_file_open(OS_AccessFlags flags, String8 path) DWORD share_mode = 0; DWORD creation_disposition = OPEN_EXISTING; SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), 0, 0}; - if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} - if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} - if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} - if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} - if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} - if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} - if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS; access_flags |= FILE_APPEND_DATA; } + if(flags & OS_AccessFlag_Read) {access_flags |= GENERIC_READ;} + if(flags & OS_AccessFlag_Write) {access_flags |= GENERIC_WRITE;} + if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} + if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} + if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} + if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} + if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS; access_flags |= FILE_APPEND_DATA; } if(flags & OS_AccessFlag_Inherited) { security_attributes.bInheritHandle = 1; @@ -469,6 +469,19 @@ os_id_from_file(OS_Handle file) return result; } +internal B32 +os_file_reserve_size(OS_Handle file, U64 size) +{ + HANDLE handle = (HANDLE)file.u64[0]; + + FILE_ALLOCATION_INFO alloc_info = {0}; + alloc_info.AllocationSize.LowPart = size & max_U32; + alloc_info.AllocationSize.HighPart = (size >> 32) & max_U32; + + BOOL is_reserved = SetFileInformationByHandle(handle, FileAllocationInfo, &alloc_info, sizeof(alloc_info)); + return is_reserved; +} + internal B32 os_delete_file_at_path(String8 path) { @@ -490,6 +503,17 @@ os_copy_file_path(String8 dst, String8 src) return result; } +internal B32 +os_move_file_path(String8 dst, String8 src) +{ + Temp scratch = scratch_begin(0, 0); + String16 dst16 = str16_from_8(scratch.arena, dst); + String16 src16 = str16_from_8(scratch.arena, src); + B32 result = MoveFileW((WCHAR*)src16.str, (WCHAR*)dst16.str); + scratch_end(scratch); + return result; +} + internal String8 os_full_path_from_path(Arena *arena, String8 path) { @@ -547,6 +571,28 @@ os_properties_from_file_path(String8 path) os_w32_dense_time_from_file_time(&props.modified, &find_data.ftLastWriteTime); props.flags = os_w32_file_property_flags_from_dwFileAttributes(find_data.dwFileAttributes); } + else + { + Temp scratch = scratch_begin(0, 0); + WCHAR buffer[512] = {0}; + DWORD length = GetLogicalDriveStringsW(sizeof(buffer), buffer); + U64 last_slash_pos = 0; + for(;last_slash_pos < path.size; last_slash_pos = str8_find_needle(path, last_slash_pos+1, str8_lit("/"), StringMatchFlag_SlashInsensitive)); + String8 path_trimmed = str8_prefix(path, last_slash_pos); + for(U64 off = 0; off < (U64)length;) + { + String16 next_drive_string_16 = str16_cstring((U16 *)buffer+off); + off += next_drive_string_16.size+1; + String8 next_drive_string = str8_from_16(scratch.arena, next_drive_string_16); + next_drive_string = str8_chop_last_slash(next_drive_string); + if(str8_match(path_trimmed, next_drive_string, StringMatchFlag_CaseInsensitive)) + { + props.flags |= FilePropertyFlag_IsFolder; + break; + } + } + scratch_end(scratch); + } FindClose(handle); scratch_end(scratch); return props; @@ -666,7 +712,7 @@ os_file_iter_begin(Arena *arena, String8 path, OS_FileIterFlags flags) } else { - w32_iter->handle = FindFirstFileW((WCHAR*)path16.str, &w32_iter->find_data); + w32_iter->handle = FindFirstFileExW((WCHAR*)path16.str, FindExInfoBasic, &w32_iter->find_data, FindExSearchNameMatch, 0, FIND_FIRST_EX_LARGE_FETCH); } scratch_end(scratch); return iter; @@ -1361,6 +1407,7 @@ os_make_guid(void) #include internal B32 win32_g_is_quiet = 0; +internal B32 win32_g_gen_dump = 0; internal HRESULT WINAPI win32_dialog_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LONG_PTR data) @@ -1396,6 +1443,7 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"A fatal exception (code 0x%x) occurred. The process is terminating.\n", exception_code); // load dbghelp dynamically just in case if it is missing + BOOL (WINAPI *dbg_MiniDumpWriteDump)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam) = 0; HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); if(dbghelp) { @@ -1419,6 +1467,7 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) *(FARPROC*)&dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW"); *(FARPROC*)&dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64"); *(FARPROC*)&dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64"); + *(FARPROC*)&dbg_MiniDumpWriteDump = GetProcAddress(dbghelp, "MiniDumpWriteDump"); if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64) { @@ -1548,10 +1597,13 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND); + B32 generate_crash_dump = win32_g_gen_dump; #if BUILD_CONSOLE_INTERFACE fwprintf(stderr, L"\n--- Fatal Exception ---\n"); fwprintf(stderr, L"%s\n\n", buffer); #else + int selected_button = 0; + TASKDIALOG_BUTTON generate_dump = {1, L"Generate Crash Dump File"}; TASKDIALOGCONFIG dialog = {0}; dialog.cbSize = sizeof(dialog); dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION; @@ -1560,9 +1612,25 @@ win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) dialog.pszWindowTitle = L"Fatal Exception"; dialog.pszContent = buffer; dialog.pfCallback = &win32_dialog_callback; - TaskDialogIndirect(&dialog, 0, 0, 0); + dialog.cButtons = 1; + dialog.pButtons = &generate_dump; + TaskDialogIndirect(&dialog, &selected_button, 0, 0); + generate_crash_dump = (selected_button == generate_dump.nButtonID); #endif + if(dbg_MiniDumpWriteDump && generate_crash_dump) + { + WCHAR desktop_path[512] = {0}; + SHGetFolderPathW(0, CSIDL_DESKTOP, 0, 0, desktop_path); + WCHAR dump_file_path[512] = {0}; + wnsprintfW(dump_file_path, ArrayCount(dump_file_path), L"%s\\raddbg_crash_dump.dmp", desktop_path); + SECURITY_ATTRIBUTES security_attributes = {sizeof(security_attributes), 0, 0}; + HANDLE file = CreateFileW(dump_file_path, GENERIC_WRITE, 0, &security_attributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + BOOL dump_successful = dbg_MiniDumpWriteDump(GetCurrentProcess(), os_get_process_info()->pid, file, MiniDumpNormal, 0, 0, 0); + CloseHandle(file); + (void)dump_successful; + } + ExitProcess(1); } @@ -1649,6 +1717,11 @@ w32_entry_point_caller(int argc, WCHAR **wargv) arena_default_reserve_size = Max(MB(64), os_w32_state.system_info.large_page_size); arena_default_commit_size = arena_default_reserve_size; } + if(str8_match(arg8, str8_lit("--gen_crash_dump"), StringMatchFlag_CaseInsensitive) || + str8_match(arg8, str8_lit("-gen_crash_dump"), StringMatchFlag_CaseInsensitive)) + { + win32_g_gen_dump = 1; + } argv[i] = (char *)arg8.str; } diff --git a/src/os/gfx/linux/os_gfx_linux.c b/src/os/gfx/linux/os_gfx_linux.c index 11da04b8..f8d43416 100644 --- a/src/os/gfx/linux/os_gfx_linux.c +++ b/src/os/gfx/linux/os_gfx_linux.c @@ -36,10 +36,38 @@ os_gfx_init(void) os_lnx_gfx_state->wm_sync_request_atom = XInternAtom(os_lnx_gfx_state->display, "_NET_WM_SYNC_REQUEST", 0); os_lnx_gfx_state->wm_sync_request_counter_atom = XInternAtom(os_lnx_gfx_state->display, "_NET_WM_SYNC_REQUEST_COUNTER", 0); + //- rjf: open im + os_lnx_gfx_state->xim = XOpenIM(os_lnx_gfx_state->display, 0, 0, 0); + //- rjf: fill out gfx info os_lnx_gfx_state->gfx_info.double_click_time = 0.5f; os_lnx_gfx_state->gfx_info.caret_blink_time = 0.5f; os_lnx_gfx_state->gfx_info.default_refresh_rate = 60.f; + + //- rjf: fill out cursors + { + struct + { + OS_Cursor cursor; + unsigned int id; + } + map[] = + { + {OS_Cursor_Pointer, XC_left_ptr}, + {OS_Cursor_IBar, XC_xterm}, + {OS_Cursor_LeftRight, XC_sb_h_double_arrow}, + {OS_Cursor_UpDown, XC_sb_v_double_arrow}, + {OS_Cursor_DownRight, XC_bottom_right_corner}, + {OS_Cursor_UpRight, XC_top_right_corner}, + {OS_Cursor_UpDownLeftRight, XC_fleur}, + {OS_Cursor_HandPoint, XC_hand1}, + {OS_Cursor_Disabled, XC_X_cursor}, + }; + for EachElement(idx, map) + { + os_lnx_gfx_state->cursors[map[idx].cursor] = XCreateFontCursor(os_lnx_gfx_state->display, map[idx].id); + } + } } //////////////////////////////// @@ -71,8 +99,10 @@ os_get_clipboard_text(Arena *arena) //~ rjf: @os_hooks Windows (Implemented Per-OS) internal OS_Handle -os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) +os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title) { + Vec2F32 resolution = dim_2f32(rect); + //- rjf: allocate window OS_LNX_Window *w = os_lnx_gfx_state->free_window; if(w) @@ -117,6 +147,13 @@ os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) } XChangeProperty(os_lnx_gfx_state->display, w->window, os_lnx_gfx_state->wm_sync_request_counter_atom, XA_CARDINAL, 32, PropModeReplace, (U8 *)&w->counter_xid, 1); + //- rjf: create xic + w->xic = XCreateIC(os_lnx_gfx_state->xim, + XNInputStyle, XIMPreeditNothing|XIMStatusNothing, + XNClientWindow, w->window, + XNFocusWindow, w->window, + NULL); + //- rjf: attach name Temp scratch = scratch_begin(0, 0); String8 title_copy = push_str8_copy(scratch.arena, title); @@ -132,6 +169,19 @@ internal void os_window_close(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return;} + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + XDestroyWindow(os_lnx_gfx_state->display, w->window); +} + +internal void +os_window_set_title(OS_Handle handle, String8 title) +{ + if(os_handle_match(handle, os_handle_zero())) {return;} + Temp scratch = scratch_begin(0, 0); + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + String8 title_copy = push_str8_copy(scratch.arena, title); + XStoreName(os_lnx_gfx_state->display, w->window, (char *)title_copy.str); + scratch_end(scratch); } internal void @@ -146,19 +196,27 @@ internal void os_window_focus(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return;} + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + XSetInputFocus(os_lnx_gfx_state->display, w->window, RevertToNone, CurrentTime); } internal B32 os_window_is_focused(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return 0;} - return 0; + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + Window focused_window = 0; + int revert_to = 0; + XGetInputFocus(os_lnx_gfx_state->display, &focused_window, &revert_to); + B32 result = (w->window == focused_window); + return result; } internal B32 os_window_is_fullscreen(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return 0;} + // TODO(rjf) return 0; } @@ -166,12 +224,14 @@ internal void os_window_set_fullscreen(OS_Handle handle, B32 fullscreen) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal B32 os_window_is_maximized(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return 0;} + // TODO(rjf) return 0; } @@ -179,72 +239,92 @@ internal void os_window_set_maximized(OS_Handle handle, B32 maximized) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal B32 -os_window_is_minimized(OS_Handle window) +os_window_is_minimized(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return 0;} + // TODO(rjf) + return 0; } internal void -os_window_set_minimized(OS_Handle window, B32 minimized) +os_window_set_minimized(OS_Handle handle, B32 minimized) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_bring_to_front(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_set_monitor(OS_Handle handle, OS_Handle monitor) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_clear_custom_border_data(OS_Handle handle) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_push_custom_title_bar(OS_Handle handle, F32 thickness) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_push_custom_edges(OS_Handle handle, F32 thickness) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal void os_window_push_custom_title_bar_client_area(OS_Handle handle, Rng2F32 rect) { if(os_handle_match(handle, os_handle_zero())) {return;} + // TODO(rjf) } internal Rng2F32 os_rect_from_window(OS_Handle handle) { - return r2f32p(0, 0, 0, 0); + if(os_handle_match(handle, os_handle_zero())) {return r2f32p(0, 0, 0, 0);} + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + XWindowAttributes atts = {0}; + Status s = XGetWindowAttributes(os_lnx_gfx_state->display, w->window, &atts); + Rng2F32 result = r2f32p((F32)atts.x, (F32)atts.y, (F32)atts.x + (F32)atts.width, (F32)atts.y + (F32)atts.height); + return result; } internal Rng2F32 os_client_rect_from_window(OS_Handle handle) { - return r2f32p(0, 0, 0, 0); + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + XWindowAttributes atts = {0}; + Status s = XGetWindowAttributes(os_lnx_gfx_state->display, w->window, &atts); + Rng2F32 result = r2f32p(0, 0, (F32)atts.width, (F32)atts.height); + return result; } internal F32 os_dpi_from_window(OS_Handle handle) { - return 0; + // TODO(rjf) + return 96.f; } //////////////////////////////// @@ -254,6 +334,7 @@ internal OS_HandleArray os_push_monitors_array(Arena *arena) { OS_HandleArray result = {0}; + // TODO(rjf) return result; } @@ -261,6 +342,7 @@ internal OS_Handle os_primary_monitor(void) { OS_Handle result = {0}; + // TODO(rjf) return result; } @@ -268,28 +350,38 @@ internal OS_Handle os_monitor_from_window(OS_Handle window) { OS_Handle result = {0}; + // TODO(rjf) return result; } internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor) { + // TODO(rjf) return str8_zero(); } internal Vec2F32 os_dim_from_monitor(OS_Handle monitor) { + // TODO(rjf) return v2f32(0, 0); } +internal F32 +os_dpi_from_monitor(OS_Handle monitor) +{ + // TODO(rjf) + return 96.f; +} + //////////////////////////////// //~ rjf: @os_hooks Events (Implemented Per-OS) internal void os_send_wakeup_event(void) { - + // TODO(rjf) } internal OS_EventList @@ -300,6 +392,7 @@ os_get_events(Arena *arena, B32 wait) { XEvent evt = {0}; XNextEvent(os_lnx_gfx_state->display, &evt); + B32 set_mouse_cursor = 0; switch(evt.type) { default:{}break; @@ -309,15 +402,19 @@ os_get_events(Arena *arena, B32 wait) case KeyRelease: { // rjf: determine flags - OS_Modifiers flags = 0; - if(evt.xkey.state & ShiftMask) { flags |= OS_Modifier_Shift; } - if(evt.xkey.state & ControlMask) { flags |= OS_Modifier_Ctrl; } - if(evt.xkey.state & Mod1Mask) { flags |= OS_Modifier_Alt; } + OS_Modifiers modifiers = 0; + if(evt.xkey.state & ShiftMask) { modifiers |= OS_Modifier_Shift; } + if(evt.xkey.state & ControlMask) { modifiers |= OS_Modifier_Ctrl; } + if(evt.xkey.state & Mod1Mask) { modifiers |= OS_Modifier_Alt; } - // rjf: map keycode -> keysym - U32 keysym = XLookupKeysym(&evt.xkey, 0); + // rjf: map keycode -> keysym & codepoint + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xkey.window); + KeySym keysym = 0; + U8 text[256] = {0}; + U64 text_size = Xutf8LookupString(window->xic, &evt.xkey, (char *)text, sizeof(text), &keysym, 0); // rjf: map keysym -> OS_Key + B32 is_right_sided = 0; OS_Key key = OS_Key_Null; switch(keysym) { @@ -328,6 +425,25 @@ os_get_events(Arena *arena, B32 wait) else if('0' <= keysym && keysym <= '9') { key = OS_Key_0 + (keysym-'0'); } }break; case XK_Escape:{key = OS_Key_Esc;};break; + case XK_BackSpace:{key = OS_Key_Backspace;}break; + case XK_Delete:{key = OS_Key_Delete;}break; + case XK_Return:{key = OS_Key_Return;}break; + case XK_Pause:{key = OS_Key_Pause;}break; + case XK_Tab:{key = OS_Key_Tab;}break; + case XK_Left:{key = OS_Key_Left;}break; + case XK_Right:{key = OS_Key_Right;}break; + case XK_Up:{key = OS_Key_Up;}break; + case XK_Down:{key = OS_Key_Down;}break; + case XK_Home:{key = OS_Key_Home;}break; + case XK_End:{key = OS_Key_End;}break; + case XK_Page_Up:{key = OS_Key_PageUp;}break; + case XK_Page_Down:{key = OS_Key_PageDown;}break; + case XK_Alt_L:{ key = OS_Key_Alt; }break; + case XK_Alt_R:{ key = OS_Key_Alt; is_right_sided = 1;}break; + case XK_Shift_L:{ key = OS_Key_Shift; }break; + case XK_Shift_R:{ key = OS_Key_Shift; is_right_sided = 1;}break; + case XK_Control_L:{ key = OS_Key_Ctrl; }break; + case XK_Control_R:{ key = OS_Key_Ctrl; is_right_sided = 1;}break; case '-':{key = OS_Key_Minus;}break; case '=':{key = OS_Key_Equal;}break; case '[':{key = OS_Key_LeftBracket;}break; @@ -338,6 +454,7 @@ os_get_events(Arena *arena, B32 wait) case ',':{key = OS_Key_Comma;}break; case '/':{key = OS_Key_Slash;}break; case '\\':{key = OS_Key_BackSlash;}break; + case '\t':{key = OS_Key_Tab;}break; case 'a':case 'A':{key = OS_Key_A;}break; case 'b':case 'B':{key = OS_Key_B;}break; case 'c':case 'C':{key = OS_Key_C;}break; @@ -367,12 +484,34 @@ os_get_events(Arena *arena, B32 wait) case ' ':{key = OS_Key_Space;}break; } - // rjf: push event - OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); - OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == KeyPress ? OS_EventKind_Press : OS_EventKind_Release); - e->window.u64[0] = (U64)window; - e->flags = flags; - e->key = key; + // rjf: push text event + if(evt.type == KeyPress && text_size != 0) + { + for(U64 off = 0; off < text_size;) + { + UnicodeDecode decode = utf8_decode(text+off, text_size-off); + if(decode.codepoint != 0 && (decode.codepoint >= 32 || decode.codepoint == '\t')) + { + OS_Event *e = os_event_list_push_new(arena, &evts, OS_EventKind_Text); + e->window.u64[0] = (U64)window; + e->character = decode.codepoint; + } + if(decode.inc == 0) + { + break; + } + off += decode.inc; + } + } + + // rjf: push key event + { + OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == KeyPress ? OS_EventKind_Press : OS_EventKind_Release); + e->window.u64[0] = (U64)window; + e->modifiers = modifiers; + e->key = key; + e->right_sided = is_right_sided; + } }break; //- rjf: mouse button presses/releases @@ -380,10 +519,10 @@ os_get_events(Arena *arena, B32 wait) case ButtonRelease: { // rjf: determine flags - OS_Modifiers flags = 0; - if(evt.xbutton.state & ShiftMask) { flags |= OS_Modifier_Shift; } - if(evt.xbutton.state & ControlMask) { flags |= OS_Modifier_Ctrl; } - if(evt.xbutton.state & Mod1Mask) { flags |= OS_Modifier_Alt; } + OS_Modifiers modifiers = 0; + if(evt.xbutton.state & ShiftMask) { modifiers |= OS_Modifier_Shift; } + if(evt.xbutton.state & ControlMask) { modifiers |= OS_Modifier_Ctrl; } + if(evt.xbutton.state & Mod1Mask) { modifiers |= OS_Modifier_Alt; } // rjf: map button -> OS_Key OS_Key key = OS_Key_Null; @@ -396,11 +535,24 @@ os_get_events(Arena *arena, B32 wait) } // rjf: push event - OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xclient.window); - OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == ButtonPress ? OS_EventKind_Press : OS_EventKind_Release); - e->window.u64[0] = (U64)window; - e->flags = flags; - e->key = key; + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xbutton.window); + if(key != OS_Key_Null) + { + OS_Event *e = os_event_list_push_new(arena, &evts, evt.type == ButtonPress ? OS_EventKind_Press : OS_EventKind_Release); + e->window.u64[0] = (U64)window; + e->modifiers = modifiers; + e->key = key; + e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y); + } + else if(evt.xbutton.button == Button4 || + evt.xbutton.button == Button5) + { + OS_Event *e = os_event_list_push_new(arena, &evts, OS_EventKind_Scroll); + e->window.u64[0] = (U64)window; + e->modifiers = modifiers; + e->delta = v2f32(0, evt.xbutton.button == Button4 ? -1.f : +1.f); + e->pos = v2f32((F32)evt.xbutton.x, (F32)evt.xbutton.y); + } }break; //- rjf: mouse motion @@ -411,13 +563,18 @@ os_get_events(Arena *arena, B32 wait) e->window.u64[0] = (U64)window; e->pos.x = (F32)evt.xmotion.x; e->pos.y = (F32)evt.xmotion.y; + set_mouse_cursor = 1; }break; //- rjf: window focus/unfocus case FocusIn: + { + }break; case FocusOut: { - + OS_LNX_Window *window = os_lnx_window_from_x11window(evt.xfocus.window); + OS_Event *e = os_event_list_push_new(arena, &evts, OS_EventKind_WindowLoseFocus); + e->window.u64[0] = (U64)window; }break; //- rjf: client messages @@ -444,6 +601,21 @@ os_get_events(Arena *arena, B32 wait) } }break; } + if(set_mouse_cursor) + { + Window root_window = 0; + Window child_window = 0; + int root_rel_x = 0; + int root_rel_y = 0; + int child_rel_x = 0; + int child_rel_y = 0; + unsigned int mask = 0; + if(XQueryPointer(os_lnx_gfx_state->display, XDefaultRootWindow(os_lnx_gfx_state->display), &root_window, &child_window, &root_rel_x, &root_rel_y, &child_rel_x, &child_rel_y, &mask)) + { + XDefineCursor(os_lnx_gfx_state->display, root_window, os_lnx_gfx_state->cursors[os_lnx_gfx_state->last_set_cursor]); + XFlush(os_lnx_gfx_state->display); + } + } } return evts; } @@ -451,19 +623,38 @@ os_get_events(Arena *arena, B32 wait) internal OS_Modifiers os_get_modifiers(void) { + // TODO(rjf) return 0; } internal B32 os_key_is_down(OS_Key key) { + // TODO(rjf) return 0; } internal Vec2F32 os_mouse_from_window(OS_Handle handle) { - return v2f32(0, 0); + if(os_handle_match(handle, os_handle_zero())) {return v2f32(0, 0);} + OS_LNX_Window *w = (OS_LNX_Window *)handle.u64[0]; + Vec2F32 result = {0}; + { + Window root_window = 0; + Window child_window = 0; + int root_rel_x = 0; + int root_rel_y = 0; + int child_rel_x = 0; + int child_rel_y = 0; + unsigned int mask = 0; + if(XQueryPointer(os_lnx_gfx_state->display, w->window, &root_window, &child_window, &root_rel_x, &root_rel_y, &child_rel_x, &child_rel_y, &mask)) + { + result.x = child_rel_x; + result.y = child_rel_y; + } + } + return result; } //////////////////////////////// @@ -472,7 +663,7 @@ os_mouse_from_window(OS_Handle handle) internal void os_set_cursor(OS_Cursor cursor) { - + os_lnx_gfx_state->last_set_cursor = cursor; } //////////////////////////////// @@ -481,7 +672,18 @@ os_set_cursor(OS_Cursor cursor) internal void os_graphical_message(B32 error, String8 title, String8 message) { - + if(error) + { + fprintf(stderr, "[X] "); + } + fprintf(stderr, "%.*s\n", str8_varg(title)); + fprintf(stderr, "%.*s\n\n", str8_varg(message)); +} + +internal String8 +os_graphical_pick_file(Arena *arena, String8 initial_path) +{ + return str8_zero(); } //////////////////////////////// @@ -490,11 +692,11 @@ os_graphical_message(B32 error, String8 title, String8 message) internal void os_show_in_filesystem_ui(String8 path) { - + // TODO(rjf) } internal void os_open_in_browser(String8 url) { - + // TODO(rjf) } diff --git a/src/os/gfx/linux/os_gfx_linux.h b/src/os/gfx/linux/os_gfx_linux.h index 4ac97ab3..b0e23df2 100644 --- a/src/os/gfx/linux/os_gfx_linux.h +++ b/src/os/gfx/linux/os_gfx_linux.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -22,6 +23,7 @@ struct OS_LNX_Window OS_LNX_Window *next; OS_LNX_Window *prev; Window window; + XIC xic; XID counter_xid; U64 counter_value; }; @@ -34,12 +36,15 @@ struct OS_LNX_GfxState { Arena *arena; Display *display; + XIM xim; OS_LNX_Window *first_window; OS_LNX_Window *last_window; OS_LNX_Window *free_window; Atom wm_delete_window_atom; Atom wm_sync_request_atom; Atom wm_sync_request_counter_atom; + Cursor cursors[OS_Cursor_COUNT]; + OS_Cursor last_set_cursor; OS_GfxInfo gfx_info; }; diff --git a/src/os/gfx/os_gfx.c b/src/os/gfx/os_gfx.c index 30d09d74..7523984b 100644 --- a/src/os/gfx/os_gfx.c +++ b/src/os/gfx/os_gfx.c @@ -45,6 +45,24 @@ os_string_list_from_modifiers(Arena *arena, OS_Modifiers modifiers) return result; } +internal String8 +os_string_from_modifiers_key(Arena *arena, OS_Modifiers modifiers, OS_Key key) +{ + String8 result = {0}; + if(key != OS_Key_Null) + { + Temp scratch = scratch_begin(&arena, 1); + String8List mods = os_string_list_from_modifiers(scratch.arena, modifiers); + String8 key_string = os_g_key_display_string_table[key]; + str8_list_push(scratch.arena, &mods, key_string); + StringJoin join = {0}; + join.sep = str8_lit(" + "); + result = str8_list_join(arena, &mods, &join); + scratch_end(scratch); + } + return result; +} + internal U32 os_codepoint_from_modifiers_and_key(OS_Modifiers modifiers, OS_Key key) { @@ -138,6 +156,7 @@ os_codepoint_from_modifiers_and_key(OS_Modifiers modifiers, OS_Key key) {'X', OS_Key_X, OS_Modifier_Shift}, {'Y', OS_Key_Y, OS_Modifier_Shift}, {'Z', OS_Key_Z, OS_Modifier_Shift}, + {' ', OS_Key_Space, 0}, }; // rjf: check numeric diff --git a/src/os/gfx/os_gfx.h b/src/os/gfx/os_gfx.h index f2a860d7..1058c304 100644 --- a/src/os/gfx/os_gfx.h +++ b/src/os/gfx/os_gfx.h @@ -21,7 +21,8 @@ struct OS_GfxInfo typedef U32 OS_WindowFlags; enum { - OS_WindowFlag_CustomBorder = (1<<0), + OS_WindowFlag_CustomBorder = (1<<0), + OS_WindowFlag_UseDefaultPosition = (1<<1), }; //////////////////////////////// @@ -111,6 +112,7 @@ internal B32 frame(void); internal String8 os_string_from_event_kind(OS_EventKind kind); internal String8List os_string_list_from_modifiers(Arena *arena, OS_Modifiers flags); +internal String8 os_string_from_modifiers_key(Arena *arena, OS_Modifiers modifiers, OS_Key key); internal U32 os_codepoint_from_modifiers_and_key(OS_Modifiers flags, OS_Key key); internal void os_eat_event(OS_EventList *events, OS_Event *event); internal B32 os_key_press(OS_EventList *events, OS_Handle window, OS_Modifiers modifiers, OS_Key key); @@ -139,8 +141,9 @@ internal String8 os_get_clipboard_text(Arena *arena); //////////////////////////////// //~ rjf: @os_hooks Windows (Implemented Per-OS) -internal OS_Handle os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title); +internal OS_Handle os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title); internal void os_window_close(OS_Handle window); +internal void os_window_set_title(OS_Handle window, String8 title); internal void os_window_first_paint(OS_Handle window); internal void os_window_focus(OS_Handle window); internal B32 os_window_is_focused(OS_Handle window); @@ -168,6 +171,7 @@ internal OS_Handle os_primary_monitor(void); internal OS_Handle os_monitor_from_window(OS_Handle window); internal String8 os_name_from_monitor(Arena *arena, OS_Handle monitor); internal Vec2F32 os_dim_from_monitor(OS_Handle monitor); +internal F32 os_dpi_from_monitor(OS_Handle monitor); //////////////////////////////// //~ rjf: @os_hooks Events (Implemented Per-OS) @@ -187,6 +191,7 @@ internal void os_set_cursor(OS_Cursor cursor); //~ rjf: @os_hooks Native User-Facing Graphical Messages (Implemented Per-OS) internal void os_graphical_message(B32 error, String8 title, String8 message); +internal String8 os_graphical_pick_file(Arena *arena, String8 initial_path); //////////////////////////////// //~ rjf: @os_hooks Shell Operations diff --git a/src/os/gfx/stub/os_gfx_stub.c b/src/os/gfx/stub/os_gfx_stub.c index 34fd08c9..3a095ab2 100644 --- a/src/os/gfx/stub/os_gfx_stub.c +++ b/src/os/gfx/stub/os_gfx_stub.c @@ -34,7 +34,7 @@ os_get_clipboard_text(Arena *arena) //~ rjf: @os_hooks Windows (Implemented Per-OS) internal OS_Handle -os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) +os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title) { OS_Handle handle = {1}; return handle; @@ -45,6 +45,11 @@ os_window_close(OS_Handle window) { } +internal void +os_window_set_title(OS_Handle window, String8 title) +{ +} + internal void os_window_first_paint(OS_Handle window) { @@ -181,6 +186,12 @@ os_dim_from_monitor(OS_Handle monitor) return v; } +internal F32 +os_dpi_from_monitor(OS_Handle monitor) +{ + return 96.f; +} + //////////////////////////////// //~ rjf: @os_hooks Events (Implemented Per-OS) @@ -231,6 +242,12 @@ os_graphical_message(B32 error, String8 title, String8 message) { } +internal String8 +os_graphical_pick_file(Arena *arena, String8 initial_path) +{ + return str8_zero(); +} + //////////////////////////////// //~ rjf: @os_hooks Shell Operations diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index 33ee2a9f..e298c187 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -8,9 +8,11 @@ typedef BOOL w32_SetProcessDpiAwarenessContext_Type(void* value); typedef UINT w32_GetDpiForWindow_Type(HWND hwnd); +typedef HRESULT w32_GetDpiForMonitor_Type(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT *dpiX, UINT *dpiY); typedef int w32_GetSystemMetricsForDpi_Type(int nIndex, UINT dpi); #define w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((void*)-4) global w32_GetDpiForWindow_Type *w32_GetDpiForWindow_func = 0; +global w32_GetDpiForMonitor_Type *w32_GetDpiForMonitor_func = 0; global w32_GetSystemMetricsForDpi_Type *w32_GetSystemMetricsForDpi_func = 0; //////////////////////////////// @@ -93,6 +95,7 @@ os_w32_window_release(OS_W32_Window *window) { arena_release(window->paint_arena); } + ReleaseDC(window->hwnd, window->hdc); DestroyWindow(window->hwnd); DLLRemove(os_w32_gfx_state->first_window, os_w32_gfx_state->last_window, window); SLLStackPush(os_w32_gfx_state->free_window, window); @@ -487,7 +490,15 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_SYSCHAR: { - result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + WORD vk_code = LOWORD(wParam); + if(vk_code == VK_SPACE) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + else + { + result = 0; + } }break; case WM_CHAR: @@ -713,9 +724,10 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) // of the top hit area so manually checking that. F32 dpi = w32_GetDpiForWindow_func ? (F32)w32_GetDpiForWindow_func(hwnd) : 96.f; S32 frame_y = w32_GetSystemMetricsForDpi_func ? w32_GetSystemMetricsForDpi_func(SM_CYFRAME, dpi) : GetSystemMetrics(SM_CYFRAME); - S32 padding = w32_GetSystemMetricsForDpi_func ? w32_GetSystemMetricsForDpi_func(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER); + // NOTE(rjf): it seems incorrect to apply this padding here... + // S32 padding = w32_GetSystemMetricsForDpi_func ? w32_GetSystemMetricsForDpi_func(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER); - B32 is_over_top_resize = pos_client.y >= 0 && pos_client.y < frame_y + padding; + B32 is_over_top_resize = pos_client.y >= 0 && pos_client.y < frame_y; // + padding; B32 is_over_title_bar = pos_client.y >= 0 && pos_client.y < window->custom_border_title_thickness; //- rjf: check against title bar client areas @@ -811,6 +823,7 @@ os_gfx_init(void) (w32_SetProcessDpiAwarenessContext_Type*)GetProcAddress(module, "SetProcessDpiAwarenessContext"); w32_GetDpiForWindow_func = (w32_GetDpiForWindow_Type*)GetProcAddress(module, "GetDpiForWindow"); + w32_GetDpiForMonitor_func = (w32_GetDpiForMonitor_Type *)GetProcAddress(module, "GetDpiForMonitor"); w32_GetSystemMetricsForDpi_func = (w32_GetSystemMetricsForDpi_Type *)GetProcAddress(module, "GetSystemMetricsForDpi"); FreeLibrary(module); } @@ -818,6 +831,21 @@ os_gfx_init(void) { SetProcessDpiAwarenessContext_func(w32_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); } + else + { + HMODULE shcore = LoadLibraryA("shcore.dll"); + if(shcore) + { + typedef HRESULT (WINAPI* SetProcessDpiAwareness_t)(int); + SetProcessDpiAwareness_t SetProcessDpiAwareness = (void*)GetProcAddress(shcore, "SetProcessDpiAwareness"); + if(SetProcessDpiAwareness) + { + SetProcessDpiAwareness(2); + } + FreeLibrary(shcore); + } + SetProcessDPIAware(); + } //- rjf: register graphical-window class { @@ -1011,9 +1039,12 @@ os_get_clipboard_text(Arena *arena) //~ rjf: @os_hooks Windows (Implemented Per-OS) internal OS_Handle -os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) +os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title) { B32 custom_border = !!(flags & OS_WindowFlag_CustomBorder); + B32 use_default_position = !!(flags & OS_WindowFlag_UseDefaultPosition); + Vec2F32 pos = rect.p0; + Vec2F32 dim = dim_2f32(rect); //- rjf: make hwnd HWND hwnd = 0; @@ -1025,9 +1056,10 @@ os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) L"graphical-window", (WCHAR*)title16.str, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, - CW_USEDEFAULT, CW_USEDEFAULT, - (int)resolution.x, - (int)resolution.y, + use_default_position ? CW_USEDEFAULT : (S32)pos.x, + use_default_position ? CW_USEDEFAULT : (S32)pos.y, + (S32)dim.x, + (S32)dim.y, 0, 0, os_w32_gfx_state->hInstance, 0); @@ -1040,6 +1072,7 @@ os_window_open(Vec2F32 resolution, OS_WindowFlags flags, String8 title) OS_W32_Window *window = os_w32_window_alloc(); { window->hwnd = hwnd; + window->hdc = GetDC(hwnd); if(w32_GetDpiForWindow_func != 0) { window->dpi = (F32)w32_GetDpiForWindow_func(hwnd); @@ -1076,6 +1109,16 @@ os_window_close(OS_Handle handle) os_w32_window_release(window); } +internal void +os_window_set_title(OS_Handle handle, String8 title) +{ + Temp scratch = scratch_begin(0, 0); + OS_W32_Window *window = os_w32_window_from_handle(handle); + String16 title16 = str16_from_8(scratch.arena, title); + SetWindowTextW(window->hwnd, (WCHAR *)title16.str); + scratch_end(scratch); +} + internal void os_window_first_paint(OS_Handle window_handle) { @@ -1385,6 +1428,21 @@ os_dim_from_monitor(OS_Handle monitor) return result; } +internal F32 +os_dpi_from_monitor(OS_Handle monitor) +{ + F32 result = 96.f; + HMONITOR monitor_handle = (HMONITOR)monitor.u64[0]; + if(w32_GetDpiForMonitor_func != 0) + { + UINT dpi_x = 0; + UINT dpi_y = 0; + HRESULT hr = w32_GetDpiForMonitor_func(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); + result = (F32)dpi_x; + } + return result; +} + //////////////////////////////// //~ rjf: @os_hooks Events (Implemented Per-OS) @@ -1519,6 +1577,29 @@ os_graphical_message(B32 error, String8 title, String8 message) scratch_end(scratch); } +internal String8 +os_graphical_pick_file(Arena *arena, String8 initial_path) +{ + String8 result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + U64 buffer_size = 4096; + U16 *buffer = push_array(scratch.arena, U16, buffer_size); + OPENFILENAMEW params = {sizeof(params)}; + { + params.lpstrFile = (WCHAR *)buffer; + params.nMaxFile = buffer_size; + params.lpstrInitialDir = (WCHAR *)str16_from_8(scratch.arena, initial_path).str; + } + if(GetOpenFileNameW(¶ms)) + { + result = str8_from_16(arena, str16_cstring((U16 *)buffer)); + } + scratch_end(scratch); + } + return result; +} + //////////////////////////////// //~ rjf: @os_hooks Shell Operations diff --git a/src/os/gfx/win32/os_gfx_win32.h b/src/os/gfx/win32/os_gfx_win32.h index d47c4df4..3ab4de16 100644 --- a/src/os/gfx/win32/os_gfx_win32.h +++ b/src/os/gfx/win32/os_gfx_win32.h @@ -15,6 +15,7 @@ #pragma comment(lib, "UxTheme") #pragma comment(lib, "ole32") #pragma comment(lib, "user32") +#pragma comment(lib, "comdlg32") #ifndef WM_NCUAHDRAWCAPTION #define WM_NCUAHDRAWCAPTION (0x00AE) #endif @@ -38,6 +39,7 @@ struct OS_W32_Window OS_W32_Window *next; OS_W32_Window *prev; HWND hwnd; + HDC hdc; WINDOWPLACEMENT last_window_placement; F32 dpi; B32 first_paint_done; diff --git a/src/path/path.c b/src/path/path.c index b4817291..32c928b7 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -2,27 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ allen: Path Helper Functions - -internal StringMatchFlags -path_match_flags_from_os(OperatingSystem os) -{ - StringMatchFlags flags = StringMatchFlag_SlashInsensitive; - switch(os) - { - default:{}break; - case OperatingSystem_Windows: - { - flags |= StringMatchFlag_CaseInsensitive; - }break; - case OperatingSystem_Linux: - case OperatingSystem_Mac: - { - // NOTE(rjf): no-op - }break; - } - return flags; -} +//~ rjf: Relative <-> Absolute Path internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) @@ -31,7 +11,7 @@ path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) // rjf: gather path parts String8 dst_name = str8_skip_last_slash(dst); - String8 src_folder = str8_chop_last_slash(src); + String8 src_folder = src; String8 dst_folder = str8_chop_last_slash(dst); String8List src_folders = str8_split_path(scratch.arena, src_folder); String8List dst_folders = str8_split_path(scratch.arena, dst_folder); @@ -58,7 +38,7 @@ path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src) String8 dst_path = {0}; if(num_backtracks >= src_folders.node_count) { - dst_path = path_normalized_from_string(arena, dst); + dst_path = dst; } else { @@ -110,69 +90,135 @@ path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src) { String8 result = dst; PathStyle dst_style = path_style_from_str8(dst); - if(dst_style == PathStyle_Relative) + if(dst.size != 0 && dst_style == PathStyle_Relative) { Temp scratch = scratch_begin(&arena, 1); String8 dst_from_src_absolute = push_str8f(scratch.arena, "%S/%S", src, dst); - String8 dst_from_src_absolute_normalized = path_normalized_from_string(arena, dst_from_src_absolute); - result = dst_from_src_absolute_normalized; + String8List dst_from_src_absolute_parts = str8_split_path(scratch.arena, dst_from_src_absolute); + PathStyle dst_from_src_absolute_style = path_style_from_str8(src); + str8_path_list_resolve_dots_in_place(&dst_from_src_absolute_parts, dst_from_src_absolute_style); + result = str8_path_list_join_by_style(arena, &dst_from_src_absolute_parts, dst_from_src_absolute_style); scratch_end(scratch); } return result; } +//////////////////////////////// +//~ rjf: Path Normalization + internal String8List -path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out){ - // analyze path +path_normalized_list_from_string(Arena *arena, String8 path_string, PathStyle *style_out) +{ + // rjf: analyze path PathStyle path_style = path_style_from_str8(path_string); String8List path = str8_split_path(arena, path_string); - // prepend current path to convert relative -> absolute - PathStyle path_style_full = path_style; - if (path.node_count != 0 && path_style == PathStyle_Relative){ - String8 current_path_string = os_get_current_path(arena); - - PathStyle current_path_style = path_style_from_str8(current_path_string); - Assert(current_path_style != PathStyle_Relative); - - String8List current_path = str8_split_path(arena, current_path_string); - str8_list_concat_in_place(¤t_path, &path); - path = current_path; - path_style_full = current_path_style; - } + // rjf: resolve dots + str8_path_list_resolve_dots_in_place(&path, path_style); - // resolve dots - str8_path_list_resolve_dots_in_place(&path, path_style_full); - - // return - if (style_out != 0){ - *style_out = path_style_full; + // rjf: return + if(style_out != 0) + { + *style_out = path_style; } - return(path); + return path; } internal String8 -path_normalized_from_string(Arena *arena, String8 path_string){ +path_normalized_from_string(Arena *arena, String8 path_string) +{ Temp scratch = scratch_begin(&arena, 1); - PathStyle style = PathStyle_Relative; String8List path = path_normalized_list_from_string(scratch.arena, path_string, &style); - String8 result = str8_path_list_join_by_style(arena, &path, style); scratch_end(scratch); - return(result); + return result; } internal B32 path_match_normalized(String8 left, String8 right) { - B32 result = 0; + Temp scratch = scratch_begin(0, 0); + String8 left_normalized = path_normalized_from_string(scratch.arena, left); + String8 right_normalized = path_normalized_from_string(scratch.arena, right); + B32 result = str8_match(left_normalized, right_normalized, StringMatchFlag_CaseInsensitive); + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal PathStyle +path_style_from_string(String8 string) +{ + for (U64 i = 0; i < ArrayCount(g_path_style_map); ++i) { - Temp scratch = scratch_begin(0, 0); - String8 left_normalized = path_normalized_from_string(scratch.arena, left); - String8 right_normalized = path_normalized_from_string(scratch.arena, right); - result = str8_match(left_normalized, right_normalized, StringMatchFlag_CaseInsensitive); - scratch_end(scratch); + if(str8_match(g_path_style_map[i].string, string, StringMatchFlag_CaseInsensitive)) + { + return g_path_style_map[i].path_style; + } + } + return PathStyle_Null; +} + +internal String8 +string_from_path_style(PathStyle style) +{ + Assert(style < ArrayCount(g_path_style_map)); + return g_path_style_map[style].string; +} + +internal String8 +path_separator_string_from_style(PathStyle style) +{ + String8 result = str8_zero(); + switch (style) + { + case PathStyle_Null: break; + case PathStyle_Relative: break; + case PathStyle_WindowsAbsolute: result = str8_lit("\\"); break; + case PathStyle_UnixAbsolute: result = str8_lit("/"); break; } return result; } + +internal StringMatchFlags +path_match_flags_from_os(OperatingSystem os) +{ + StringMatchFlags flags = StringMatchFlag_SlashInsensitive; + switch(os) + { + default:{}break; + case OperatingSystem_Windows: + { + flags |= StringMatchFlag_CaseInsensitive; + }break; + case OperatingSystem_Linux: + case OperatingSystem_Mac: + { + // NOTE(rjf): no-op + }break; + } + return flags; +} + +internal String8 +path_convert_slashes(Arena *arena, String8 path, PathStyle path_style) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = str8_split_path(scratch.arena, path); + StringJoin join = {0}; + join.sep = path_separator_string_from_style(path_style); + String8 result = str8_list_join(arena, &list, &join); + scratch_end(scratch); + return result; +} + +internal String8 +path_replace_file_extension(Arena *arena, String8 file_name, String8 ext) +{ + String8 file_name_no_ext = str8_chop_last_dot(file_name); + String8 result = push_str8f(arena, "%S.%S", file_name_no_ext, ext); + return result; +} diff --git a/src/path/path.h b/src/path/path.h index dd110eb1..0aa18ec2 100644 --- a/src/path/path.h +++ b/src/path/path.h @@ -5,13 +5,26 @@ #define PATH_H //////////////////////////////// -//~ allen: Path Helper Functions +//~ rjf: Relative <-> Absolute Path -internal StringMatchFlags path_match_flags_from_os(OperatingSystem os); internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src); internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src); + +//////////////////////////////// +//~ rjf: Path Normalization + internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out); -internal String8 path_normalized_from_string(Arena *arena, String8 path); -internal B32 path_match_normalized(String8 left, String8 right); +internal String8 path_normalized_from_string(Arena *arena, String8 path); +internal B32 path_match_normalized(String8 left, String8 right); + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal PathStyle path_style_from_string(String8 string); +internal String8 string_from_path_style(PathStyle style); +internal String8 path_separator_string_from_style(PathStyle style); +internal StringMatchFlags path_match_flags_from_os(OperatingSystem os); +internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style); +internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext); #endif //PATH_H diff --git a/src/pdb/pdb_parse.c b/src/pdb/pdb_parse.c index 5ae4bff3..8d75a0d2 100644 --- a/src/pdb/pdb_parse.c +++ b/src/pdb/pdb_parse.c @@ -74,34 +74,50 @@ pdb_info_from_data(Arena *arena, String8 data){ // table layout: epilogue U32 epilogue_base_off = deleted_words_array_off + num_deleted_words*sizeof(U32); - // read table - if (hash_table_count > 0 && epilogue_base_off <= data.size){ - PDB_InfoNode *first = 0; - PDB_InfoNode *last = 0; - - U32 record_off = epilogue_base_off; - for (U32 i = 0; i < hash_table_count; i += 1, record_off += 8){ - U32 *record = (U32*)(data.str + record_off); - U32 relative_name_off = record[0]; - MSF_StreamNumber sn = (MSF_StreamNumber)record[1]; + if (epilogue_base_off <= data.size){ + U64 record_off = epilogue_base_off; + + // read table + if (hash_table_count > 0) { + PDB_InfoNode *first = 0; + PDB_InfoNode *last = 0; - U32 name_off = names_base_off + relative_name_off; - String8 name = str8_cstring_capped((char*)(data.str + name_off), - (char*)(data.str + names_base_opl)); + for (U32 i = 0; i < hash_table_count; i += 1, record_off += 8){ + U32 *record = (U32*)(data.str + record_off); + U32 relative_name_off = record[0]; + MSF_StreamNumber sn = (MSF_StreamNumber)record[1]; + + U32 name_off = names_base_off + relative_name_off; + String8 name = str8_cstring_capped((char*)(data.str + name_off), + (char*)(data.str + names_base_opl)); + + // push info node + PDB_InfoNode *node = push_array(arena, PDB_InfoNode, 1); + SLLQueuePush(first, last, node); + node->string = name; + node->sn = sn; + } - // push info node - PDB_InfoNode *node = push_array(arena, PDB_InfoNode, 1); - SLLQueuePush(first, last, node); - node->string = name; - node->sn = sn; + result = push_array(arena, PDB_Info, 1); + result->first = first; + result->last = last; + result->auth_guid = *auth_guid; } - - result = push_array(arena, PDB_Info, 1); - result->first = first; - result->last = last; - result->auth_guid = *auth_guid; + + // read PDB features + PDB_FeatureFlags features = 0; + for (; record_off + sizeof(PDB_FeatureSig) <= data.size; ) { + PDB_FeatureSig sig = 0; + record_off += str8_deserial_read_struct(data, record_off, &sig); + switch (sig) { + case PDB_FeatureSig_NULL: break; + case PDB_FeatureSig_VC140: features |= PDB_FeatureFlag_HAS_ID_STREAM; break; + case PDB_FeatureSig_NO_TYPE_MERGE: features |= PDB_FeatureFlag_NO_TYPE_MERGE; break; + case PDB_FeatureSig_MINIMAL_DEBUG_INFO: features |= PDB_FeatureFlag_MINIMAL_DBG_INFO; break; + } + } + result->features = features; } - } } diff --git a/src/pdb/pdb_parse.h b/src/pdb/pdb_parse.h index eb9f56e7..ec827408 100644 --- a/src/pdb/pdb_parse.h +++ b/src/pdb/pdb_parse.h @@ -45,6 +45,7 @@ typedef struct PDB_Info PDB_InfoNode *first; PDB_InfoNode *last; Guid auth_guid; + PDB_FeatureFlags features; } PDB_Info; typedef struct PDB_InfoHeader diff --git a/src/pe/pe.c b/src/pe/pe.c index b823bbbf..36c9e423 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -408,6 +408,20 @@ pe_subsystem_from_string(String8 string) //////////////////////////////// //~ rjf: Parser Functions +internal B32 +pe_check_magic(String8 data) +{ + B32 is_pe = 0; + PE_DosHeader dos_header = {0}; + str8_deserial_read_struct(data, 0, &dos_header); + if (dos_header.magic == PE_DOS_MAGIC) { + U32 pe_magic = 0; + str8_deserial_read_struct(data, dos_header.coff_file_offset, &pe_magic); + is_pe= pe_magic == PE_MAGIC; + } + return is_pe; +} + internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data) { @@ -554,8 +568,8 @@ pe_bin_info_from_data(Arena *arena, String8 data) switch(file_header.machine) { default:{ NotImplemented; }break; - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: { PE_TLSHeader32 tls_header32 = {0}; if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header32) == sizeof(tls_header32)) @@ -572,7 +586,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) Assert(!"unable to read TLS Header 32"); } }break; - case COFF_Machine_X64: + case COFF_MachineType_X64: { if(str8_deserial_read_struct(data, tls_header_frng.min, &tls_header) != sizeof(tls_header)) { @@ -586,20 +600,20 @@ pe_bin_info_from_data(Arena *arena, String8 data) // rjf: fill info if(valid) { - info.image_base = image_base; - info.entry_point = entry_point; - info.is_pe32 = (optional_magic == PE_PE32_MAGIC); - info.virt_section_align = virt_section_align; - info.file_section_align = file_section_align; - info.section_array_off = sec_array_off; - info.section_count = clamped_sec_count; - info.symbol_array_off = symbol_array_off; - info.symbol_count = symbol_count; - info.string_table_off = string_table_off; - info.data_dir_franges = data_dir_franges; - info.data_dir_count = data_dir_count; - info.arch = arch_from_coff_machine(file_header.machine); - info.tls_header = tls_header; + info.arch = arch_from_coff_machine(file_header.machine); + info.image_base = image_base; + info.entry_point = entry_point; + info.is_pe32 = (optional_magic == PE_PE32_MAGIC); + info.virt_section_align = virt_section_align; + info.file_section_align = file_section_align; + info.section_count = clamped_sec_count; + info.symbol_count = symbol_count; + info.section_table_range = rng_1u64(sec_array_off, sec_array_off + sizeof(COFF_SectionHeader) * clamped_sec_count); + info.symbol_table_range = rng_1u64(symbol_array_off, symbol_array_off + sizeof(COFF_Symbol16) * symbol_count); + info.string_table_range = rng_1u64(string_table_off, data.size); + info.data_dir_franges = data_dir_franges; + info.data_dir_count = data_dir_count; + info.tls_header = tls_header; } return info; @@ -748,80 +762,15 @@ pe_pdata_off_from_voff__binary_search_x8664(String8 raw_pdata, U64 voff) return result; } -internal void * -pe_ptr_from_voff(String8 data, PE_BinInfo *bin, U64 voff) -{ - // rjf: get the section for this voff - U64 sec_count = bin->section_count; - COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); - COFF_SectionHeader *sec_ptr = sec_array; - COFF_SectionHeader *sec = 0; - for(U64 i = 1; i <= sec_count; i += 1, sec_ptr += 1) - { - if(sec_ptr->voff <= voff && voff < sec_ptr->voff + sec_ptr->vsize) - { - sec = sec_ptr; - break; - } - } - - // rjf: adjust to file pointer - void *result = 0; - if(sec != 0 && sec_ptr->fsize > 0) - { - U64 off = voff - sec->voff + sec->foff; - if(off < data.size) - { - result = data.str + off; - } - } - return result; -} - -internal U64 -pe_section_num_from_voff(String8 data, PE_BinInfo *bin, U64 voff) -{ - U64 sec_count = bin->section_count; - COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); - COFF_SectionHeader *sec_ptr = sec_array; - U64 result = 0; - for(U64 i = 1; i <= sec_count; i += 1, sec_ptr += 1) - { - if(sec_ptr->voff <= voff && voff < sec_ptr->voff + sec_ptr->vsize) - { - result = i; - break; - } - } - return result; -} - -internal void * -pe_ptr_from_section_num(String8 data, PE_BinInfo *bin, U64 n) -{ - void *result = 0; - U64 sec_count = bin->section_count; - if(1 <= n && n <= sec_count) - { - COFF_SectionHeader *sec_array = (COFF_SectionHeader*)((U8*)data.str + bin->section_array_off); - COFF_SectionHeader *sec = sec_array + n - 1; - if(sec->fsize > 0) - { - result = data.str + sec->foff; - } - } - return(result); -} - internal U64 pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff) { - U64 foff = 0; - COFF_SectionHeader *sections = (COFF_SectionHeader*)(data.str+bin->section_array_off); - U64 section_count = bin->section_count; - for(U64 sect_idx = 0; sect_idx < section_count; sect_idx += 1) + U64 foff = 0; + String8 raw_section_table = str8_substr(data, bin->section_table_range); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; + for(U64 sect_idx = 0; sect_idx < bin->section_count; sect_idx += 1) { - COFF_SectionHeader *sect = §ions[sect_idx]; + COFF_SectionHeader *sect = §ion_table[sect_idx]; if(sect->voff <= voff && voff < sect->voff + sect->vsize) { if(!(sect->flags & COFF_SectionFlag_CntUninitializedData)) @@ -967,7 +916,7 @@ pe_get_entry_point_names(COFF_MachineType machine, String8Array entry_point_names = {0}; if (file_characteristics & PE_ImageFileCharacteristic_FILE_DLL) { - if (machine == COFF_Machine_X86) { + if (machine == COFF_MachineType_X86) { read_only static String8 dll_entry_point_arr[] = { str8_lit_comp("__DllMainCRTStartup@12"), }; @@ -1418,8 +1367,8 @@ pe_tls_from_data(Arena *arena, U64 *callback_addrs = 0; switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: { PE_TLSHeader32 header32 = {0}; str8_deserial_read_struct(raw_tls, 0, &header32); @@ -1444,7 +1393,7 @@ pe_tls_from_data(Arena *arena, callback_addrs[i] = (U64)src[i]; } } break; - case COFF_Machine_X64: { + case COFF_MachineType_X64: { str8_deserial_read_struct(raw_tls, 0, &header64); U64 callbacks_voff = header64.callbacks_address - image_base; @@ -1554,7 +1503,7 @@ pe_resource_dir_push_dir(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID id, internal PE_ResourceNode * pe_resource_dir_search_node(PE_ResourceDir *dir, COFF_ResourceID id) { - for (PE_ResourceNode *i = dir->id_list.first; i != NULL; i = i->next) { + for (PE_ResourceNode *i = dir->id_list.first; i != 0; i = i->next) { if (coff_resource_id_compar(&i->data.id, &id) == 0) { return i; } diff --git a/src/pe/pe.h b/src/pe/pe.h index c6e40254..7dadd496 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -993,17 +993,17 @@ struct PE_HandlerScope typedef struct PE_BinInfo PE_BinInfo; struct PE_BinInfo { + Arch arch; U64 image_base; U64 entry_point; B32 is_pe32; U64 virt_section_align; U64 file_section_align; - U64 section_array_off; U64 section_count; - U64 symbol_array_off; U64 symbol_count; - U64 string_table_off; - Arch arch; + Rng1U64 section_table_range; + Rng1U64 symbol_table_range; + Rng1U64 string_table_range; Rng1U64 *data_dir_franges; U32 data_dir_count; PE_TLSHeader64 tls_header; @@ -1072,6 +1072,7 @@ internal String8 pe_string_from_dll_characteristics(Arena *arena, PE_DllCharacte //////////////////////////////// //~ rjf: Parser Functions +internal B32 pe_check_magic(String8 data); internal PE_BinInfo pe_bin_info_from_data(Arena *arena, String8 data); internal PE_DebugInfoList pe_parse_debug_directory(Arena *arena, String8 raw_image, String8 raw_debug_dir); @@ -1084,9 +1085,6 @@ internal PE_ParsedTLS pe_tls_from_data(Arena *arena, COFF_MachineT //~ rjf: Helpers internal U64 pe_pdata_off_from_voff__binary_search_x8664(String8 raw_data, U64 voff); -internal void * pe_ptr_from_voff(String8 data, PE_BinInfo *bin, U64 voff); -internal U64 pe_section_num_from_voff(String8 data, PE_BinInfo *bin, U64 voff); -internal void * pe_ptr_from_section_num(String8 data, PE_BinInfo *bin, U64 n); internal U64 pe_foff_from_voff(String8 data, PE_BinInfo *bin, U64 voff); internal PE_BaseRelocBlockList pe_base_reloc_block_list_from_data(Arena *arena, String8 raw_relocs); internal Rng1U64 pe_tls_rng_from_bin_base_vaddr(String8 data, PE_BinInfo *bin, U64 base_vaddr); diff --git a/src/radcon/radcon.c b/src/radcon/radcon.c new file mode 100644 index 00000000..c66e40ea --- /dev/null +++ b/src/radcon/radcon.c @@ -0,0 +1,481 @@ +internal String8 +rc_data_from_file_path(Arena *arena, String8 path) +{ + String8 data = os_data_from_file_path(arena, path); + if (data.size == 0) { + fprintf(stderr, "error: unable to read file %.*s\n", str8_varg(path)); + os_abort(1); + } + return data; +} + +internal RC_Context +rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl) +{ + Temp scratch = scratch_begin(&arena, 1); + + if (cmdl->inputs.node_count > 2) { + fprintf(stderr, "error: too many input files on the command line.\n"); + os_abort(1); + } + + B32 is_pe_present = 0; + B32 is_pdb_present = 0; + B32 is_elf_present = 0; + B32 is_elf_debug_present = 0; + String8 pe_name = {0}; + String8 pe_data = {0}; + String8 pdb_name = {0}; + String8 pdb_data = {0}; + String8 elf_name = {0}; + String8 elf_data = {0}; + String8 elf_debug_name = {0}; + String8 elf_debug_data = {0}; + + // + // Set typed inputs + // + if (cmd_line_has_flag(cmdl, str8_lit("pe"))) { + pe_name = cmd_line_string(cmdl, str8_lit("pe")); + pe_data = rc_data_from_file_path(arena, pe_name); + if (!pe_check_magic(pe_data)) { + fprintf(stderr, "error: -pe:%.*s is not of PE format\n", str8_varg(pe_name)); + os_abort(1); + } + is_pe_present = 1; + } + if (cmd_line_has_flag(cmdl, str8_lit("pdb"))) { + pdb_name = cmd_line_string(cmdl, str8_lit("pdb")); + pdb_data = rc_data_from_file_path(arena, pdb_name); + if (!msf_check_magic_20(pdb_data) && !msf_check_magic_70(pdb_data)) { + fprintf(stderr, "error: -pdb:%.*s is not of PDB format\n", str8_varg(pdb_name)); + os_abort(1); + } + is_pdb_present = 1; + } + if (cmd_line_has_flag(cmdl, str8_lit("elf"))) { + elf_name = cmd_line_string(cmdl, str8_lit("elf")); + elf_data = rc_data_from_file_path(arena, elf_name); + if (!elf_check_magic(elf_data)) { + fprintf(stderr, "error: -elf:%.*s is not of ELF format\n", str8_varg(elf_name)); + os_abort(1); + } + is_elf_present = 1; + } + if (cmd_line_has_flag(cmdl, str8_lit("elf_debug"))) { + elf_debug_name = cmd_line_string(cmdl, str8_lit("elf_debug")); + elf_debug_data = rc_data_from_file_path(arena, elf_debug_name); + if (!elf_check_magic(elf_debug_data)) { + fprintf(stderr, "error: -elf_debug:%.*s is not of ELF format\n", str8_varg(elf_debug_name)); + os_abort(1); + } + is_elf_debug_present = 1; + } + + // + // Pick conversion driver + // + RC_Driver driver = RC_Driver_Null; + if (cmd_line_has_flag(cmdl, str8_lit("driver"))) { + String8 driver_name = cmd_line_string(cmdl, str8_lit("driver")); + if (str8_match(driver_name, str8_lit("dwarf"), StringMatchFlag_CaseInsensitive)) { + driver = RC_Driver_Dwarf; + } else if (str8_match(driver_name, str8_lit("pdb"), StringMatchFlag_CaseInsensitive)) { + driver = RC_Driver_Pdb; + } else { + fprintf(stderr, "error: unknown driver \"%.*s\"\n", str8_varg(driver_name)); + os_abort(1); + } + } + + // + // Load inputs + // + for (String8Node *input_n = cmdl->inputs.first; input_n != 0; input_n = input_n->next) { + String8 input_data = os_data_from_file_path(arena, input_n->string); + + if (input_data.size == 0) { + fprintf(stderr, "unable to read input %.*s\n", str8_varg(input_n->string)); + os_abort(1); + } + + if (pe_check_magic(input_data)) { + if (is_pe_present) { + fprintf(stderr, "error: too many PE files are specified on the command line\n"); + fprintf(stderr, " selected: %.*s\n", str8_varg(pe_name)); + fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string)); + os_abort(1); + } + pe_data = input_data; + pe_name = input_n->string; + is_pe_present = 1; + } else if (elf_check_magic(input_data)) { + ELF_BinInfo elf = elf_bin_from_data(input_data); + B32 is_dwarf_present = dw_is_dwarf_present_elf_section_table(input_data, &elf); + if (is_dwarf_present) { + if (is_elf_debug_present) { + fprintf(stderr, "error: ambiguous input, both ELFs have DWARF debug sections, please use --elf: --elf_debug: to clarify inputs.\n"); + os_abort(1); + } + elf_debug_name = input_n->string; + elf_debug_data = input_data; + is_elf_debug_present = 1; + } else { + elf_name = input_n->string; + elf_data = input_data; + is_elf_present = 1; + } + } else if (msf_check_magic_20(input_data) || msf_check_magic_70(input_data)) { + if (is_pdb_present) { + fprintf(stderr, "error: too many PDB files are specified on the command line\n"); + fprintf(stderr, " selected: %.*s\n", str8_varg(pdb_name)); + fprintf(stderr, " current: %.*s\n", str8_varg(input_n->string)); + continue; + } + pdb_name = input_n->string; + pdb_data = input_data; + is_pdb_present = 1; + } else { + fprintf(stderr, "error: unknown file format %.*s\n", str8_varg(input_n->string)); + } + } + + // + // Validate input combos + // + if ((is_pe_present || is_pdb_present) && (is_elf_present || is_elf_debug_present)) { + fprintf(stderr, "error: invalid combination of inputs provided, we convert only (PE|PDB) or (ELF|ELF_DEBUG) at a time.\n"); + if (is_pe_present) { + fprintf(stderr, " PE: %.*s\n", str8_varg(pe_name)); + } + if (is_pdb_present) { + fprintf(stderr, " PDB: %.*s\n", str8_varg(pdb_name)); + } + if (is_elf_present) { + fprintf(stderr, " ELF: %.*s\n", str8_varg(elf_name)); + } + if (is_elf_debug_present) { + fprintf(stderr, " ELF Debug: %.*s\n", str8_varg(elf_debug_name)); + } + os_abort(1); + } + + if (is_pe_present && (is_elf_present || is_elf_debug_present)) { + fprintf(stderr, "error: command line has too many image types specified.\n"); + os_abort(1); + } + + + ImageType image = Image_Null; + String8 image_name = {0}; + String8 image_data = {0}; + String8 debug_name = {0}; + String8 debug_data = {0}; + + B32 check_guid = 0; + Guid pe_pdb_guid = {0}; + + B32 elf_has_debug_link = 0; + ELF_GnuDebugLink debug_link = {0}; + + // + // Input has PE/COFF + // + if (is_pe_present) { + image = Image_CoffPe; + image_name = pe_name; + image_data = pe_data; + + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, pe_data); + String8 raw_debug_dir = str8_substr(pe_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); + PE_DebugInfoList debug_dir = pe_parse_debug_directory(scratch.arena, pe_data, raw_debug_dir); + for (PE_DebugInfoNode *debug_n = debug_dir.first; debug_n != 0; debug_n = debug_n->next) { + PE_DebugInfo *debug = &debug_n->v; + if (debug->header.type == PE_DebugDirectoryType_CODEVIEW) { + if (debug->u.codeview.magic == PE_CODEVIEW_PDB70_MAGIC) { + check_guid = 1; + pe_pdb_guid = debug->u.codeview.pdb70.header.guid; + + if (!is_pdb_present) { + pdb_name = debug->u.codeview.pdb70.path; + pdb_data = rc_data_from_file_path(arena, pdb_name); + is_pdb_present = 1; + } + + break; + } + } + } + + if (driver == RC_Driver_Null || driver == RC_Driver_Dwarf) { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, pe_data); + String8 raw_section_table = str8_substr(pe_data, pe.section_table_range); + String8 string_table = str8_substr(pe_data, pe.string_table_range); + U64 section_count = raw_section_table.size / sizeof(COFF_SectionHeader); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; + if (dw_is_dwarf_present_coff_section_table(pe_data, string_table, section_count, section_table)) { + driver = RC_Driver_Dwarf; + debug_name = pe_name; + debug_data = pe_data; + goto driver_found; + } else if (driver == RC_Driver_Dwarf) { + fprintf(stderr, "error: image doesn't have DWARF debug sections.\n"); + os_abort(1); + } + } + } + + if (is_elf_present || is_elf_debug_present) { + if (driver != RC_Driver_Null && driver != RC_Driver_Dwarf) { + fprintf(stderr, "error: ELF inputs are only supported when using DWARF driver.\n"); + os_abort(1); + } + + // + // Load image ELF + // + ELF_BinInfo elf = elf_bin_from_data(elf_data); + B32 has_elf_dwarf = dw_is_dwarf_present_elf_section_table(elf_data, &elf); + + // + // ELF doesn't have debug info and no .debug was specified on command line, + // try to load .debug via debug link + // + if (is_elf_present && !is_elf_debug_present) { + elf_has_debug_link = elf_parse_debug_link(elf_data, &elf, &debug_link); + } + if (elf_has_debug_link) { + elf_debug_data = rc_data_from_file_path(arena, debug_link.path); + is_elf_debug_present = 1; + } + + // + // Load .debug ELF + // + ELF_BinInfo elf_debug = elf_bin_from_data(elf_debug_data); + B32 has_elf_debug_dwarf = dw_is_dwarf_present_elf_section_table(elf_debug_data, &elf_debug); + + // + // Input is image ELF and .debug ELF + // + B32 is_split_elf = is_elf_present && is_elf_debug_present && !has_elf_dwarf && has_elf_debug_dwarf; + if (is_split_elf) { + driver = RC_Driver_Dwarf; + image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? Image_Elf64 : Image_Elf32; + image_name = elf_name; + image_data = elf_data; + debug_name = elf_debug_name; + debug_data = elf_debug_data; + goto driver_found; + } + + // + // Input ELF is image with debug info + // + B32 is_monolithic_elf = is_elf_present && !is_elf_debug_present && has_elf_dwarf; + if (is_monolithic_elf) { + driver = RC_Driver_Dwarf; + image = ELF_HdrIs64Bit(elf.hdr.e_ident) ? Image_Elf64 : Image_Elf32; + image_name = elf_name; + image_data = elf_data; + debug_name = elf_name; + debug_data = elf_data; + goto driver_found; + } + + // + // Input ELF is .debug + // + B32 is_debug_elf = !is_elf_present && is_elf_debug_present && has_elf_debug_dwarf; + if (is_debug_elf) { + driver = RC_Driver_Dwarf; + image = ELF_HdrIs64Bit(elf_debug.hdr.e_ident) ? Image_Elf64 : Image_Elf32; + debug_name = elf_debug_name; + debug_data = elf_debug_data; + goto driver_found; + } + } + + // + // Input is PDB + // + if (is_pdb_present) { + if (driver == RC_Driver_Null || driver == RC_Driver_Pdb) { + driver = RC_Driver_Pdb; + debug_name = pdb_name; + debug_data = pdb_data; + goto driver_found; + } else if (driver == RC_Driver_Dwarf) { + fprintf(stderr, "error: unable to select DWARF conversion driver because convert doesn't support PDB as input format.\n"); + os_abort(1); + } else { + InvalidPath; + } + } + + driver_found:; + + // + // Handle -out param + // + String8 out_name = {0}; + if (cmd_line_has_flag(cmdl, str8_lit("out"))) { + out_name = cmd_line_string(cmdl, str8_lit("out")); + if (out_name.size == 0) { + fprintf(stderr, "error: -out parameter doesn't have a value\n"); + os_abort(1); + } + } else { + if (image_name.size) { + out_name = path_replace_file_extension(arena, image_name, str8_lit("rdi")); + } else { + out_name = path_replace_file_extension(arena, debug_name, str8_lit("rdi")); + } + } + + + // + // Validate driver input + // + if (driver == RC_Driver_Pdb && + !is_pdb_present && (is_elf_present || is_elf_debug_present)) { + fprintf(stderr, "error: DWARF is an invalid input for PDB driver\n"); + os_abort(1); + } + + + RC_Context ctx = {0}; + ctx.driver = driver; + ctx.image = image; + ctx.image_name = image_name; + ctx.image_data = image_data; + ctx.debug_name = debug_name; + ctx.debug_data = debug_data; + ctx.flags = RC_Flag_Strings| + RC_Flag_IndexRuns| + RC_Flag_BinarySections| + RC_Flag_Units| + RC_Flag_Procedures| + RC_Flag_GlobalVariables| + RC_Flag_ThreadVariables| + RC_Flag_Scopes| + RC_Flag_Locals| + RC_Flag_Types| + RC_Flag_UDTs| + RC_Flag_LineInfo| + RC_Flag_GlobalVariableNameMap| + RC_Flag_ThreadVariableNameMap| + RC_Flag_ProcedureNameMap| + RC_Flag_TypeNameMap| + RC_Flag_LinkNameProcedureNameMap| + RC_Flag_NormalSourcePathNameMap; + if (check_guid) { + ctx.flags |= RC_Flag_CheckPdbGuid; + ctx.guid = pe_pdb_guid; + } + if (elf_has_debug_link) { + ctx.flags |= RC_Flag_CheckElfChecksum; + ctx.debug_link = debug_link; + } + ctx.out_name = out_name; + + scratch_end(scratch); + return ctx; +} + +internal String8List +rc_run(Arena *arena, RC_Context *rc) +{ + Temp scratch = scratch_begin(&arena, 1); + + ProfBegin("Convert"); + RDIM_LocalState *local_state = rdim_local_init(); + RDIM_BakeParams *convert2bake = 0; + switch (rc->driver) { + case RC_Driver_Null: break; + case RC_Driver_Dwarf: convert2bake = d2r_convert(scratch.arena, local_state, rc); break; + case RC_Driver_Pdb: convert2bake = p2r_convert(scratch.arena, local_state, rc); break; + } + ProfEnd(); + + if (rc->errors.node_count) { + NotImplemented; + } + + ProfBegin("Bake"); + RDIM_BakeResults bake2srlz = rdim_bake(local_state, convert2bake); + ProfEnd(); + + ProfBegin("Serialize Bake"); + RDIM_SerializedSectionBundle srlz2file = rdim_serialized_section_bundle_from_bake_results(&bake2srlz); + ProfEnd(); + + RDIM_SerializedSectionBundle srlz2file_compressed = srlz2file; + if (rc->flags & RC_Flag_Compress) { + ProfBegin("Compress"); + srlz2file_compressed = rdim_compress(scratch.arena, &srlz2file); + ProfEnd(); + } + + ProfBegin("Serialize"); + String8List raw_rdi = rdim_file_blobs_from_section_bundle(scratch.arena, &srlz2file_compressed); + ProfEnd(); + + scratch_end(scratch); + return raw_rdi; +} + +internal String8 +rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl) +{ + Temp scratch = scratch_begin(&arena, 1); + RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl); + String8List raw_rdi = rc_run(scratch.arena, &rc); + String8 result = str8_list_join(arena, &raw_rdi, 0); + scratch_end(scratch); + return result; +} + +internal void +rc_main(CmdLine *cmdl) +{ + B32 do_help = (cmd_line_has_flag(cmdl, str8_lit("help")) || + cmd_line_has_flag(cmdl, str8_lit("h")) || + cmd_line_has_flag(cmdl, str8_lit("?")) || + cmdl->argc == 1); + if (do_help) { + fprintf(stderr, "--- Help ---------------------------------------------------------------------\n"); + fprintf(stderr, " %s\n\n", BUILD_TITLE_STRING_LITERAL); + fprintf(stderr, " Usage: radcon [Options] [Files]\n\n"); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -pe: Path to Win32 executable image\n"); + fprintf(stderr, " -pdb: Path to PDB\n"); + fprintf(stderr, " -elf: Path to ELF\n"); + fprintf(stderr, " -elf_debug: Path to ELF with debug info\n"); + fprintf(stderr, " -out: Path at which the output RDI debug info will be written\n"); + fprintf(stderr, " -driver: Sets converter for debug info\n"); + } else { + Temp scratch = scratch_begin(0,0); + + // make converter context + RC_Context rc = rc_context_from_cmd_line(scratch.arena, cmdl); + + // make RDI from context + String8List raw_rdi = rc_run(scratch.arena, &rc); + + // output RDI + if (rc.errors.node_count == 0) { + if (!os_write_data_list_to_file_path(rc.out_name, raw_rdi)) { + str8_list_pushf(scratch.arena, &rc.errors, "no write access to path %.*s", str8_varg(rc.out_name)); + } + } + + // report any errors + for (String8Node *error_n = rc.errors.first; error_n != 0; error_n = error_n->next) { + fprintf(stderr, "error: %.*s\n", str8_varg(error_n->string)); + } + + scratch_end(scratch); + } +} + diff --git a/src/radcon/radcon.h b/src/radcon/radcon.h new file mode 100644 index 00000000..95631068 --- /dev/null +++ b/src/radcon/radcon.h @@ -0,0 +1,66 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADCON_H +#define RADCON_H + +typedef U32 RC_Flags; +enum +{ + RC_Flag_Strings = (1 << 0), + RC_Flag_IndexRuns = (1 << 1), + RC_Flag_BinarySections = (1 << 2), + RC_Flag_Units = (1 << 3), + RC_Flag_Procedures = (1 << 4), + RC_Flag_GlobalVariables = (1 << 5), + RC_Flag_ThreadVariables = (1 << 6), + RC_Flag_Scopes = (1 << 7), + RC_Flag_Locals = (1 << 8), + RC_Flag_Types = (1 << 9), + RC_Flag_UDTs = (1 << 10), + RC_Flag_LineInfo = (1 << 11), + RC_Flag_GlobalVariableNameMap = (1 << 12), + RC_Flag_ThreadVariableNameMap = (1 << 13), + RC_Flag_ProcedureNameMap = (1 << 14), + RC_Flag_TypeNameMap = (1 << 15), + RC_Flag_LinkNameProcedureNameMap= (1 << 16), + RC_Flag_NormalSourcePathNameMap = (1 << 17), + RC_Flag_Compress = (1 << 18), + RC_Flag_StrictDwarfParse = (1 << 19), + RC_Flag_Deterministic = (1 << 20), + RC_Flag_CheckPdbGuid = (1 << 21), + RC_Flag_CheckElfChecksum = (1 << 22), + RC_Flag_All = 0xffffffff, +}; + +typedef enum +{ + RC_Driver_Null, + RC_Driver_Dwarf, + RC_Driver_Pdb, +} RC_Driver; + +typedef struct RC_Context +{ + ImageType image; + RC_Driver driver; + String8 image_name; + String8 image_data; + String8 debug_name; + String8 debug_data; + String8 out_name; + RC_Flags flags; + Guid guid; + ELF_GnuDebugLink debug_link; + String8List errors; +} RC_Context; + +//////////////////////////////// + +internal RC_Context rc_context_from_cmd_line(Arena *arena, CmdLine *cmdl); +internal String8List rc_run(Arena *arena, RC_Context *rc); +internal String8 rc_rdi_from_cmd_line(Arena *arena, CmdLine *cmdl); +internal void rc_main(CmdLine *cmdl); + +#endif // RADCON_H + diff --git a/src/radcon/radcon_coff.c b/src/radcon/radcon_coff.c new file mode 100644 index 00000000..08f40a4a --- /dev/null +++ b/src/radcon/radcon_coff.c @@ -0,0 +1,80 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal RDI_Arch +c2r_rdi_arch_from_coff_machine(COFF_MachineType machine) +{ + switch (machine) { + case COFF_MachineType_X86: return RDI_Arch_X86; + case COFF_MachineType_X64: return RDI_Arch_X64; + + case COFF_MachineType_Unknown: + case COFF_MachineType_Am33: + case COFF_MachineType_Arm: + case COFF_MachineType_Arm64: + case COFF_MachineType_ArmNt: + case COFF_MachineType_Ebc: + case COFF_MachineType_Ia64: + case COFF_MachineType_M32R: + case COFF_MachineType_Mips16: + case COFF_MachineType_MipsFpu: + case COFF_MachineType_MipsFpu16: + case COFF_MachineType_PowerPc: + case COFF_MachineType_PowerPcFp: + case COFF_MachineType_R4000: + case COFF_MachineType_RiscV32: + case COFF_MachineType_RiscV64: + case COFF_MachineType_Sh3: + case COFF_MachineType_Sh3Dsp: + case COFF_MachineType_Sh4: + case COFF_MachineType_Sh5: + case COFF_MachineType_Thumb: + case COFF_MachineType_WceMipsV2: + NotImplemented; + default: + return RDI_Arch_NULL; + } +} + +internal RDI_BinarySectionFlags +c2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) +{ + RDI_BinarySectionFlags result = 0; + if(flags & COFF_SectionFlag_MemRead) + { + result |= RDI_BinarySectionFlag_Read; + } + if(flags & COFF_SectionFlag_MemWrite) + { + result |= RDI_BinarySectionFlag_Write; + } + if(flags & COFF_SectionFlag_MemExecute) + { + result |= RDI_BinarySectionFlag_Execute; + } + return(result); +} + +internal RDIM_BinarySectionList +c2r_rdi_binary_sections_from_coff_sections(Arena *arena, String8 image_data, String8 string_table, U64 sectab_count, COFF_SectionHeader *sectab) +{ + ProfBeginFunction(); + + RDIM_BinarySectionList binary_sections = {0}; + + for (U64 isec = 0; isec < sectab_count; ++isec) { + COFF_SectionHeader *coff_sec = §ab[isec]; + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + + sec->name = coff_name_from_section_header(string_table, coff_sec); + sec->flags = c2r_rdi_binary_section_flags_from_coff_section_flags(coff_sec->flags); + sec->voff_first = coff_sec->voff; + sec->voff_opl = coff_sec->voff + coff_sec->vsize; + sec->foff_first = coff_sec->foff; + sec->foff_opl = coff_sec->foff + coff_sec->fsize; + } + + ProfEnd(); + return binary_sections; +} + diff --git a/src/radcon/radcon_coff.h b/src/radcon/radcon_coff.h new file mode 100644 index 00000000..252874fd --- /dev/null +++ b/src/radcon/radcon_coff.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADCON_COFF_H +#define RADCON_COFF_H + +internal RDI_Arch c2r_rdi_arch_from_coff_machine(COFF_MachineType machine); +internal RDI_BinarySectionFlags c2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); +internal RDIM_BinarySectionList c2r_rdi_binary_sections_from_coff_sections(Arena *arena, String8 image_data, String8 string_table, U64 sectab_count, COFF_SectionHeader *sectab); + +#endif // RADCON_COFF_H + diff --git a/src/radcon/radcon_cv.c b/src/radcon/radcon_cv.c new file mode 100644 index 00000000..6b687feb --- /dev/null +++ b/src/radcon/radcon_cv.c @@ -0,0 +1,252 @@ +//////////////////////////////// +//~ rjf: CodeView <-> RDI Canonical Conversions + +internal RDI_Arch +cv2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) +{ + RDI_Arch result = 0; + switch(cv_arch) + { + case CV_Arch_8086: result = RDI_Arch_X86; break; + case CV_Arch_X64: result = RDI_Arch_X64; break; + //case CV_Arch_8080: break; + //case CV_Arch_80286: break; + //case CV_Arch_80386: break; + //case CV_Arch_80486: break; + //case CV_Arch_PENTIUM: break; + //case CV_Arch_PENTIUMII: break; + //case CV_Arch_PENTIUMIII: break; + //case CV_Arch_MIPS: break; + //case CV_Arch_MIPS16: break; + //case CV_Arch_MIPS32: break; + //case CV_Arch_MIPS64: break; + //case CV_Arch_MIPSI: break; + //case CV_Arch_MIPSII: break; + //case CV_Arch_MIPSIII: break; + //case CV_Arch_MIPSIV: break; + //case CV_Arch_MIPSV: break; + //case CV_Arch_M68000: break; + //case CV_Arch_M68010: break; + //case CV_Arch_M68020: break; + //case CV_Arch_M68030: break; + //case CV_Arch_M68040: break; + //case CV_Arch_ALPHA: break; + //case CV_Arch_ALPHA_21164: break; + //case CV_Arch_ALPHA_21164A: break; + //case CV_Arch_ALPHA_21264: break; + //case CV_Arch_ALPHA_21364: break; + //case CV_Arch_PPC601: break; + //case CV_Arch_PPC603: break; + //case CV_Arch_PPC604: break; + //case CV_Arch_PPC620: break; + //case CV_Arch_PPCFP: break; + //case CV_Arch_PPCBE: break; + //case CV_Arch_SH3: break; + //case CV_Arch_SH3E: break; + //case CV_Arch_SH3DSP: break; + //case CV_Arch_SH4: break; + //case CV_Arch_SHMEDIA: break; + //case CV_Arch_ARM3: break; + //case CV_Arch_ARM4: break; + //case CV_Arch_ARM4T: break; + //case CV_Arch_ARM5: break; + //case CV_Arch_ARM5T: break; + //case CV_Arch_ARM6: break; + //case CV_Arch_ARM_XMAC: break; + //case CV_Arch_ARM_WMMX: break; + //case CV_Arch_ARM7: break; + //case CV_Arch_OMNI: break; + //case CV_Arch_IA64_1: break; + //case CV_Arch_IA64_2: break; + //case CV_Arch_CEE: break; + //case CV_Arch_AM33: break; + //case CV_Arch_M32R: break; + //case CV_Arch_TRICORE: break; + //case CV_Arch_EBC: break; + //case CV_Arch_THUMB: break; + //case CV_Arch_ARMNT: break; + //case CV_Arch_ARM64: break; + //case CV_Arch_D3D11_SHADER: break; + } + return(result); +} + +internal RDI_RegCode +cv2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code) +{ + RDI_RegCode result = 0; + switch(arch) + { + case RDI_Arch_X86: + { + switch(reg_code) + { +#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX86_##RDN; break; + CV_Reg_X86_XList(X) +#undef X + } + }break; + case RDI_Arch_X64: + { + switch(reg_code) + { +#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegCodeX64_##RDN; break; + CV_Reg_X64_XList(X) +#undef X + } + }break; + } + return(result); +} + +internal RDI_Language +cv2r_rdi_language_from_cv_language(CV_Language cv_language) +{ + RDI_Language result = 0; + switch(cv_language) + { + case CV_Language_C: result = RDI_Language_C; break; + case CV_Language_CXX: result = RDI_Language_CPlusPlus; break; + //case CV_Language_FORTRAN: result = ; break; + //case CV_Language_MASM: result = ; break; + //case CV_Language_PASCAL: result = ; break; + //case CV_Language_BASIC: result = ; break; + //case CV_Language_COBOL: result = ; break; + //case CV_Language_LINK: result = ; break; + //case CV_Language_CVTRES: result = ; break; + //case CV_Language_CVTPGD: result = ; break; + //case CV_Language_CSHARP: result = ; break; + //case CV_Language_VB: result = ; break; + //case CV_Language_ILASM: result = ; break; + //case CV_Language_JAVA: result = ; break; + //case CV_Language_JSCRIPT: result = ; break; + //case CV_Language_MSIL: result = ; break; + //case CV_Language_HLSL: result = ; break; + } + return(result); +} + +internal RDI_RegCode +cv2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg) +{ + RDI_RegCode result = 0; + switch(arch) + { + case RDI_Arch_X86: + { + switch(encoded_reg) + { + case CV_EncodedFramePtrReg_StackPtr: + { + // TODO(allen): support CV_AllReg_VFRAME + // TODO(allen): error + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RDI_RegCodeX86_ebp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RDI_RegCodeX86_ebx; + }break; + } + }break; + case RDI_Arch_X64: + { + switch(encoded_reg) + { + case CV_EncodedFramePtrReg_StackPtr: + { + result = RDI_RegCodeX64_rsp; + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RDI_RegCodeX64_rbp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RDI_RegCodeX64_r13; + }break; + } + }break; + } + return(result); +} + + +internal RDI_TypeKind +cv2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type) +{ + RDI_TypeKind result = RDI_TypeKind_NULL; + switch(basic_type) + { + case CV_BasicType_VOID: {result = RDI_TypeKind_Void;}break; + case CV_BasicType_HRESULT: {result = RDI_TypeKind_HResult;}break; + + case CV_BasicType_RCHAR: + case CV_BasicType_CHAR: + case CV_BasicType_CHAR8: + {result = RDI_TypeKind_Char8;}break; + + case CV_BasicType_UCHAR: {result = RDI_TypeKind_UChar8;}break; + case CV_BasicType_WCHAR: {result = RDI_TypeKind_UChar16;}break; + case CV_BasicType_CHAR16: {result = RDI_TypeKind_Char16;}break; + case CV_BasicType_CHAR32: {result = RDI_TypeKind_Char32;}break; + + case CV_BasicType_BOOL8: + case CV_BasicType_INT8: + {result = RDI_TypeKind_S8;}break; + + case CV_BasicType_BOOL16: + case CV_BasicType_INT16: + case CV_BasicType_SHORT: + {result = RDI_TypeKind_S16;}break; + + case CV_BasicType_BOOL32: + case CV_BasicType_INT32: + case CV_BasicType_LONG: + {result = RDI_TypeKind_S32;}break; + + case CV_BasicType_BOOL64: + case CV_BasicType_INT64: + case CV_BasicType_QUAD: + {result = RDI_TypeKind_S64;}break; + + case CV_BasicType_INT128: + case CV_BasicType_OCT: + {result = RDI_TypeKind_S128;}break; + + case CV_BasicType_UINT8: {result = RDI_TypeKind_U8;}break; + + case CV_BasicType_UINT16: + case CV_BasicType_USHORT: + {result = RDI_TypeKind_U16;}break; + + case CV_BasicType_UINT32: + case CV_BasicType_ULONG: + {result = RDI_TypeKind_U32;}break; + + case CV_BasicType_UINT64: + case CV_BasicType_UQUAD: + {result = RDI_TypeKind_U64;}break; + + case CV_BasicType_UINT128: + case CV_BasicType_UOCT: + {result = RDI_TypeKind_U128;}break; + + case CV_BasicType_FLOAT16:{result = RDI_TypeKind_F16;}break; + case CV_BasicType_FLOAT32:{result = RDI_TypeKind_F32;}break; + case CV_BasicType_FLOAT32PP:{result = RDI_TypeKind_F32PP;}break; + case CV_BasicType_FLOAT48:{result = RDI_TypeKind_F48;}break; + case CV_BasicType_FLOAT64:{result = RDI_TypeKind_F64;}break; + case CV_BasicType_FLOAT80:{result = RDI_TypeKind_F80;}break; + case CV_BasicType_FLOAT128:{result = RDI_TypeKind_F128;}break; + case CV_BasicType_COMPLEX32:{result = RDI_TypeKind_ComplexF32;}break; + case CV_BasicType_COMPLEX64:{result = RDI_TypeKind_ComplexF64;}break; + case CV_BasicType_COMPLEX80:{result = RDI_TypeKind_ComplexF80;}break; + case CV_BasicType_COMPLEX128:{result = RDI_TypeKind_ComplexF128;}break; + case CV_BasicType_PTR:{result = RDI_TypeKind_Handle;}break; + } + return result; +} + diff --git a/src/radcon/radcon_cv.h b/src/radcon/radcon_cv.h new file mode 100644 index 00000000..014a4c9e --- /dev/null +++ b/src/radcon/radcon_cv.h @@ -0,0 +1,10 @@ +#pragma once + +//////////////////////////////// +//~ rjf: CodeView => RDI Canonical Conversions + +internal RDI_Arch cv2r_rdi_arch_from_cv_arch(CV_Arch arch); +internal RDI_RegCode cv2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); +internal RDI_Language cv2r_rdi_language_from_cv_language(CV_Language language); +internal RDI_RegCode cv2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); +internal RDI_TypeKind cv2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type); diff --git a/src/radcon/radcon_dwarf.c b/src/radcon/radcon_dwarf.c new file mode 100644 index 00000000..e2b6af54 --- /dev/null +++ b/src/radcon/radcon_dwarf.c @@ -0,0 +1,2151 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// TODO: +// +// [ ] Currently converter relies on clang's -gdwarf-aranges to generate compile unit ranges, +// however it is optional and in case it is missing converter has to generate the ranges from scopes. +// [ ] Error handling + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code_x64(U64 reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX64_##reg_name_dw: return RDI_RegCodeX64_##reg_name_rdi; + DW_Regs_X64_XList(X) +#undef X + } + InvalidPath; + return 0; +} + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code_x86(U64 reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX86_##reg_name_dw: return RDI_RegCodeX86_##reg_name_rdi; + DW_Regs_X86_XList(X) +#undef X + } + InvalidPath; + return 0; +} + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code(Arch arch, U64 reg_code) +{ + switch (arch) { + case Arch_Null: return 0; + case Arch_x64: return d2r_rdi_reg_from_dw_reg_code_x64(reg_code); + case Arch_x86: return d2r_rdi_reg_from_dw_reg_code_x86(reg_code); + default: InvalidPath; + } + return 0; +} + +internal RDIM_Type * +d2r_create_type(Arena *arena, D2R_TypeTable *type_table) +{ + RDIM_Type *type = rdim_type_chunk_list_push(arena, type_table->types, type_table->type_chunk_cap); + return type; +} + +internal RDIM_Type * +d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) +{ + RDIM_Type *type = 0; + KeyValuePair *is_type_present = hash_table_search_u64(type_table->ht, info_off); + if (is_type_present) { + type = is_type_present->value_raw; + } else { + type = d2r_create_type(arena, type_table); + hash_table_push_u64_raw(arena, type_table->ht, info_off, type); + } + return type; +} + +internal RDIM_Type * +d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + RDIM_Type *type = 0; + + // find attrib + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + + // does tag have this attribute? + if (attrib->attrib_kind == kind) { + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + + if (value_class == DW_AttribClass_Reference) { + // resolve reference + DW_Reference ref = dw_ref_from_attrib_ptr(input, cu, attrib); + + // TODO: support for external compile unit references + AssertAlways(ref.cu == cu); + + // find or create type + type = d2r_find_or_create_type_from_offset(arena, type_table, ref.info_off); + } else { + Assert(!"unexpected attrib class"); + } + } else if (attrib->attrib_kind == DW_Attrib_Null) { + type = rdim_builtin_type_from_kind(*type_table->types, RDI_TypeKind_NULL); + } + + return type; +} + +internal Rng1U64List +d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) +{ + // collect non-contiguous range + Rng1U64List ranges = dw_rnglist_from_attrib(arena, input, cu, tag, DW_Attrib_Ranges); + + // debase ranges + for (Rng1U64Node *range_n = ranges.first; range_n != 0; range_n = range_n->next) { + // TODO: error handling + AssertAlways(range_n->v.min >= image_base); + AssertAlways(range_n->v.max >= image_base); + range_n->v.min -= image_base; + range_n->v.max -= image_base; + } + + // collect contiguous range + DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_Attrib_LowPc); + DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_Attrib_HighPc); + if (lo_pc_attrib->attrib_kind != DW_Attrib_Null && hi_pc_attrib->attrib_kind != DW_Attrib_Null) { + U64 lo_pc = dw_address_from_attrib_ptr(input, cu, lo_pc_attrib); + + U64 hi_pc; + DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); + if (hi_pc_class == DW_AttribClass_Address) { + hi_pc = dw_address_from_attrib_ptr(input, cu, hi_pc_attrib); + } else if (hi_pc_class == DW_AttribClass_Const) { + hi_pc = dw_const_u64_from_attrib_ptr(input, cu, hi_pc_attrib); + hi_pc += lo_pc; + } else { + AssertAlways(!"undefined attrib encoding"); + } + + // TODO: error handling + AssertAlways(lo_pc >= image_base); + AssertAlways(hi_pc >= image_base); + AssertAlways(lo_pc <= hi_pc); + + U64 lo_voff = lo_pc - image_base; + U64 hi_voff = hi_pc - image_base; + rng1u64_list_push(arena, &ranges, rng_1u64(lo_voff, hi_voff)); + } + + return ranges; +} + +internal RDIM_Type ** +d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDIM_TypeList list = {0}; + B32 has_vargs = 0; + for (DW_TagNode *i = cur_node->first_child; i != 0; i = i->sibling) { + if (i->tag.kind == DW_Tag_FormalParameter) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = d2r_type_from_attrib(arena, type_table, input, cu, i->tag, DW_Attrib_Type); + SLLQueuePush(list.first, list.last, n); + ++list.count; + } else if (i->tag.kind == DW_Tag_UnspecifiedParameters) { + has_vargs = 1; + } + } + + if (has_vargs) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = type_table->varg_type; + SLLQueuePush(list.first, list.last, n); + ++list.count; + } + + // collect params + *param_count_out = list.count; + RDIM_Type **params = rdim_array_from_type_list(arena, list); + + scratch_end(scratch); + return params; +} + +internal RDI_TypeKind +d2r_unsigned_type_kind_from_size(U64 byte_size) +{ + RDI_TypeKind result = RDI_TypeKind_NULL; + switch (byte_size) { + case 1: result = RDI_TypeKind_U8; break; + case 2: result = RDI_TypeKind_U16; break; + case 4: result = RDI_TypeKind_U32; break; + case 8: result = RDI_TypeKind_U64; break; + } + return result; +} + +internal RDI_TypeKind +d2r_signed_type_kind_from_size(U64 byte_size) +{ + RDI_TypeKind result = RDI_TypeKind_NULL; + switch (byte_size) { + case 1: result = RDI_TypeKind_S8; break; + case 2: result = RDI_TypeKind_S16; break; + case 4: result = RDI_TypeKind_S32; break; + case 8: result = RDI_TypeKind_S64; break; + } + return result; +} + +internal RDI_EvalTypeGroup +d2r_type_group_from_type_kind(RDI_TypeKind x) +{ + switch (x) { + case RDI_TypeKind_NULL: + case RDI_TypeKind_Void: + case RDI_TypeKind_Handle: + break; + case RDI_TypeKind_UChar8: + case RDI_TypeKind_UChar16: + case RDI_TypeKind_UChar32: + case RDI_TypeKind_U8: + case RDI_TypeKind_U16: + case RDI_TypeKind_U32: + case RDI_TypeKind_U64: + case RDI_TypeKind_U128: + case RDI_TypeKind_U256: + case RDI_TypeKind_U512: + return RDI_EvalTypeGroup_U; + case RDI_TypeKind_Char8: + case RDI_TypeKind_Char16: + case RDI_TypeKind_Char32: + case RDI_TypeKind_S8: + case RDI_TypeKind_S16: + case RDI_TypeKind_S32: + case RDI_TypeKind_S64: + case RDI_TypeKind_S128: + case RDI_TypeKind_S256: + case RDI_TypeKind_S512: + return RDI_EvalTypeGroup_S; + case RDI_TypeKind_F32: + return RDI_EvalTypeGroup_F32; + case RDI_TypeKind_F64: + return RDI_EvalTypeGroup_F64; + default: InvalidPath; + } + return RDI_EvalTypeGroup_Other; +} + +internal RDIM_EvalBytecode +d2r_bytecode_from_expression(Arena *arena, + DW_Input *input, + U64 image_base, + U64 address_size, + Arch arch, + DW_ListUnit *addr_lu, + String8 expr, + DW_CompUnit *cu, + B32 *is_addr_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDIM_EvalBytecode bc = {0}; + + *is_addr_out = 0; + + struct Frame { + struct Frame *next; + RDI_EvalTypeGroup value_type; + }; + struct Frame *stack = 0; +#define push_of_type(type) do { \ + struct Frame *f = push_array(scratch.arena, struct Frame, 1); \ + f->value_type = d2r_type_group_from_type_kind(type); \ + SLLStackPush(stack, f); \ +} while (0) +#define pop_type() stack->value_type; SLLStackPop(stack) +#define peek_type() stack->value_type + + + RDI_TypeKind addr_type_kind = RDI_TypeKind_NULL; + if (address_size == 4) { + addr_type_kind = RDI_TypeKind_U32; + } else if (address_size == 8) { + addr_type_kind = RDI_TypeKind_U64; + } + + + for (U64 cursor = 0; cursor < expr.size; ) { + U8 op = 0; + cursor += str8_deserial_read_struct(expr, cursor, &op); + + U64 size_param; + switch (op) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 lit = op - DW_ExprOp_Lit0; + + rdim_bytecode_push_uconst(arena, &bc, lit); + push_of_type(RDI_TypeKind_U64); + } break; + + case DW_ExprOp_Const1U: { + U8 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_uconst(arena, &bc, val); + push_of_type(RDI_TypeKind_U8); + } break; + case DW_ExprOp_Const2U: { + U16 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_uconst(arena, &bc, val); + push_of_type(RDI_TypeKind_U16); + } break; + case DW_ExprOp_Const4U: { + U32 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_uconst(arena, &bc, val); + push_of_type(RDI_TypeKind_U32); + } break; + case DW_ExprOp_Const8U: { + U64 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_uconst(arena, &bc, val); + push_of_type(RDI_TypeKind_U64); + } break; + + case DW_ExprOp_Const1S: { + S8 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_sconst(arena, &bc, val); + push_of_type(RDI_TypeKind_S8); + } break; + case DW_ExprOp_Const2S: { + S16 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_sconst(arena, &bc, val); + push_of_type(RDI_TypeKind_S16); + } break; + case DW_ExprOp_Const4S: { + S32 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_sconst(arena, &bc, val); + push_of_type(RDI_TypeKind_S32); + } break; + case DW_ExprOp_Const8S: { + S64 val = 0; + cursor += str8_deserial_read_struct(expr, cursor, &val); + + rdim_bytecode_push_sconst(arena, &bc, val); + push_of_type(RDI_TypeKind_S64); + } break; + + case DW_ExprOp_ConstU: { + U64 val = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &val); + + rdim_bytecode_push_uconst(arena, &bc, val); + push_of_type(RDI_TypeKind_U64); + } break; + + case DW_ExprOp_ConstS: { + S64 val = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, &val); + + rdim_bytecode_push_sconst(arena, &bc, val); + push_of_type(RDI_TypeKind_S64); + } break; + + case DW_ExprOp_Addr: { + U64 addr = 0; + cursor += str8_deserial_read(expr, cursor, &addr, address_size, address_size); + if (addr >= image_base) { + U64 voff = addr - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + push_of_type(addr_type_kind); + } else { + // TODO: error handling + AssertAlways(!"unable to relocate address"); + } + + *is_addr_out = 1; + } break; + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_code_dw = op - DW_ExprOp_Reg0; + U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); + U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + push_of_type(d2r_unsigned_type_kind_from_size(reg_size)); + } break; + + case DW_ExprOp_RegX: { + U64 reg_code_dw = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); + + U64 reg_size = dw_reg_size_from_code(arch, reg_code_dw); + U64 reg_pos = dw_reg_pos_from_code(arch, reg_code_dw); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, reg_size, reg_pos); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + push_of_type(d2r_unsigned_type_kind_from_size(reg_size)); + + *is_addr_out = 1; + } break; + + case DW_ExprOp_ImplicitValue: { + U64 val_size = 0; + String8 val = {0}; + cursor += str8_deserial_read_uleb128(expr, cursor, &val_size); + cursor += str8_deserial_read_block(expr, cursor, val_size, &val); + if (val.size <= sizeof(U64)) { + U64 val64 = 0; + MemoryCopy(&val64, val.str, val.size); + + rdim_bytecode_push_uconst(arena, &bc, val64); + push_of_type(d2r_unsigned_type_kind_from_size(val_size)); + } else { + // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp + NotImplemented; + } + } break; + + case DW_ExprOp_Piece: { + U64 piece_byte_size = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &piece_byte_size); + + U64 partial_value_size32 = safe_cast_u32(piece_byte_size); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValue, partial_value_size32); + } break; + + case DW_ExprOp_BitPiece: { + U64 piece_bit_size = 0; + U64 piece_bit_off = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &piece_bit_size); + cursor += str8_deserial_read_uleb128(expr, cursor, &piece_bit_off); + + U32 piece_bit_size32 = safe_cast_u32(piece_bit_size); + U32 piece_bit_off32 = safe_cast_u32(piece_bit_off); + + U64 partial_value = ((U64)piece_bit_size32 << 32) | (U64)piece_bit_off32; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_PartialValueBit, partial_value); + } break; + + case DW_ExprOp_Pick: { + U8 stack_idx = 0; + cursor += str8_deserial_read_struct(expr, cursor, &stack_idx); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, stack_idx); + } break; + + case DW_ExprOp_PlusUConst: { + U64 addend = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &addend); + rdim_bytecode_push_uconst(arena, &bc, addend); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_U); + } break; + + case DW_ExprOp_Skip: { + S16 skip = 0; + cursor += str8_deserial_read_struct(expr, cursor, &skip); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, skip); + } break; + + case DW_ExprOp_Bra: { + NotImplemented; + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_code_dw = op - DW_ExprOp_BReg0; + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + push_of_type(RDI_TypeKind_S64); + + *is_addr_out = 1; + } break; + + case DW_ExprOp_BRegX: { + U64 reg_code_dw = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); + cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + if (reg_off > 0) { + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, RDI_EvalTypeGroup_S); + } + push_of_type(RDI_TypeKind_S64); + + *is_addr_out = 1; + } break; + + case DW_ExprOp_FBReg: { + S64 frame_off = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, &frame_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, frame_off); + + *is_addr_out = 1; + } break; + + case DW_ExprOp_Deref: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); + } break; + + case DW_ExprOp_DerefSize: { + U8 deref_size_in_bytes = 0; + cursor += str8_deserial_read_struct(expr, cursor, &deref_size_in_bytes); + if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); + } else { + // TODO: error handling + AssertAlways(!"ill formed expression"); + } + } break; + + case DW_ExprOp_XDerefSize: { + // TODO: error handling + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: { + // TODO: error handling + AssertAlways(!"calls are not supported"); + } break; + + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + U64 type_info_off = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &type_info_off); + + RDI_EvalTypeGroup in = stack ? d2r_type_group_from_type_kind(stack->value_type) : RDI_EvalTypeGroup_Other; + RDI_EvalTypeGroup out = RDI_EvalTypeGroup_Other; + + if (type_info_off == 0) { + // + // 2.5.1 + // Instead of a base type, elements can have a generic type, + // which is an integral type that has the size of an address + // on the target machine and unspecified signedness. + // + out = d2r_type_group_from_type_kind(addr_type_kind); + } else { + // find ref tag + DW_TagNode *tag_node = dw_tag_node_from_info_off(cu, type_info_off); + DW_Tag tag = tag_node->tag; + if (tag.kind == DW_Tag_BaseType) { + // extract encoding attribute + DW_ATE encoding = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_Encoding); + + // DW_ATE -> RDI_EvalTypeGroup + switch (encoding) { + case DW_ATE_SignedChar: + case DW_ATE_Signed: out = RDI_EvalTypeGroup_S; break; + case DW_ATE_UnsignedChar: + case DW_ATE_Unsigned: out = RDI_EvalTypeGroup_U; break; + case DW_ATE_Float: { + U64 byte_size = dw_const_u64_from_attrib(input, cu, tag, DW_Attrib_ByteSize); + switch (byte_size) { + case 4: out = RDI_EvalTypeGroup_F32; break; + case 8: out = RDI_EvalTypeGroup_F64; break; + default: InvalidPath; + } + } break; + default: InvalidPath; + } + } else { + AssertAlways(!"unexpected tag"); // TODO: error handling + } + } + + if (in == RDI_EvalTypeGroup_Other) { + push_of_type(out); + break; + } + + // TODO: error handling + AssertAlways(in != RDI_EvalTypeGroup_Other); + AssertAlways(out != RDI_EvalTypeGroup_Other); + + U16 operand = (U16)in | ((U16)out << 8); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Convert, operand); + } break; + + case DW_ExprOp_GNU_ParameterRef: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_RegvalType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + U64 entry_value_expr_size = 0; + String8 entry_value_expr = {0}; + cursor += str8_deserial_read_uleb128(expr, cursor, &entry_value_expr_size); + cursor += str8_deserial_read_block(expr, cursor, entry_value_expr_size, &entry_value_expr); + + B32 dummy = 0; + RDIM_EvalBytecode call_site_bc = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, entry_value_expr, cu, &dummy); + + U32 encoded_size32 = safe_cast_u32(call_site_bc.encoded_size); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_CallSiteValue, encoded_size32); + rdim_bytecode_concat_in_place(&bc, &call_site_bc); + } break; + + case DW_ExprOp_Addrx: { + U64 addr_idx = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &addr_idx); + U64 addr = dw_addr_from_list_unit(addr_lu, addr_idx); + if (addr != max_U64) { + if (addr >= image_base) { + U64 voff = addr - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + } else { + // TODO: error handling + AssertAlways(!"unable to relocate address"); + } + } else { + // TODO: error handling + AssertAlways(!"out of bounds index"); + } + } break; + + case DW_ExprOp_CallFrameCfa: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); + } break; + + case DW_ExprOp_FormTlsAddress: { + // TODO: + AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); + } break; + + case DW_ExprOp_PushObjectAddress: { + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Nop: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Noop, 0); + } break; + + case DW_ExprOp_Eq: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_EqEq, peek_type()); + } break; + + case DW_ExprOp_Ge: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_GrEq, peek_type()); + } break; + + case DW_ExprOp_Gt: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Grtr, peek_type()); + } break; + + case DW_ExprOp_Le: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LsEq, peek_type()); + } break; + + case DW_ExprOp_Lt: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Less, peek_type()); + } break; + + case DW_ExprOp_Ne: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_NtEq, peek_type()); + } break; + + case DW_ExprOp_Shl: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LShift, peek_type()); + } break; + + case DW_ExprOp_Shr: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, RDI_EvalTypeGroup_U); + } break; + + case DW_ExprOp_Shra: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, RDI_EvalTypeGroup_S); + } break; + + case DW_ExprOp_Xor: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitXor, peek_type()); + } break; + + case DW_ExprOp_XDeref: { + // TODO: error handling + Assert(!"multiple address spaces are not supported"); + } break; + + case DW_ExprOp_Abs: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, peek_type()); + } break; + + case DW_ExprOp_And: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitAnd, peek_type()); + } break; + + case DW_ExprOp_Div: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Div, peek_type()); + } break; + + case DW_ExprOp_Minus: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Sub, peek_type()); + } break; + + case DW_ExprOp_Mod: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, peek_type()); + } break; + + case DW_ExprOp_Mul: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mul, peek_type()); + } break; + + case DW_ExprOp_Neg: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, peek_type()); + } break; + + case DW_ExprOp_Not: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, peek_type()); + } break; + + case DW_ExprOp_Or: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitOr, peek_type()); + } break; + + case DW_ExprOp_Plus: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, peek_type()); + } break; + + case DW_ExprOp_Rot: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Swap: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Dup: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Drop: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Over: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); + } break; + + case DW_ExprOp_StackValue: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); + } break; + + default: InvalidPath; break; + } + } + +#undef peek_type +#undef pop_type +#undef push_of_type + scratch_end(scratch); + return bc; +} + +internal RDIM_Location * +d2r_transpile_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr) +{ + RDIM_Location *loc = 0; + if (expr.size) { + B32 is_addr = 0; + RDIM_EvalBytecode bytecode = d2r_bytecode_from_expression(arena, input, image_base, address_size, arch, addr_lu, expr, cu, &is_addr); + + loc = push_array(arena, RDIM_Location, 1); + loc->kind = is_addr ? RDI_LocationKind_AddrBytecodeStream : RDI_LocationKind_ValBytecodeStream; + loc->bytecode = bytecode; + } + return loc; +} + +internal RDIM_Location * +d2r_location_from_attrib(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind) +{ + String8 expr = dw_exprloc_from_attrib(input, cu, tag, kind); + RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + return location; +} + +internal RDIM_LocationSet +d2r_locset_from_attrib(Arena *arena, + DW_Input *input, + DW_CompUnit *cu, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + U64 image_base, + Arch arch, + DW_Tag tag, + DW_AttribKind kind) +{ + RDIM_LocationSet locset = {0}; + + // extract attrib from tag + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib); + + if (attrib_class == DW_AttribClass_LocList || attrib_class == DW_AttribClass_LocListPtr) { + Temp scratch = scratch_begin(&arena, 1); + + // extract location list from attrib + DW_LocList loclist = dw_loclist_from_attrib_ptr(scratch.arena, input, cu, attrib); + + // convert location list to RDIM location set + for (DW_LocNode *loc_n = loclist.first; loc_n != 0; loc_n = loc_n->next) { + RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, loc_n->v.expr); + RDIM_Rng1U64 voff_range = { .min = loc_n->v.range.min - image_base, .max = loc_n->v.range.max - image_base }; + rdim_location_set_push_case(arena, scopes, &locset, voff_range, location); + } + + scratch_end(scratch); + } else if (attrib_class == DW_AttribClass_ExprLoc) { + // extract expression from attrib + String8 expr = dw_exprloc_from_attrib_ptr(input, cu, attrib); + + // convert expression and inherit life-time ranges from enclosed scope + RDIM_Location *location = d2r_transpile_expression(arena, input, image_base, cu->address_size, arch, cu->addr_lu, cu, expr); + for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { + rdim_location_set_push_case(arena, scopes, &locset, range_n->v, location); + } + } else if (attrib_class != DW_AttribClass_Null) { + AssertAlways(!"unexpected attrib class"); + } + + return locset; +} + +internal RDIM_LocationSet +d2r_var_locset_from_tag(Arena *arena, + DW_Input *input, + DW_CompUnit *cu, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + U64 image_base, + Arch arch, + DW_Tag tag) +{ + RDIM_LocationSet locset = {0}; + + B32 has_const_value = dw_tag_has_attrib(input, cu, tag, DW_Attrib_ConstValue); + B32 has_location = dw_tag_has_attrib(input, cu, tag, DW_Attrib_Location); + + if (has_const_value && has_location) { + // TODO: error handling + AssertAlways(!"unexpected variable encoding"); + } + + if (has_const_value) { + // extract const value + U64 const_value = dw_u64_from_attrib(input, cu, tag, DW_Attrib_ConstValue); + + // make value byte code + RDIM_EvalBytecode bc = {0}; + rdim_bytecode_push_uconst(arena, &bc, const_value); + + // fill out location + RDIM_Location *loc = push_array(arena, RDIM_Location, 1); + loc->kind = RDI_LocationKind_ValBytecodeStream; + loc->bytecode = bc; + + // push location cases + for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { + rdim_location_set_push_case(arena, scopes, &locset, range_n->v, loc); + } + } else if (has_location) { + locset = d2r_locset_from_attrib(arena, input, cu, scopes, curr_scope, image_base, arch, tag, DW_Attrib_Location); + } + + return locset; +} + +internal D2R_CompUnitContribMap +d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 aranges_data = input->sec[DW_Section_ARanges].data; + Rng1U64List unit_range_list = dw_unit_ranges_from_data(scratch.arena, aranges_data); + + D2R_CompUnitContribMap cm = {0}; + cm.count = 0; + cm.info_off_arr = push_array(arena, U64, unit_range_list.count); + cm.voff_range_arr = push_array(arena, RDIM_Rng1U64List, unit_range_list.count); + + for (Rng1U64Node *range_n = unit_range_list.first; range_n != 0; range_n = range_n->next) { + String8 unit_data = str8_substr(aranges_data, range_n->v); + U64 unit_cursor = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, unit_cursor, &unit_length); + if (unit_length_size == 0) { + continue; + } + unit_cursor += unit_length_size; + + DW_Version version = 0; + U64 version_size = str8_deserial_read_struct(unit_data, unit_cursor, &version); + if (version_size == 0) { + continue; + } + unit_cursor += version; + + if (version != DW_Version_2) { + AssertAlways(!"unknown .debug_aranges version"); + continue; + } + + DW_Format unit_format = DW_FormatFromSize(unit_length); + U64 cu_info_off = 0; + U64 cu_info_off_size = str8_deserial_read_dwarf_uint(unit_data, unit_cursor, unit_format, &cu_info_off); + if (cu_info_off_size == 0) { + continue; + } + unit_cursor += cu_info_off_size; + + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &address_size); + if (address_size_size == 0) { + continue; + } + unit_cursor += address_size_size; + + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &segment_selector_size); + if (segment_selector_size_size == 0) { + continue; + } + unit_cursor += segment_selector_size_size; + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = unit_cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + unit_cursor += tuple_size - bytes_too_far_past_boundary; + } + + RDIM_Rng1U64List voff_ranges = {0}; + if (segment_selector_size == 0) { + while (unit_cursor + address_size * 2 <= unit_data.size) { + U64 address = 0; + U64 length = 0; + unit_cursor += str8_deserial_read(unit_data, unit_cursor, &address, address_size, address_size); + unit_cursor += str8_deserial_read(unit_data, unit_cursor, &length, address_size, address_size); + + if (address == 0 && length == 0) { + break; + } + + // TODO: error handling + AssertAlways(address >= image_base); + + U64 min = address - image_base; + U64 max = min + length; + rdim_rng1u64_list_push(arena, &voff_ranges, (RDIM_Rng1U64){.min = min, .max = max}); + } + } else { + // TODO: segment relative addressing + NotImplemented; + } + + U64 map_idx = cm.count++; + cm.info_off_arr[map_idx] = cu_info_off; + cm.voff_range_arr[map_idx] = voff_ranges; + } + + scratch_end(scratch); + return cm; +} + +internal RDIM_Rng1U64List +d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) +{ + RDIM_Rng1U64List voff_ranges = {0}; + U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); + if (voff_list_idx < map.count) { + voff_ranges = map.voff_range_arr[voff_list_idx]; + } + return voff_ranges; +} + +internal RDIM_Scope * +d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagNode *tag_stack, Rng1U64List ranges) +{ + // fill out scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, scopes, scope_chunk_cap); + + // push ranges + for (Rng1U64Node *i = ranges.first; i != 0; i = i->next) { + rdim_scope_push_voff_range(arena, scopes, scope, (RDIM_Rng1U64){.min = i->v.min, i->v.max}); + } + + // associate scope with tag + tag_stack->scope = scope; + + // update scope hierarchy + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || parent_tag_kind == DW_Tag_InlinedSubroutine || parent_tag_kind == DW_Tag_LexicalBlock) { + RDIM_Scope *parent = tag_stack->next->scope; + + scope->parent_scope = parent; + scope->symbol = parent->symbol; + + if (parent->last_child) { + parent->last_child->next_sibling = scope; + } + SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); + } + + return scope; +} + +internal RDIM_BakeParams * +d2r_convert(Arena *arena, RDIM_LocalState *local_state, RC_Context *in) +{ + Temp scratch = scratch_begin(&arena, 1); + + //////////////////////////////// + + ProfBegin("compute exe hash"); + U64 exe_hash = rdi_hash(in->image_data.str, in->image_data.size); + ProfEnd(); + + //////////////////////////////// + + Arch arch = Arch_Null; + U64 image_base = 0; + RDIM_BinarySectionList binary_sections = {0}; + DW_Input input = {0}; + + if (in->image == Image_CoffPe) { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, in->image_data); + + // get image arch + arch = pe.arch; + + // get image base + image_base = pe.image_base; + + // get image sections + String8 raw_sections = str8_substr(in->image_data, pe.section_table_range); + U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_sections.str; + + // convert sections + String8 string_table = str8_substr(in->image_data, pe.string_table_range); + binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, in->image_data, string_table, section_count, section_table); + + // make DWARF input + input = dw_input_from_coff_section_table(scratch.arena, in->image_data, string_table, section_count, section_table); + } else if (in->image == Image_Elf32 || in->image == Image_Elf64) { + ELF_BinInfo elf = elf_bin_from_data(in->debug_data); + + // get image arch + arch = arch_from_elf_machine(elf.hdr.e_machine); + + // get image base + image_base = elf_base_addr_from_bin(&elf.hdr); + + // get image sections + ELF_Shdr64Array shdrs = elf_shdr64_array_from_bin(scratch.arena, in->debug_data, &elf.hdr); + + // convert sections + binary_sections = e2r_rdi_binary_sections_from_elf_section_table(arena, shdrs); + + // make DWARF input + input = dw_input_from_elf_section_table(scratch.arena, in->debug_data, &elf); + } else { + InvalidPath; + } + + //////////////////////////////// + + RDIM_TopLevelInfo top_level_info = rdim_make_top_level_info(in->image_name, arch, exe_hash, binary_sections); + + //////////////////////////////// + + U64 arch_addr_size = rdi_addr_size_from_arch(arch); + + //////////////////////////////// + + static const U64 UNIT_CHUNK_CAP = 256; + static const U64 UDT_CHUNK_CAP = 256; + static const U64 TYPE_CHUNK_CAP = 256; + static const U64 GVAR_CHUNK_CAP = 256; + static const U64 TVAR_CHUNK_CAP = 256; + static const U64 PROC_CHUNK_CAP = 256; + static const U64 SCOPE_CHUNK_CAP = 256; + static const U64 INLINE_SITE_CHUNK_CAP = 256; + static const U64 SRC_FILE_CAP = 256; + static const U64 LINE_TABLE_CAP = 256; + + RDIM_UnitChunkList units = {0}; + RDIM_UDTChunkList udts = {0}; + RDIM_TypeChunkList types = rdim_init_type_chunk_list(arena, arch); + RDIM_SymbolChunkList gvars = {0}; + RDIM_SymbolChunkList tvars = {0}; + RDIM_SymbolChunkList procs = {0}; + RDIM_ScopeChunkList scopes = {0}; + RDIM_InlineSiteChunkList inline_sites = {0}; + RDIM_SrcFileChunkList src_files = {0}; + RDIM_LineTableChunkList line_tables = {0}; + + //////////////////////////////// + + RDIM_Scope *global_scope = rdim_scope_chunk_list_push(arena, &scopes, SCOPE_CHUNK_CAP); + + //////////////////////////////// + + ProfBegin("Make Unit Contrib Map"); + D2R_CompUnitContribMap cu_contrib_map = {0}; + if (input.sec[DW_Section_ARanges].data.size > 0) { + cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); + } else { + // TODO: synthesize cu ranges from scopes + NotImplemented; + } + ProfEnd(); + + ProfBegin("Parse Comop Unit Ranges"); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); + Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); + Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Compile Unit Headers"); + B32 is_parse_relaxed = !(in->flags & RC_Flag_StrictDwarfParse); + DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Line Tables"); + DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + DW_CompUnit *cu = &cu_arr[cu_idx]; + String8 cu_stmt_list = dw_line_ptr_from_attrib(&input, cu, cu->tag, DW_Attrib_StmtList); + String8 cu_dir = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_CompDir); + String8 cu_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Name); + cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Convert Line Tables"); + + HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); + RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); + + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); + + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; + DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; + DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; + RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); + for (U64 file_idx = 0; file_idx < file_table->count; ++file_idx) { + DW_LineFile *file = &file_table->v[file_idx]; + String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); + String8List file_path_split = str8_split_path(scratch.arena, file_path); + str8_path_list_resolve_dots_in_place(&file_path_split, PathStyle_WindowsAbsolute); + String8 file_path_resolved = str8_path_list_join_by_style(scratch.arena, &file_path_split, PathStyle_WindowsAbsolute); + String8 file_path_normalized = lower_from_str8(scratch.arena, file_path_resolved); + RDIM_SrcFile *src_file = hash_table_search_path_raw(source_file_ht, file_path_normalized); + if (src_file == 0) { + src_file = rdim_src_file_chunk_list_push(arena, &src_files, SRC_FILE_CAP); + src_file->normal_full_path = push_str8_copy(arena, file_path_normalized); + hash_table_push_path_raw(scratch.arena, source_file_ht, src_file->normal_full_path, src_file); + } + src_file_map[file_idx] = src_file; + } + + for (DW_LineSeqNode *line_seq = line_table->first_seq; line_seq != 0; line_seq = line_seq->next) { + if (line_seq->count == 0) { + continue; + } + + U64 *voffs = push_array(arena, U64, line_seq->count); + U32 *line_nums = push_array(arena, U32, line_seq->count); + U16 *col_nums = 0; + U64 line_idx = 0; + + DW_LineNode *file_line_n = line_seq->first; + U64 file_line_count = 0; + + for (DW_LineNode *line_n = file_line_n; line_n != 0; line_n = line_n->next) { + if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { + U64 file_index = file_line_n->v.file_index; + U64 *file_voffs = &voffs[line_idx]; + U32 *file_line_nums = &line_nums[line_idx]; + U16 *file_col_nums = 0; + + U64 lines_written = 0; + U64 prev_ln = max_U64; + DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; + for (; file_line_n != sentinel; file_line_n = file_line_n->next) { + if (file_line_n->v.line != prev_ln) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; + + ++lines_written; + ++line_idx; + + prev_ln = file_line_n->v.line; + } + } + + RDIM_SrcFile *src_file = src_file_map[file_index]; + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); + rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + + file_line_count = 1; + } else { + ++file_line_count; + } + } + + // handle last line + if (file_line_n) { + U64 file_index = file_line_n->v.file_index; + U64 *file_voffs = &voffs[line_idx]; + U32 *file_line_nums = &line_nums[line_idx]; + U16 *file_col_nums = 0; + + for (; file_line_n != 0; file_line_n = file_line_n->next, ++line_idx) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; + } + + RDIM_SrcFile *src_file = src_file_map[file_index]; + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); + rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + } + + //Assert(line_idx == line_seq->count); + } + } + + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Convert Units"); + + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + DW_CompUnit *cu = &cu_arr[cu_idx]; + + // parse and build tag tree + DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); + + // build tag hash table for abstract origin resolution + cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); + + String8 dwo_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_DwoName); + String8 gnu_dwo_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_GNU_DwoName); + if (dwo_name.size || gnu_dwo_name.size || cu->dwo_id) { + // TODO: report that we dont support DWO + continue; + } + + // get unit's contribution ranges + RDIM_Rng1U64List cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); + + String8 cu_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Name); + String8 cu_dir = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_CompDir); + String8 cu_prod = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Producer); + DW_Language cu_lang = dw_const_u64_from_attrib(&input, cu, cu->tag, DW_Attrib_Language); + + RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); + unit->unit_name = cu_name; + unit->compiler_name = cu_prod; + unit->source_file = str8_zero(); + unit->object_file = str8_zero(); + unit->archive_file = str8_zero(); + unit->build_path = cu_dir; + unit->language = rdi_language_from_dw_language(cu_lang); + unit->line_table = cu_line_tables_rdi[cu_idx]; + unit->voff_ranges = cu_voff_ranges; + + D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); + type_table->ht = hash_table_init(comp_temp.arena, 0x4000); + type_table->types = &types; + type_table->type_chunk_cap = TYPE_CHUNK_CAP; + type_table->varg_type = d2r_create_type(arena, type_table); + type_table->varg_type->kind = RDI_TypeKind_Variadic; + + D2R_TagNode *free_tags = push_array(comp_temp.arena, D2R_TagNode, 1); + D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); + tag_stack->cur_node = tag_tree.root; + + while (tag_stack) { + while (tag_stack->cur_node) { + DW_TagNode *cur_node = tag_stack->cur_node; + DW_Tag tag = cur_node->tag; + B32 visit_children = 1; + + switch (tag.kind) { + case DW_Tag_Null: { + InvalidPath; + } break; + case DW_Tag_ClassType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteClass; + + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + tag_stack->type = type; + } + } break; + case DW_Tag_StructureType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteStruct; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Struct; + type->udt = udt; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + + tag_stack->type = type; + } + } break; + case DW_Tag_UnionType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + + tag_stack->type = type; + } + } break; + case DW_Tag_EnumerationType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteEnum; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + + tag_stack->type = type; + } + } break; + case DW_Tag_SubroutineType: { + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_Tag_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_Attrib_Type); + rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_Tag_UnspecifiedParameters) { + rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->varg_type); + } else { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + + visit_children = 0; + } break; + case DW_Tag_Typedef: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_BaseType: { + DW_ATE encoding = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_Encoding); + U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *base_type = rdim_builtin_type_from_kind(types, kind); + base_type->kind = kind; + base_type->byte_size = byte_size; + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + type->direct_type = base_type; + } break; + case DW_Tag_PointerType: { + RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Allocated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Associated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); + } + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_Tag_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3][4]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] -> DW_Tag_Subrange [4] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array (2) -> Pointer -> Array (3) -> Array (4) -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Array; + type->direct_type = 0; + + U64 subrange_count = 0; + RDIM_Type *t = type; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_Tag_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + if (subrange_count > 0) { + // init array type node + RDIM_Type *s = d2r_create_type(arena, type_table); + s->kind = RDI_TypeKind_Array; + s->direct_type = 0; + + // append new array type node + t->direct_type = s; + t = s; + } + + // resolve array lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_LowerBound)) { + lower_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve array upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_Count)) { + U64 count = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_UpperBound)) { + upper_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero size array + } + + t->count = upper_bound - lower_bound; + ++subrange_count; + } + + Assert(t->direct_type == 0); + t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + visit_children = 0; + } break; + case DW_Tag_SubrangeType: { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } break; + case DW_Tag_Inheritance: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_StructureType && + parent_node->tag.kind != DW_Tag_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + member->off = safe_cast_u32(dw_const_u32_from_attrib(&input, cu, tag, DW_Attrib_DataMemberLocation)); + } break; + case DW_Tag_Enumerator: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + member->val = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_ConstValue); + } break; + case DW_Tag_Member: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_StructureType && + parent_node->tag.kind != DW_Tag_ClassType && + parent_node->tag.kind != DW_Tag_UnionType && + parent_node->tag.kind != DW_Tag_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_Attrib_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = RDI_MemberKind_DataField; + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + member->off = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_DataMemberLocation); + } break; + case DW_Tag_SubProgram: { + DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_Attrib_Inline); + switch (inl) { + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_Attrib_ContainingType)) { + container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_attrib(&input, cu, tag, DW_Attrib_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_External); + proc->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + proc->link_name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->frame_base = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, arch, tag, DW_Attrib_FrameBase); + + // sub program with user-defined parent tag is a method + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_ClassType || parent_tag_kind == DW_Tag_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + //default: InvalidPath; break; + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + } else if (parent_tag_kind != DW_Tag_CompileUnit) { + //AssertAlways(!"unexpected tag"); + } + + tag_stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + visit_children = 0; + } break; + default: InvalidPath; break; + } + } break; + case DW_Tag_InlinedSubroutine: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *owner = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_Attrib_ContainingType)) { + owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_ContainingType); + } + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->inline_site = inline_site; + } break; + case DW_Tag_Variable: { + String8 name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || + parent_tag_kind == DW_Tag_InlinedSubroutine || + parent_tag_kind == DW_Tag_LexicalBlock) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->locset = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { + break; + } + + RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); + gvar->is_extern = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_External); + gvar->name = name; + gvar->link_name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_LinkageName); + gvar->type = type; + //gvar->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, global_scope, image_base, arch, tag, DW_Attrib_Location); + gvar->container_symbol = 0; + gvar->container_type = 0; // TODO: NotImplemented; + } + } break; + case DW_Tag_FormalParameter: { + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || parent_tag_kind == DW_Tag_InlinedSubroutine) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + param->locset = d2r_var_locset_from_tag(arena, &input, cu, &scopes, scope, image_base, arch, tag); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_Tag_LexicalBlock: { + if (tag_stack->next->cur_node->tag.kind == DW_Tag_SubProgram || + tag_stack->next->cur_node->tag.kind == DW_Tag_InlinedSubroutine || + tag_stack->next->cur_node->tag.kind == DW_Tag_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + } + } break; + case DW_Tag_CallSite: { + // TODO + } break; + case DW_Tag_CallSiteParameter: { + // TODO + } break; + case DW_Tag_Label: + case DW_Tag_CompileUnit: + case DW_Tag_UnspecifiedParameters: + break; + case DW_Tag_Namespace: break; + case DW_Tag_ImportedDeclaration: break; + case DW_Tag_PtrToMemberType: break; + case DW_Tag_TemplateTypeParameter: break; + case DW_Tag_ReferenceType: break; + default: NotImplemented; break; + } + + if (tag_stack->cur_node->first_child && visit_children) { + D2R_TagNode *frame = free_tags; + if (frame) { + SLLStackPop(free_tags); + MemoryZeroStruct(frame); + } else { + frame = push_array(scratch.arena, D2R_TagNode, 1); + } + frame->cur_node = tag_stack->cur_node->first_child; + SLLStackPush(tag_stack, frame); + } else { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } + + // recycle free frame + D2R_TagNode *frame = tag_stack; + SLLStackPop(tag_stack); + SLLStackPush(free_tags, frame); + + if (tag_stack) { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } + + temp_end(comp_temp); + } + + ProfEnd(); + + { + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Alias) { + for (RDIM_Type *t = type->direct_type; t != 0; t = t->direct_type) { + if (t->byte_size != 0) { + type->byte_size = t->byte_size; + break; + } + } + } + } + } + } + + { + RDIM_TypeNode *type_stack = 0; + RDIM_TypeNode *free_types = 0; + + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Array) { + if (type->byte_size != 0) + continue; + + RDIM_Type *t; + for (t = type; t != 0 && t->kind == RDI_TypeKind_Array; t = t->direct_type) { + RDIM_TypeNode *f = free_types; + if (f == 0) { + f = push_array(scratch.arena, RDIM_TypeNode, 1); + } else { + SLLStackPop(free_types); + } + f->v = t; + SLLStackPush(type_stack, f); + } + + U64 base_type_size = 0; + if (t) { + base_type_size = t->byte_size; + } + + U64 array_size = base_type_size; + while (type_stack) { + if (type_stack->v->count) { + array_size *= type_stack->v->count; + } else { + array_size += type_stack->v->byte_size; + } + SLLStackPop(type_stack); + } + + type->count = 0; + type->byte_size = array_size; + + // recycle frames + free_types = type_stack; + type_stack = 0; + } + } + } + } + + //////////////////////////////// + + RDIM_BakeParams *bake_params = push_array(arena, RDIM_BakeParams, 1); + bake_params->top_level_info = top_level_info; + bake_params->binary_sections = binary_sections; + bake_params->units = units; + bake_params->types = types; + bake_params->udts = udts; + bake_params->src_files = src_files; + bake_params->line_tables = line_tables; + bake_params->global_variables = gvars; + bake_params->thread_variables = tvars; + bake_params->procedures = procs; + bake_params->scopes = scopes; + bake_params->inline_sites = inline_sites; + + scratch_end(scratch); + return bake_params; +} + +internal RDI_Language +rdi_language_from_dw_language(DW_Language v) +{ + RDI_Language result = RDI_Language_NULL; + switch (v) { + case DW_Language_Null: result = RDI_Language_NULL; break; + + case DW_Language_C89: + case DW_Language_C99: + case DW_Language_C11: + case DW_Language_C: + result = RDI_Language_C; + break; + + case DW_Language_CPlusPlus03: + case DW_Language_CPlusPlus11: + case DW_Language_CPlusPlus14: + case DW_Language_CPlusPlus: + result = RDI_Language_CPlusPlus; + break; + + default: NotImplemented; break; + } + return result; +} + +internal RDI_RegCodeX86 +rdi_reg_from_dw_reg_x86(DW_RegX86 v) +{ + RDI_RegCodeX86 result = RDI_RegCode_nil; + switch (v) { +#define X(reg_dw, val_dw, reg_rdi, ...) case DW_RegX86_##reg_dw: result = RDI_RegCodeX86_##reg_rdi; break; + DW_Regs_X86_XList(X) +#undef X + default: NotImplemented; break; + } + return result; +} + +internal B32 +rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out) +{ + RDI_RegCodeX64 result = RDI_RegCode_nil; + switch (v) { +#define X(reg_dw, val_dw, reg_rdi, off, size) case DW_RegX64_##reg_dw: result = RDI_RegCodeX64_##reg_rdi; *off_out = off; *size_out = size; break; + DW_Regs_X64_XList(X) +#undef X + default: NotImplemented; break; + } + return result; +} + +internal B32 +rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out) +{ + RDI_RegCode result = RDI_RegCode_nil; + switch (arch) { + case Arch_Null: break; + case Arch_x86: ; break; + case Arch_x64: return rdi_reg_from_dw_reg_x64(v, code_out, off_out, size_out); + default: NotImplemented; break; + } + return 0; +} + diff --git a/src/radcon/radcon_dwarf.h b/src/radcon/radcon_dwarf.h new file mode 100644 index 00000000..3029b314 --- /dev/null +++ b/src/radcon/radcon_dwarf.h @@ -0,0 +1,42 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADCON_DWARF_H +#define RADCON_DWARF_H + +typedef struct D2R_TypeTable +{ + HashTable *ht; + RDIM_TypeChunkList *types; + U64 type_chunk_cap; + RDIM_Type *varg_type; +} D2R_TypeTable; + +typedef struct D2R_TagNode +{ + struct D2R_TagNode *next; + DW_TagNode *cur_node; + RDIM_Type *type; + RDIM_Scope *scope; +} D2R_TagNode; + +typedef struct D2R_CompUnitContribMap +{ + U64 count; + U64 *info_off_arr; + RDIM_Rng1U64List *voff_range_arr; +} D2R_CompUnitContribMap; + +//////////////////////////////// + +internal RDIM_BakeParams * d2r_convert(Arena *arena, RDIM_LocalState *local_state, RC_Context *in); + +//////////////////////////////// + +internal RDI_Language rdi_language_from_dw_language(DW_Language v); +internal RDI_RegCodeX86 rdi_reg_from_dw_reg_x86(DW_RegX86 v); +internal B32 rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out); +internal B32 rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out); + +#endif // RADCON_DWARF_H + diff --git a/src/radcon/radcon_elf.c b/src/radcon/radcon_elf.c new file mode 100644 index 00000000..d5ab8333 --- /dev/null +++ b/src/radcon/radcon_elf.c @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal RDIM_BinarySectionList +e2r_rdi_binary_sections_from_elf_section_table(Arena *arena, ELF_Shdr64Array shdrs) +{ + RDIM_BinarySectionList result = {0}; + return result; +} + diff --git a/src/radcon/radcon_elf.h b/src/radcon/radcon_elf.h new file mode 100644 index 00000000..dadb2ae2 --- /dev/null +++ b/src/radcon/radcon_elf.h @@ -0,0 +1,9 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADCON_ELF_H +#define RADCON_ELF_H + +internal RDIM_BinarySectionList e2r_rdi_binary_sections_from_elf_section_table(Arena *arena, ELF_Shdr64Array shdrs); + +#endif // RADCON_ELF_H diff --git a/src/radcon/radcon_main.c b/src/radcon/radcon_main.c new file mode 100644 index 00000000..9f3c2b0a --- /dev/null +++ b/src/radcon/radcon_main.c @@ -0,0 +1,96 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define BUILD_TITLE "Epic Games Tools (R) RAD Debug Info Converter" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +// Third Party + +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" +#define XXH_STATIC_LINKING_ONLY +#include "third_party/xxHash/xxhash.c" +#include "third_party/xxHash/xxhash.h" +#define SINFL_IMPLEMENTATION +#include "third_party/sinfl/sinfl.h" +#include "third_party/radsort/radsort.h" + +//////////////////////////////// +// RDI Format Library + +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" + +//////////////////////////////// +// Headers + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "async/async.h" +#include "path/path.h" +#include "rdi_make/rdi_make_local.h" +#include "linker/hash_table.h" +#include "coff/coff.h" +#include "coff/coff_parse.h" +#include "pe/pe.h" +#include "elf/elf.h" +#include "elf/elf_parse.h" +#include "codeview/codeview.h" +#include "codeview/codeview_parse.h" +#include "dwarf/dwarf.h" +#include "dwarf/dwarf_parse.h" +#include "dwarf/dwarf_coff.h" +#include "dwarf/dwarf_elf.h" +#include "msf/msf.h" +#include "msf/msf_parse.h" +#include "pdb/pdb.h" +#include "pdb/pdb_parse.h" +#include "pdb/pdb_stringize.h" +#include "radcon.h" +#include "radcon_coff.h" +#include "radcon_elf.h" +#include "radcon_cv.h" +#include "radcon_dwarf.h" +#include "radcon_pdb.h" + +//////////////////////////////// +// Implementations + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "async/async.c" +#include "path/path.c" +#include "rdi_make/rdi_make_local.c" +#include "linker/hash_table.c" +#include "coff/coff.c" +#include "coff/coff_parse.c" +#include "pe/pe.c" +#include "elf/elf.c" +#include "elf/elf_parse.c" +#include "codeview/codeview.c" +#include "codeview/codeview_parse.c" +#include "msf/msf.c" +#include "msf/msf_parse.c" +#include "pdb/pdb.c" +#include "pdb/pdb_parse.c" +#include "pdb/pdb_stringize.c" +#include "dwarf/dwarf.c" +#include "dwarf/dwarf_parse.c" +#include "dwarf/dwarf_coff.c" +#include "dwarf/dwarf_elf.c" +#include "radcon.c" +#include "radcon_coff.c" +#include "radcon_elf.c" +#include "radcon_cv.c" +#include "radcon_dwarf.c" +#include "radcon_pdb.c" + +//////////////////////////////// + +internal void +entry_point(CmdLine *cmdl) +{ + rc_main(cmdl); +} + diff --git a/src/radcon/radcon_pdb.c b/src/radcon/radcon_pdb.c new file mode 100644 index 00000000..453c5b75 --- /dev/null +++ b/src/radcon/radcon_pdb.c @@ -0,0 +1,3190 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +// TODO(rjf): eliminate redundant null checks, just always allocate +// empty results, and have nulls gracefully fall through +// +// (search for != 0 instances, inserted to prevent prior crashes) + +global RDIM_LocalState *g_p2r_local_state = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +p2r_end_of_cplusplus_container_name(String8 str) +{ + // NOTE: This finds the index one past the last "::" contained in str. + // if no "::" is contained in str, then the returned index is 0. + // The intent is that [0,clamp_bot(0,result - 2)) gives the + // "container name" and [result,str.size) gives the leaf name. + U64 result = 0; + if(str.size >= 2) + { + for(U64 i = str.size; i >= 2; i -= 1) + { + if(str.str[i - 2] == ':' && str.str[i - 1] == ':') + { + result = i; + break; + } + } + } + return(result); +} + +internal U64 +p2r_hash_from_voff(U64 voff) +{ + U64 hash = (voff >> 3) ^ ((7 & voff) << 6); + return hash; +} + +//////////////////////////////// +//~ rjf: Location Info Building Helpers + +internal RDIM_Location * +p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection) +{ + RDIM_Location *result = 0; + if(0 <= offset && offset <= (S64)max_U16) + { + if(extra_indirection) + { + result = rdim_push_location_addr_addr_reg_plus_u16(arena, reg_code, (U16)offset); + } + else + { + result = rdim_push_location_addr_reg_plus_u16(arena, reg_code, (U16)offset); + } + } + else + { + RDIM_EvalBytecode bytecode = {0}; + U32 regread_param = RDI_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_RegRead, regread_param); + rdim_bytecode_push_sconst(arena, &bytecode, offset); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_Add, 0); + if(extra_indirection) + { + U64 addr_size = rdi_addr_size_from_arch(arch); + rdim_bytecode_push_op(arena, &bytecode, RDI_EvalOp_MemRead, addr_size); + } + result = rdim_push_location_addr_bytecode_stream(arena, &bytecode); + } + return result; +} + +internal void +p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count) +{ + //- rjf: extract range info + U64 voff_first = 0; + U64 voff_opl = 0; + if(section != 0) + { + voff_first = section->voff + range->off; + voff_opl = voff_first + range->len; + } + + //- rjf: emit ranges + CV_LvarAddrGap *gap_ptr = gaps; + U64 voff_cursor = voff_first; + for(U64 i = 0; i < gap_count; i += 1, gap_ptr += 1) + { + U64 voff_gap_first = voff_first + gap_ptr->off; + U64 voff_gap_opl = voff_gap_first + gap_ptr->len; + if(voff_cursor < voff_gap_first) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_gap_first}; + rdim_location_set_push_case(arena, scopes, locset, voff_range, location); + } + voff_cursor = voff_gap_opl; + } + + //- rjf: emit remaining range + if(voff_cursor < voff_opl) + { + RDIM_Rng1U64 voff_range = {voff_cursor, voff_opl}; + rdim_location_set_push_case(arena, scopes, locset, voff_range, location); + } +} + +//////////////////////////////// +//~ rjf: Initial Parsing & Preparation Pass Tasks + +ASYNC_WORK_DEF(p2r_exe_hash_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_EXEHashIn *in = (P2R_EXEHashIn *)input; + U64 *out = push_array(arena, U64, 1); + ProfScope("hash exe") *out = rdi_hash(in->exe_data.str, in->exe_data.size); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_tpi_hash_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_TPIHashParseIn *in = (P2R_TPIHashParseIn *)input; + void *out = 0; + ProfScope("parse tpi hash") out = pdb_tpi_hash_from_data(arena, in->strtbl, in->tpi, in->hash_data, in->aux_data); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_tpi_leaf_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_TPILeafParseIn *in = (P2R_TPILeafParseIn *)input; + void *out = 0; + ProfScope("parse tpi leaf") out = cv_leaf_from_data(arena, in->leaf_data, in->itype_first); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_symbol_stream_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_SymbolStreamParseIn *in = (P2R_SymbolStreamParseIn *)input; + void *out = 0; + ProfScope("parse symbol stream") out = cv_sym_from_data(arena, in->data, 4); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_c13_stream_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_C13StreamParseIn *in = (P2R_C13StreamParseIn *)input; + void *out = 0; + ProfScope("parse c13 stream") out = cv_c13_parsed_from_data(arena, in->data, in->strtbl, in->coff_sections); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_comp_unit_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_CompUnitParseIn *in = (P2R_CompUnitParseIn *)input; + void *out = 0; + ProfScope("parse comp units") out = pdb_comp_unit_array_from_data(arena, in->data); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_CompUnitContributionsParseIn *in = (P2R_CompUnitContributionsParseIn *)input; + void *out = 0; + ProfScope("parse comp unit contributions") out = pdb_comp_unit_contribution_array_from_data(arena, in->data, in->coff_sections); + ProfEnd(); + return out; +} + +//////////////////////////////// +//~ rjf: Unit Conversion Tasks + +ASYNC_WORK_DEF(p2r_units_convert_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + Temp scratch = scratch_begin(&arena, 1); + P2R_UnitConvertIn *in = (P2R_UnitConvertIn *)input; + P2R_UnitConvertOut *out = push_array(arena, P2R_UnitConvertOut, 1); + ProfScope("build units, initial src file map, & collect unit source files") + if(in->comp_units != 0) + { + U64 units_chunk_cap = in->comp_units->count; + P2R_SrcFileMap src_file_map = {0}; + src_file_map.slots_count = 65536; + src_file_map.slots = push_array(scratch.arena, P2R_SrcFileNode *, src_file_map.slots_count); + + //////////////////////////// + //- rjf: pass 1: build per-unit info & per-unit line tables + // + ProfScope("pass 1: build per-unit info & per-unit line tables") + for(U64 comp_unit_idx = 0; comp_unit_idx < in->comp_units->count; comp_unit_idx += 1) + { + PDB_CompUnit *pdb_unit = in->comp_units->units[comp_unit_idx]; + CV_SymParsed *pdb_unit_sym = in->comp_unit_syms[comp_unit_idx]; + CV_C13Parsed *pdb_unit_c13 = in->comp_unit_c13s[comp_unit_idx]; + + //- rjf: produce unit name + String8 unit_name = pdb_unit->obj_name; + if(unit_name.size != 0) + { + String8 unit_name_past_last_slash = str8_skip_last_slash(unit_name); + if(unit_name_past_last_slash.size != 0) + { + unit_name = unit_name_past_last_slash; + } + } + + //- rjf: produce obj name + String8 obj_name = pdb_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + + //- rjf: build this unit's line table, fill out primary line info (inline info added after) + RDIM_LineTable *line_table = 0; + for(CV_C13SubSectionNode *node = pdb_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13SubSectionKind_Lines) + { + for(CV_C13LinesParsedNode *lines_n = node->lines_first; + lines_n != 0; + lines_n = lines_n->next) + { + CV_C13LinesParsed *lines = &lines_n->v; + + // rjf: file name -> normalized file path + String8 file_path = lines->file_name; + String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + for(U64 idx = 0; idx < file_path_normalized.size; idx += 1) + { + if(file_path_normalized.str[idx] == '\\') + { + file_path_normalized.str[idx] = '/'; + } + } + + // rjf: normalized file path -> source file node + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->normal_full_path, file_path_normalized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); + SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096); + src_file_node->src_file->normal_full_path = push_str8_copy(arena, file_path_normalized); + } + + // rjf: push sequence into both line table & source file's line map + if(lines->line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, &out->line_tables, 256); + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, &out->line_tables, line_table, src_file_node->src_file, lines->voffs, lines->line_nums, lines->col_nums, lines->line_count); + rdim_src_file_push_line_sequence(arena, &out->src_files, src_file_node->src_file, seq); + } + } + } + } + + //- rjf: build unit + RDIM_Unit *dst_unit = rdim_unit_chunk_list_push(arena, &out->units, units_chunk_cap); + dst_unit->unit_name = unit_name; + dst_unit->compiler_name = pdb_unit_sym->info.compiler_name; + dst_unit->object_file = obj_name; + dst_unit->archive_file = pdb_unit->group_name; + dst_unit->language = cv2r_rdi_language_from_cv_language(pdb_unit_sym->info.language); + dst_unit->line_table = line_table; + } + + //////////////////////////// + //- rjf: pass 2: build per-unit voff ranges from comp unit contributions table + // + PDB_CompUnitContribution *contrib_ptr = in->comp_unit_contributions->contributions; + PDB_CompUnitContribution *contrib_opl = contrib_ptr + in->comp_unit_contributions->count; + ProfScope("pass 2: build per-unit voff ranges from comp unit contributions table") + for(;contrib_ptr < contrib_opl; contrib_ptr += 1) + { + if(contrib_ptr->mod < in->comp_units->count) + { + RDIM_Unit *unit = &out->units.first->v[contrib_ptr->mod]; + RDIM_Rng1U64 range = {contrib_ptr->voff_first, contrib_ptr->voff_opl}; + rdim_rng1u64_list_push(arena, &unit->voff_ranges, range); + } + } + + //////////////////////////// + //- rjf: pass 3: parse all inlinee line tables + // + out->units_first_inline_site_line_tables = push_array(arena, RDIM_LineTable *, in->comp_units->count); + ProfScope("pass 3: parse all inlinee line tables") + for(U64 comp_unit_idx = 0; comp_unit_idx < in->comp_units->count; comp_unit_idx += 1) + { + CV_SymParsed *unit_sym = in->comp_unit_syms[comp_unit_idx]; + CV_C13Parsed *unit_c13 = in->comp_unit_c13s[comp_unit_idx]; + CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; + U64 base_voff = 0; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > unit_sym->data.size || sym_off_first > unit_sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = unit_sym->data.str + sym_off_first; + void *sym_data_opl = unit_sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: process symbol + switch(kind) + { + default:{}break; + + //- rjf: LPROC32/GPROC32 (gather base address) + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + base_voff = section->voff + proc32->off; + } + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: map inlinee -> parsed cv c13 inlinee line info + CV_C13InlineeLinesParsed *inlinee_lines_parsed = 0; + { + U64 hash = cv_hash_from_item_id(sym->inlinee); + U64 slot_idx = hash%unit_c13->inlinee_lines_parsed_slots_count; + for(CV_C13InlineeLinesParsedNode *n = unit_c13->inlinee_lines_parsed_slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->v.inlinee == sym->inlinee) + { + inlinee_lines_parsed = &n->v; + break; + } + } + } + + // rjf: build line table, fill with parsed binary annotations + + if(inlinee_lines_parsed != 0) + { + // rjf: grab checksums sub-section + CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; + + // rjf: gathered lines + typedef struct LineChunk LineChunk; + struct LineChunk + { + LineChunk *next; + U64 cap; + U64 count; + U64 *voffs; // [line_count + 1] (sorted) + U32 *line_nums; // [line_count] + U16 *col_nums; // [2*line_count] + }; + LineChunk *first_line_chunk = 0; + LineChunk *last_line_chunk = 0; + U64 total_line_chunk_line_count = 0; + U32 last_file_off = max_U32; + U32 curr_file_off = max_U32; + RDIM_LineTable* line_table = 0; + + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); + for(;;) + { + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) + { + last_file_off = curr_file_off; + curr_file_off = step.file_off; + } + if(step.flags == 0 && total_line_chunk_line_count > 0) + { + last_file_off = curr_file_off; + curr_file_off = max_U32; + } + if((last_file_off != max_U32 && last_file_off != curr_file_off)) + { + String8 seq_file_name = {0}; + + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) + { + CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); + U32 name_off = checksum->name_off; + seq_file_name = pdb_strtbl_string_from_off(in->pdb_strtbl, name_off); + } + + // rjf: file name -> normalized file path + String8 file_path = seq_file_name; + String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); + for(U64 idx = 0; idx < file_path_normalized.size; idx += 1) + { + if(file_path_normalized.str[idx] == '\\') + { + file_path_normalized.str[idx] = '/'; + } + } + + // rjf: normalized file path -> source file node + U64 file_path_normalized_hash = rdi_hash(file_path_normalized.str, file_path_normalized.size); + U64 src_file_slot = file_path_normalized_hash%src_file_map.slots_count; + P2R_SrcFileNode *src_file_node = 0; + for(P2R_SrcFileNode *n = src_file_map.slots[src_file_slot]; n != 0; n = n->next) + { + if(str8_match(n->src_file->normal_full_path, file_path_normalized, 0)) + { + src_file_node = n; + break; + } + } + if(src_file_node == 0) + { + src_file_node = push_array(scratch.arena, P2R_SrcFileNode, 1); + SLLStackPush(src_file_map.slots[src_file_slot], src_file_node); + src_file_node->src_file = rdim_src_file_chunk_list_push(arena, &out->src_files, 4096); + src_file_node->src_file->normal_full_path = push_str8_copy(arena, file_path_normalized); + } + + // rjf: gather all lines + RDI_U64 *voffs = push_array_no_zero(arena, RDI_U64, total_line_chunk_line_count+1); + RDI_U32 *line_nums = push_array_no_zero(arena, RDI_U32, total_line_chunk_line_count); + RDI_U64 line_count = total_line_chunk_line_count; + { + U64 dst_idx = 0; + for(LineChunk *chunk = first_line_chunk; chunk != 0; chunk = chunk->next) + { + MemoryCopy(voffs+dst_idx, chunk->voffs, sizeof(U64)*(chunk->count+1)); + MemoryCopy(line_nums+dst_idx, chunk->line_nums, sizeof(U32)*chunk->count); + dst_idx += chunk->count; + } + } + + // rjf: push + if(line_count != 0) + { + if(line_table == 0) + { + line_table = rdim_line_table_chunk_list_push(arena, &out->line_tables, 256); + if(out->units_first_inline_site_line_tables[comp_unit_idx] == 0) + { + out->units_first_inline_site_line_tables[comp_unit_idx] = line_table; + } + } + RDIM_LineSequence *seq = rdim_line_table_push_sequence(arena, &out->line_tables, line_table, src_file_node->src_file, voffs, line_nums, 0, line_count); + rdim_src_file_push_line_sequence(arena, &out->src_files, src_file_node->src_file, seq); + } + + // rjf: clear line chunks for subsequent sequences + first_line_chunk = last_line_chunk = 0; + total_line_chunk_line_count = 0; + } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) + { + LineChunk *chunk = last_line_chunk; + if(chunk == 0 || chunk->count+1 >= chunk->cap) + { + chunk = push_array(scratch.arena, LineChunk, 1); + SLLQueuePush(first_line_chunk, last_line_chunk, chunk); + chunk->cap = 256; + chunk->voffs = push_array_no_zero(scratch.arena, U64, chunk->cap); + chunk->line_nums = push_array_no_zero(scratch.arena, U32, chunk->cap); + } + chunk->voffs[chunk->count] = step.line_voff; + chunk->voffs[chunk->count+1] = step.line_voff_end; + chunk->line_nums[chunk->count] = step.ln; + chunk->count += 1; + total_line_chunk_line_count += 1; + } + + if(step.flags == 0) + { + break; + } + } + } + }break; + } + } + } + } + scratch_end(scratch); + ProfEnd(); + return out; +} + +//////////////////////////////// +//~ rjf: Link Name Map Building Tasks + +ASYNC_WORK_DEF(p2r_link_name_map_build_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_LinkNameMapBuildIn *in = (P2R_LinkNameMapBuildIn *)input; + CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges; + CV_RecRange *rec_ranges_opl = rec_ranges_first + in->sym->sym_ranges.count; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: unpack symbol range info + CV_SymKind kind = rec_range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_sym_kind(kind); + U8 *sym_first = in->sym->data.str + rec_range->off + 2; + U8 *sym_opl = sym_first + rec_range->hdr.size; + + //- rjf: skip bad ranges + if(sym_opl > in->sym->data.str + in->sym->data.size || sym_first + header_struct_size > in->sym->data.str + in->sym->data.size) + { + continue; + } + + //- rjf: consume symbol + switch(kind) + { + default:{}break; + case CV_SymKind_PUB32: + { + // rjf: unpack sym + CV_SymPub32 *pub32 = (CV_SymPub32 *)sym_first; + String8 name = str8_cstring_capped(pub32+1, sym_opl); + COFF_SectionHeader *section = (0 < pub32->sec && pub32->sec <= in->coff_sections.count) ? &in->coff_sections.v[pub32->sec-1] : 0; + U64 voff = 0; + if(section != 0) + { + voff = section->voff + pub32->off; + } + + // rjf: commit to link name map + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%in->link_name_map->buckets_count; + P2R_LinkNameNode *node = push_array(arena, P2R_LinkNameNode, 1); + SLLStackPush(in->link_name_map->buckets[bucket_idx], node); + node->voff = voff; + node->name = name; + in->link_name_map->link_name_count += 1; + in->link_name_map->bucket_collision_count += (node->next != 0); + }break; + } + } + ProfEnd(); + return 0; +} + +//////////////////////////////// +//~ rjf: UDT Conversion Tasks + +ASYNC_WORK_DEF(p2r_udt_convert_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + P2R_UDTConvertIn *in = (P2R_UDTConvertIn *)input; +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[itype]) : 0) + RDIM_UDTChunkList *udts = push_array(arena, RDIM_UDTChunkList, 1); + RDI_U64 udts_chunk_cap = 1024; + ProfScope("convert UDT info") + { + for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) + { + //- rjf: skip basics + if(itype < in->tpi_leaf->itype_first) { continue; } + + //- rjf: grab type for this itype - skip if empty + RDIM_Type *dst_type = in->itype_type_ptrs[itype]; + if(dst_type == 0) { continue; } + + //- rjf: unpack itype leaf range - skip if out-of-range + CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[itype-in->tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + if(range->off+range->hdr.size > in->tpi_leaf->data.size || + range->off+2+header_struct_size > in->tpi_leaf->data.size || + range->hdr.size < 2) + { + continue; + } + + //- rjf: build UDT + CV_TypeId field_itype = 0; + switch(kind) + { + default:{}break; + + //////////////////////// + //- rjf: structs/unions/classes -> equip members + // + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_UNION: + { + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_members; + equip_members: + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < in->tpi_leaf->itype_first || in->tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[field_list_itype-in->tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > in->tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = in->tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_list_opl; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: MEMBER + case CV_LeafKind_MEMBER: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafMember *lf = (CV_LeafMember *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + U8 *name_ptr = offset_ptr + offset.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_DataField; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: STMEMBER + case CV_LeafKind_STMEMBER: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafStMember *lf = (CV_LeafStMember *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticData; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: METHOD + case CV_LeafKind_METHOD: + { + // rjf: unpack leaf + CV_LeafMethod *lf = (CV_LeafMethod *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + //- rjf: method list itype -> range + CV_RecRange *method_list_range = &in->tpi_leaf->leaf_ranges.ranges[lf->list_itype-in->tpi_leaf->itype_first]; + + //- rjf: skip bad method lists + if(method_list_range->off+method_list_range->hdr.size > in->tpi_leaf->data.size || + method_list_range->hdr.size < 2 || + method_list_range->hdr.kind != CV_LeafKind_METHODLIST) + { + break; + } + + //- rjf: loop through all methods & emit members + U8 *method_list_first = in->tpi_leaf->data.str + method_list_range->off + 2; + U8 *method_list_opl = method_list_first + method_list_range->hdr.size-2; + for(U8 *method_read_ptr = method_list_first, *next_method_read_ptr = method_list_opl; + method_read_ptr < method_list_opl; + method_read_ptr = next_method_read_ptr) + { + CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)method_read_ptr; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(method->attribs); + RDIM_Type *method_type = p2r_type_ptr_from_itype(method->itype); + next_method_read_ptr = (U8 *)(method+1); + + // TODO(allen): PROBLEM + // We only get offsets for virtual functions (the "vbaseoff") from + // "Intro" and "PureIntro". In C++ inheritance, when we have a chain + // of inheritance (let's just talk single inheritance for now) the + // first class in the chain that introduces a new virtual function + // has this "Intro" method. If a later class in the chain redefines + // the virtual function it only has a "Virtual" method which does + // not update the offset. There is a "Virtual" and "PureVirtual" + // variant of "Virtual". The "Pure" in either case means there + // is no concrete procedure. When there is no "Pure" the method + // should have a corresponding procedure symbol id. + // + // The issue is we will want to mark all of our virtual methods as + // virtual and give them an offset, but that means we have to do + // some extra figuring to propogate offsets from "Intro" methods + // to "Virtual" methods in inheritance trees. That is - IF we want + // to start preserving the offsets of virtuals. There is room in + // the method struct to make this work, but for now I've just + // decided to drop this information. It is not urgently useful to + // us and greatly complicates matters. + + // rjf: read vbaseoff + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + if(next_method_read_ptr+4 <= method_list_opl) + { + vbaseoff = *(U32 *)next_method_read_ptr; + } + next_method_read_ptr += 4; + } + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + } + + }break; + + //- rjf: ONEMETHOD + case CV_LeafKind_ONEMETHOD: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafOneMethod *lf = (CV_LeafOneMethod *)field_leaf_first; + CV_MethodProp prop = CV_FieldAttribs_Extract_MethodProp(lf->attribs); + U8 *vbaseoff_ptr = (U8 *)(lf+1); + U8 *vbaseoff_opl_ptr = vbaseoff_ptr; + U32 vbaseoff = 0; + if(prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro) + { + vbaseoff = *(U32 *)(vbaseoff_ptr); + vbaseoff_opl_ptr += sizeof(U32); + } + U8 *name_ptr = vbaseoff_opl_ptr; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + RDIM_Type *method_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit method + switch(prop) + { + default: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Method; + mem->name = name; + mem->type = method_type; + }break; + + case CV_MethodProp_Static: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_StaticMethod; + mem->name = name; + mem->type = method_type; + }break; + + case CV_MethodProp_Virtual: + case CV_MethodProp_PureVirtual: + case CV_MethodProp_Intro: + case CV_MethodProp_PureIntro: + { + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualMethod; + mem->name = name; + mem->type = method_type; + }break; + } + }break; + + //- rjf: NESTTYPE + case CV_LeafKind_NESTTYPE: + { + // rjf: unpack leaf + CV_LeafNestType *lf = (CV_LeafNestType *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: NESTTYPEEX + case CV_LeafKind_NESTTYPEEX: + { + // TODO(rjf): handle attribs + + // rjf: unpack leaf + CV_LeafNestTypeEx *lf = (CV_LeafNestTypeEx *)field_leaf_first; + U8 *name_ptr = (U8 *)(lf+1); + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_NestedType; + mem->name = name; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: BCLASS + case CV_LeafKind_BCLASS: + { + // TODO(rjf): log on bad offset + + // rjf: unpack leaf + CV_LeafBClass *lf = (CV_LeafBClass *)field_leaf_first; + U8 *offset_ptr = (U8 *)(lf+1); + CV_NumericParsed offset = cv_numeric_from_data_range(offset_ptr, field_leaf_opl); + U64 offset64 = cv_u64_from_numeric(&offset); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = offset_ptr+offset.encoded_size; + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_Base; + mem->type = p2r_type_ptr_from_itype(lf->itype); + mem->off = (U32)offset64; + }break; + + //- rjf: VBCLASS/IVBCLASS + case CV_LeafKind_VBCLASS: + case CV_LeafKind_IVBCLASS: + { + // TODO(rjf): log on bad offsets + // TODO(rjf): handle attribs + // TODO(rjf): offsets? + + // rjf: unpack leaf + CV_LeafVBClass *lf = (CV_LeafVBClass *)field_leaf_first; + U8 *num1_ptr = (U8 *)(lf+1); + CV_NumericParsed num1 = cv_numeric_from_data_range(num1_ptr, field_leaf_opl); + U8 *num2_ptr = num1_ptr + num1.encoded_size; + CV_NumericParsed num2 = cv_numeric_from_data_range(num2_ptr, field_leaf_opl); + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // rjf: emit member + RDIM_UDTMember *mem = rdim_udt_push_member(arena, udts, dst_udt); + mem->kind = RDI_MemberKind_VirtualBase; + mem->type = p2r_type_ptr_from_itype(lf->itype); + }break; + + //- rjf: VFUNCTAB + case CV_LeafKind_VFUNCTAB: + { + CV_LeafVFuncTab *lf = (CV_LeafVFuncTab *)field_leaf_first; + + // rjf: bump next read pointer past header + next_read_ptr = (U8 *)(lf+1); + + // NOTE(rjf): currently no-op this case + (void)lf; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + + //////////////////////// + //- rjf: enums -> equip enumerates + // + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + if(lf->props & CV_TypeProp_FwdRef) + { + break; + } + field_itype = lf->field_itype; + }goto equip_enum_vals; + equip_enum_vals:; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: grab UDT info + RDIM_UDT *dst_udt = dst_type->udt; + if(dst_udt == 0) + { + dst_udt = dst_type->udt = rdim_udt_chunk_list_push(arena, udts, udts_chunk_cap); + dst_udt->self_type = dst_type; + } + + //- rjf: gather all fields + typedef struct FieldListTask FieldListTask; + struct FieldListTask + { + FieldListTask *next; + CV_TypeId itype; + }; + FieldListTask start_fl_task = {0, field_itype}; + FieldListTask *fl_todo_stack = &start_fl_task; + FieldListTask *fl_done_stack = 0; + for(;fl_todo_stack != 0;) + { + //- rjf: take & unpack task + FieldListTask *fl_task = fl_todo_stack; + SLLStackPop(fl_todo_stack); + SLLStackPush(fl_done_stack, fl_task); + CV_TypeId field_list_itype = fl_task->itype; + + //- rjf: skip bad itypes + if(field_list_itype < in->tpi_leaf->itype_first || in->tpi_leaf->itype_opl <= field_list_itype) + { + continue; + } + + //- rjf: field list itype -> range + CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[field_list_itype-in->tpi_leaf->itype_first]; + + //- rjf: skip bad headers + if(range->off+range->hdr.size > in->tpi_leaf->data.size || + range->hdr.size < 2 || + range->hdr.kind != CV_LeafKind_FIELDLIST) + { + continue; + } + + //- rjf: loop over all fields + { + U8 *field_list_first = in->tpi_leaf->data.str+range->off+2; + U8 *field_list_opl = field_list_first+range->hdr.size-2; + for(U8 *read_ptr = field_list_first, *next_read_ptr = field_list_opl; + read_ptr < field_list_opl; + read_ptr = next_read_ptr) + { + // rjf: unpack field + CV_LeafKind field_kind = *(CV_LeafKind *)read_ptr; + U64 field_leaf_header_size = cv_header_struct_size_from_leaf_kind(field_kind); + U8 *field_leaf_first = read_ptr+2; + U8 *field_leaf_opl = field_leaf_first+range->hdr.size-2; + next_read_ptr = field_leaf_opl; + + // rjf: skip out-of-bounds fields + if(field_leaf_first+field_leaf_header_size > field_list_opl) + { + continue; + } + + // rjf: process field + switch(field_kind) + { + //- rjf: unhandled/invalid cases + default: + { + // TODO(rjf): log + }break; + + //- rjf: INDEX + case CV_LeafKind_INDEX: + { + // rjf: unpack leaf + CV_LeafIndex *lf = (CV_LeafIndex *)field_leaf_first; + CV_TypeId new_itype = lf->itype; + + // rjf: determine if index itype is new + B32 is_new = 1; + for(FieldListTask *t = fl_done_stack; t != 0; t = t->next) + { + if(t->itype == new_itype) + { + is_new = 0; + break; + } + } + + // rjf: if new -> push task to follow new itype + if(is_new) + { + FieldListTask *new_task = push_array(scratch.arena, FieldListTask, 1); + SLLStackPush(fl_todo_stack, new_task); + new_task->itype = new_itype; + } + }break; + + //- rjf: ENUMERATE + case CV_LeafKind_ENUMERATE: + { + // TODO(rjf): attribs + + // rjf: unpack leaf + CV_LeafEnumerate *lf = (CV_LeafEnumerate *)field_leaf_first; + U8 *val_ptr = (U8 *)(lf+1); + CV_NumericParsed val = cv_numeric_from_data_range(val_ptr, field_leaf_opl); + U64 val64 = cv_u64_from_numeric(&val); + U8 *name_ptr = val_ptr + val.encoded_size; + String8 name = str8_cstring_capped(name_ptr, field_leaf_opl); + + // rjf: bump next read pointer past variable length parts + next_read_ptr = name.str+name.size+1; + + // rjf: emit member + RDIM_UDTEnumVal *enum_val = rdim_udt_push_enum_val(arena, udts, dst_udt); + enum_val->name = name; + enum_val->val = val64; + }break; + } + + // rjf: align-up next field + next_read_ptr = (U8 *)AlignPow2((U64)next_read_ptr, 4); + } + } + } + + scratch_end(scratch); + }break; + } + } + } +#undef p2r_type_ptr_from_itype + ProfEnd(); + return udts; +} + +//////////////////////////////// +//~ rjf: Symbol Stream Conversion Path & Thread + +ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) +{ + ProfBeginFunction(); + Arena *arena = g_p2r_local_state->work_thread_arenas[thread_idx]; + Temp scratch = scratch_begin(&arena, 1); + P2R_SymbolStreamConvertIn *in = (P2R_SymbolStreamConvertIn *)input; +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[itype]) : 0) + + ////////////////////////// + //- rjf: set up outputs for this sym stream + // + U64 sym_procedures_chunk_cap = 1024; + U64 sym_global_variables_chunk_cap = 1024; + U64 sym_thread_variables_chunk_cap = 1024; + U64 sym_scopes_chunk_cap = 1024; + U64 sym_inline_sites_chunk_cap = 1024; + RDIM_SymbolChunkList sym_procedures = {0}; + RDIM_SymbolChunkList sym_global_variables = {0}; + RDIM_SymbolChunkList sym_thread_variables = {0}; + RDIM_ScopeChunkList sym_scopes = {0}; + RDIM_InlineSiteChunkList sym_inline_sites = {0}; + + ////////////////////////// + //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) + // + U64 procedure_frameprocs_count = 0; + U64 procedure_frameprocs_cap = (in->sym_ranges_opl - in->sym_ranges_first); + CV_SymFrameproc **procedure_frameprocs = push_array_no_zero(scratch.arena, CV_SymFrameproc *, procedure_frameprocs_cap); + ProfScope("symbols pass 1: produce procedure frame info map (procedure -> frame info)") + { + U64 procedure_num = 0; + CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges + in->sym_ranges_first; + CV_RecRange *rec_ranges_opl = in->sym->sym_ranges.ranges + in->sym_ranges_opl; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > in->sym->data.size || sym_off_first > in->sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = in->sym->data.str + sym_off_first; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: FRAMEPROC + case CV_SymKind_FRAMEPROC: + { + if(procedure_num == 0) { break; } + if(procedure_num > procedure_frameprocs_cap) { break; } + CV_SymFrameproc *frameproc = (CV_SymFrameproc*)sym_header_struct_base; + procedure_frameprocs[procedure_num-1] = frameproc; + procedure_frameprocs_count = Max(procedure_frameprocs_count, procedure_num); + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + procedure_num += 1; + }break; + } + } + U64 scratch_overkill = sizeof(procedure_frameprocs[0])*(procedure_frameprocs_cap-procedure_frameprocs_count); + arena_pop(scratch.arena, scratch_overkill); + } + + ////////////////////////// + //- rjf: symbols pass 2: construct all symbols, given procedure frame info map + // + ProfScope("symbols pass 2: construct all symbols, given procedure frame info map") + { + RDIM_LocationSet *defrange_target = 0; + B32 defrange_target_is_param = 0; + U64 procedure_num = 0; + U64 procedure_base_voff = 0; + CV_RecRange *rec_ranges_first = in->sym->sym_ranges.ranges + in->sym_ranges_first; + CV_RecRange *rec_ranges_opl = in->sym->sym_ranges.ranges + in->sym_ranges_opl; + typedef struct P2R_ScopeNode P2R_ScopeNode; + struct P2R_ScopeNode + { + P2R_ScopeNode *next; + RDIM_Scope *scope; + }; + P2R_ScopeNode *top_scope_node = 0; + P2R_ScopeNode *free_scope_node = 0; + RDIM_LineTable *inline_site_line_table = in->first_inline_site_line_table; + for(CV_RecRange *rec_range = rec_ranges_first; + rec_range < rec_ranges_opl; + rec_range += 1) + { + //- rjf: rec range -> symbol info range + U64 sym_off_first = rec_range->off + 2; + U64 sym_off_opl = rec_range->off + rec_range->hdr.size; + + //- rjf: skip invalid ranges + if(sym_off_opl > in->sym->data.size || sym_off_first > in->sym->data.size || sym_off_first > sym_off_opl) + { + continue; + } + + //- rjf: unpack symbol info + CV_SymKind kind = rec_range->hdr.kind; + U64 sym_header_struct_size = cv_header_struct_size_from_sym_kind(kind); + void *sym_header_struct_base = in->sym->data.str + sym_off_first; + void *sym_data_opl = in->sym->data.str + sym_off_opl; + + //- rjf: skip bad sizes + if(sym_off_first + sym_header_struct_size > sym_off_opl) + { + continue; + } + + //- rjf: consume symbol based on kind + switch(kind) + { + default:{}break; + + //- rjf: END + case CV_SymKind_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: BLOCK32 + case CV_SymKind_BLOCK32: + { + // rjf: unpack sym + CV_SymBlock32 *block32 = (CV_SymBlock32 *)sym_header_struct_base; + + // rjf: build scope, insert into current parent scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + { + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + COFF_SectionHeader *section = (0 < block32->sec && block32->sec <= in->coff_sections.count) ? &in->coff_sections.v[block32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + block32->off; + U64 voff_last = voff_first + block32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + } + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + }break; + + //- rjf: LDATA32/GDATA32 + case CV_SymKind_LDATA32: + case CV_SymKind_GDATA32: + { + // rjf: unpack sym + CV_SymData32 *data32 = (CV_SymData32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(data32+1, sym_data_opl); + COFF_SectionHeader *section = (0 < data32->sec && data32->sec <= in->coff_sections.count) ? &in->coff_sections.v[data32->sec-1] : 0; + U64 voff = (section ? section->voff : 0) + data32->off; + + // rjf: determine if this is an exact duplicate global + // + // PDB likes to have duplicates of these spread across different + // symbol streams so we deduplicate across the entire translation + // context. + // + B32 is_duplicate = 0; + { + // TODO(rjf): @important global symbol dedup + } + + // rjf: is not duplicate -> push new global + if(!is_duplicate) + { + // rjf: unpack global variable's type + RDIM_Type *type = p2r_type_ptr_from_itype(data32->itype); + + // rjf: unpack global's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack global's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // form a VOFF location +#if 0 + RDIM_LocationSet locset = {0}; + RDIM_Location *voff_loc = rdim_push_location_voff(arena, voff); + rdim_location_set_push_case(arena, &locset, (RDIM_Rng1U64){0,max_U64}, voff_loc); +#endif + + // rjf: build symbol + RDIM_Symbol *symbol = rdim_symbol_chunk_list_push(arena, &sym_global_variables, sym_global_variables_chunk_cap); + symbol->is_extern = (kind == CV_SymKind_GDATA32); + symbol->name = name; + symbol->type = type; + //symbol->locset = locset; + symbol->container_symbol = container_symbol; + symbol->container_type = container_type; + } + }break; + + //- rjf: LPROC32/GPROC32 + case CV_SymKind_LPROC32: + case CV_SymKind_GPROC32: + { + // rjf: unpack sym + CV_SymProc32 *proc32 = (CV_SymProc32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(proc32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(proc32->itype); + + // rjf: unpack proc's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2 && in->tpi_hash != 0 && in->tpi_leaf != 0) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack proc's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // rjf: build procedure's root scope + // + // NOTE: even if there could be a containing scope at this point (which should be + // illegal in C/C++ but not necessarily in another language) we would not use + // it here because these scopes refer to the ranges of code that make up a + // procedure *not* the namespaces, so a procedure's root scope always has + // no parent. + RDIM_Scope *procedure_root_scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + { + COFF_SectionHeader *section = (0 < proc32->sec && proc32->sec <= in->coff_sections.count) ? &in->coff_sections.v[proc32->sec-1] : 0; + if(section != 0) + { + U64 voff_first = section->voff + proc32->off; + U64 voff_last = voff_first + proc32->len; + RDIM_Rng1U64 voff_range = {voff_first, voff_last}; + rdim_scope_push_voff_range(arena, &sym_scopes, procedure_root_scope, voff_range); + procedure_base_voff = voff_first; + } + } + + // rjf: root scope voff minimum range -> link name + String8 link_name = {0}; + if(procedure_root_scope->voff_ranges.min != 0) + { + U64 voff = procedure_root_scope->voff_ranges.min; + U64 hash = p2r_hash_from_voff(voff); + U64 bucket_idx = hash%in->link_name_map->buckets_count; + P2R_LinkNameNode *node = 0; + for(P2R_LinkNameNode *n = in->link_name_map->buckets[bucket_idx]; n != 0; n = n->next) + { + if(n->voff == voff) + { + link_name = n->name; + break; + } + } + } + + // rjf: build procedure symbol + RDIM_Symbol *procedure_symbol = rdim_symbol_chunk_list_push(arena, &sym_procedures, sym_procedures_chunk_cap); + procedure_symbol->is_extern = (kind == CV_SymKind_GPROC32); + procedure_symbol->name = name; + procedure_symbol->link_name = link_name; + procedure_symbol->type = type; + procedure_symbol->container_symbol = container_symbol; + procedure_symbol->container_type = container_type; + procedure_symbol->root_scope = procedure_root_scope; + + // rjf: fill root scope's symbol + procedure_root_scope->symbol = procedure_symbol; + + // rjf: push scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = procedure_root_scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: increment procedure counter + procedure_num += 1; + }break; + + //- rjf: REGREL32 + case CV_SymKind_REGREL32: + { + // TODO(rjf): apparently some of the information here may end up being + // redundant with "better" information from CV_SymKind_LOCAL record. + // we don't currently handle this, but if those cases arise then it + // will obviously be better to prefer the better information from both + // records. + + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymRegrel32 *regrel32 = (CV_SymRegrel32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(regrel32+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(regrel32->itype); + CV_Reg cv_reg = regrel32->reg; + U32 var_off = regrel32->reg_off; + + // rjf: determine if this is a parameter + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + { + B32 is_stack_reg = 0; + switch(in->arch) + { + default:{}break; + case RDI_Arch_X86:{is_stack_reg = (cv_reg == CV_Regx86_ESP);}break; + case RDI_Arch_X64:{is_stack_reg = (cv_reg == CV_Regx64_RSP);}break; + } + if(is_stack_reg) + { + U32 frame_size = 0xFFFFFFFF; + if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num < procedure_frameprocs_count) + { + CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; + frame_size = frameproc->frame_size; + } + if(var_off > frame_size) + { + local_kind = RDI_LocalKind_Parameter; + } + } + } + + // TODO(rjf): is this correct? + // rjf: redirect type, if 0, and if outside frame, to the return type of the + // containing procedure + if(local_kind == RDI_LocalKind_Parameter && regrel32->itype == 0 && + top_scope_node->scope->symbol != 0 && + top_scope_node->scope->symbol->type != 0) + { + type = top_scope_node->scope->symbol->type->direct_type; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: add location info to local + if(type != 0) + { + // rjf: determine if we need an extra indirection to the value + B32 extra_indirection_to_value = 0; + switch(in->arch) + { + case RDI_Arch_X86: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))); + }break; + case RDI_Arch_X64: + { + extra_indirection_to_value = (local_kind == RDI_LocalKind_Parameter && (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))); + }break; + } + + // rjf: get raddbg register code + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); + // TODO(rjf): real byte_size & byte_pos from cv_reg goes here + U32 byte_size = 8; + U32 byte_pos = 0; + + // rjf: set location case + RDIM_Location *loc = p2r_location_from_addr_reg_off(arena, in->arch, reg_code, byte_size, byte_pos, (S64)(S32)var_off, extra_indirection_to_value); + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, &sym_scopes, &local->locset, voff_range, loc); + } + }break; + + //- rjf: LTHREAD32/GTHREAD32 + case CV_SymKind_LTHREAD32: + case CV_SymKind_GTHREAD32: + { + // rjf: unpack sym + CV_SymThread32 *thread32 = (CV_SymThread32 *)sym_header_struct_base; + String8 name = str8_cstring_capped(thread32+1, sym_data_opl); + U32 tls_off = thread32->tls_off; + RDIM_Type *type = p2r_type_ptr_from_itype(thread32->itype); + + // rjf: unpack thread variable's container type + RDIM_Type *container_type = 0; + U64 container_name_opl = p2r_end_of_cplusplus_container_name(name); + if(container_name_opl > 2) + { + String8 container_name = str8(name.str, container_name_opl - 2); + CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, container_name, 0); + container_type = p2r_type_ptr_from_itype(cv_type_id); + } + + // rjf: unpack thread variable's container symbol + RDIM_Symbol *container_symbol = 0; + if(container_type == 0 && top_scope_node != 0) + { + container_symbol = top_scope_node->scope->symbol; + } + + // form TLS OFF location +#if 0 + RDIM_LocationSet locset = {0}; + RDIM_Location *tls_off_loc = rdim_push_location_tls_off(arena, tls_off); + rdim_location_set_push_case(arena, &locset, (RDIM_Rng1U64){0,max_U64}, tls_off_loc); +#endif + + // rjf: build symbol + RDIM_Symbol *tvar = rdim_symbol_chunk_list_push(arena, &sym_thread_variables, sym_thread_variables_chunk_cap); + tvar->name = name; + tvar->type = type; + tvar->is_extern = (kind == CV_SymKind_GTHREAD32); + //tvar->locset = locset; + tvar->container_type = container_type; + tvar->container_symbol = container_symbol; + }break; + + //- rjf: LOCAL + case CV_SymKind_LOCAL: + { + // rjf: no containing scope? -> malformed data; locals cannot be produced + // outside of a containing scope + if(top_scope_node == 0) + { + break; + } + + // rjf: unpack sym + CV_SymLocal *slocal = (CV_SymLocal *)sym_header_struct_base; + String8 name = str8_cstring_capped(slocal+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(slocal->itype); + + // rjf: determine if this symbol encodes the beginning of a global modification + B32 is_global_modification = 0; + if((slocal->flags & CV_LocalFlag_Global) || + (slocal->flags & CV_LocalFlag_Static)) + { + is_global_modification = 1; + } + + // rjf: is global modification -> emit global modification symbol + if(is_global_modification) + { + // TODO(rjf): add global modification symbols + defrange_target = 0; + defrange_target_is_param = 0; + } + + // rjf: is not a global modification -> emit a local variable + if(!is_global_modification) + { + // rjf: determine local kind + RDI_LocalKind local_kind = RDI_LocalKind_Variable; + if(slocal->flags & CV_LocalFlag_Param) + { + local_kind = RDI_LocalKind_Parameter; + } + + // rjf: build local + RDIM_Scope *scope = top_scope_node->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &sym_scopes, scope); + local->kind = local_kind; + local->name = name; + local->type = type; + + // rjf: save defrange target, for subsequent defrange symbols + defrange_target = &local->locset; + defrange_target_is_param = (local_kind == RDI_LocalKind_Parameter); + } + }break; + + //- rjf: DEFRANGE_REGISTESR + case CV_SymKind_DEFRANGE_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register->reg; + CV_LvarAddrRange *range = &defrange_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); + + // rjf: build location + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)sym_header_struct_base; + CV_LvarAddrRange *range = &defrange_fprel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: select frame pointer register + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = cv2r_reg_code_from_arch_encoded_fp_reg(in->arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(in->arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel->off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_SUBFIELD_REGISTER + case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)sym_header_struct_base; + CV_Reg cv_reg = defrange_subfield_register->reg; + CV_LvarAddrRange *range = &defrange_subfield_register->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); + + // rjf: skip "subfield" location info - currently not supported + if(defrange_subfield_register->field_offset != 0) + { + break; + } + + // rjf: build location + RDIM_Location *location = rdim_push_location_val_reg(arena, reg_code); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: find current procedure's frameproc + CV_SymFrameproc *frameproc = 0; + if(procedure_num != 0 && procedure_num <= procedure_frameprocs_count && procedure_frameprocs[procedure_num-1] != 0) + { + frameproc = procedure_frameprocs[procedure_num-1]; + } + + // rjf: no current valid frameproc? -> somehow we got a to a framepointer-relative defrange + // without having an actually active procedure - break + if(frameproc == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = (CV_SymDefrangeFramepointerRelFullScope*)sym_header_struct_base; + CV_EncodedFramePtrReg encoded_fp_reg = cv_pick_fp_encoding(frameproc, defrange_target_is_param); + RDI_RegCode fp_register_code = cv2r_reg_code_from_arch_encoded_fp_reg(in->arch, encoded_fp_reg); + + // rjf: build location + B32 extra_indirection = 0; + U32 byte_size = rdi_addr_size_from_arch(in->arch); + U32 byte_pos = 0; + S64 var_off = (S64)defrange_fprel_full_scope->off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, fp_register_code, byte_size, byte_pos, var_off, extra_indirection); + + // rjf: emit location over ranges + RDIM_Rng1U64 voff_range = {0, max_U64}; + rdim_location_set_push_case(arena, &sym_scopes, defrange_target, voff_range, location); + }break; + + //- rjf: DEFRANGE_REGISTER_REL + case CV_SymKind_DEFRANGE_REGISTER_REL: + { + // rjf: no defrange target? -> somehow we got to a defrange symbol without first seeing + // a local - break immediately + if(defrange_target == 0) + { + break; + } + + // rjf: unpack sym + CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)sym_header_struct_base; + CV_Reg cv_reg = defrange_register_rel->reg; + RDI_RegCode reg_code = cv2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); + CV_LvarAddrRange *range = &defrange_register_rel->range; + COFF_SectionHeader *range_section = (0 < range->sec && range->sec <= in->coff_sections.count) ? &in->coff_sections.v[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + + // rjf: build location + // TODO(rjf): offset & size from cv_reg code + U32 byte_size = rdi_addr_size_from_arch(in->arch); + U32 byte_pos = 0; + B32 extra_indirection_to_value = 0; + S64 var_off = defrange_register_rel->reg_off; + RDIM_Location *location = p2r_location_from_addr_reg_off(arena, in->arch, reg_code, byte_size, byte_pos, var_off, extra_indirection_to_value); + + // rjf: emit locations over ranges + p2r_location_over_lvar_addr_range(arena, &sym_scopes, defrange_target, location, range, range_section, gaps, gap_count); + }break; + + //- rjf: FILESTATIC + case CV_SymKind_FILESTATIC: + { + CV_SymFileStatic *file_static = (CV_SymFileStatic*)sym_header_struct_base; + String8 name = str8_cstring_capped(file_static+1, sym_data_opl); + RDIM_Type *type = p2r_type_ptr_from_itype(file_static->itype); + // TODO(rjf): emit a global modifier symbol + defrange_target = 0; + defrange_target_is_param = 0; + }break; + + //- rjf: INLINESITE + case CV_SymKind_INLINESITE: + { + // rjf: unpack sym + CV_SymInlineSite *sym = (CV_SymInlineSite *)sym_header_struct_base; + String8 binary_annots = str8((U8 *)(sym+1), rec_range->hdr.size - sizeof(rec_range->hdr.kind) - sizeof(*sym)); + + // rjf: extract external info about inline site + String8 name = str8_zero(); + RDIM_Type *type = 0; + RDIM_Type *owner = 0; + if(in->ipi_leaf != 0 && in->ipi_leaf->itype_first <= sym->inlinee && sym->inlinee < in->ipi_leaf->itype_opl) + { + CV_RecRange rec_range = in->ipi_leaf->leaf_ranges.ranges[sym->inlinee - in->ipi_leaf->itype_first]; + String8 rec_data = str8_substr(in->ipi_leaf->data, rng_1u64(rec_range.off, rec_range.off + rec_range.hdr.size)); + void *raw_leaf = rec_data.str + sizeof(U16); + + // rjf: extract method inline info + if(rec_range.hdr.kind == CV_LeafKind_MFUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafMFuncId)) + { + CV_LeafMFuncId *mfunc_id = (CV_LeafMFuncId*)raw_leaf; + name = str8_cstring_capped(mfunc_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(mfunc_id->itype); + owner = mfunc_id->owner_itype != 0 ? p2r_type_ptr_from_itype(mfunc_id->owner_itype) : 0; + } + + // rjf: extract non-method function inline info + else if(rec_range.hdr.kind == CV_LeafKind_FUNC_ID && + rec_range.hdr.size >= sizeof(CV_LeafFuncId)) + { + CV_LeafFuncId *func_id = (CV_LeafFuncId*)raw_leaf; + name = str8_cstring_capped(func_id + 1, rec_data.str + rec_data.size); + type = p2r_type_ptr_from_itype(func_id->itype); + owner = func_id->scope_string_id != 0 ? p2r_type_ptr_from_itype(func_id->scope_string_id) : 0; + } + } + + // rjf: build inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &sym_inline_sites, sym_inline_sites_chunk_cap); + inline_site->name = name; + inline_site->type = type; + inline_site->owner = owner; + inline_site->line_table = inline_site_line_table; + + // rjf: increment to next inline site line table in this unit + if(inline_site_line_table != 0 && inline_site_line_table->chunk != 0) + { + RDIM_LineTableChunkNode *chunk = inline_site_line_table->chunk; + U64 current_idx = (U64)(inline_site_line_table - chunk->v); + if(current_idx+1 < chunk->count) + { + inline_site_line_table += 1; + } + else + { + chunk = chunk->next; + inline_site_line_table = 0; + if(chunk != 0) + { + inline_site_line_table = chunk->v; + } + } + } + + // rjf: build scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, &sym_scopes, sym_scopes_chunk_cap); + scope->inline_site = inline_site; + if(top_scope_node == 0) + { + // TODO(rjf): log + } + if(top_scope_node != 0) + { + RDIM_Scope *top_scope = top_scope_node->scope; + SLLQueuePush_N(top_scope->first_child, top_scope->last_child, scope, next_sibling); + scope->parent_scope = top_scope; + scope->symbol = top_scope->symbol; + } + + // rjf: push this scope to scope stack + { + P2R_ScopeNode *node = free_scope_node; + if(node != 0) { SLLStackPop(free_scope_node); } + else { node = push_array_no_zero(scratch.arena, P2R_ScopeNode, 1); } + node->scope = scope; + SLLStackPush(top_scope_node, node); + } + + // rjf: parse offset ranges of this inline site - attach to scope + { + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(0, 0, procedure_base_voff); + for(;;) + { + CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) + { + // rjf: build new range & add to scope + RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; + rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); + } + + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) + { + if(scope->voff_ranges.last != 0) + { + scope->voff_ranges.last->v.max = step.range.max; + } + } + + if(step.flags == 0) + { + break; + } + } + } + }break; + + //- rjf: INLINESITE_END + case CV_SymKind_INLINESITE_END: + { + P2R_ScopeNode *n = top_scope_node; + if(n != 0) + { + SLLStackPop(top_scope_node); + SLLStackPush(free_scope_node, n); + } + defrange_target = 0; + defrange_target_is_param = 0; + }break; + } + } + } + + ////////////////////////// + //- rjf: allocate & fill output + // + P2R_SymbolStreamConvertOut *out = push_array(arena, P2R_SymbolStreamConvertOut, 1); + { + out->procedures = sym_procedures; + out->global_variables = sym_global_variables; + out->thread_variables = sym_thread_variables; + out->scopes = sym_scopes; + out->inline_sites = sym_inline_sites; + } + +#undef p2r_type_ptr_from_itype + scratch_end(scratch); + ProfEnd(); + return out; +} + +//////////////////////////////// +//~ rjf: Top-Level Conversion Entry Point + +internal RDIM_BakeParams * +p2r_convert(Arena *arena, RDIM_LocalState *local_state, RC_Context *in) +{ + Temp scratch = scratch_begin(&arena, 1); + + g_p2r_local_state = local_state; + + ////////////////////////////////////////////////////////////// + //- rjf: parse MSF structure + // + MSF_Parsed *msf = 0; + if(in->debug_data.size != 0) ProfScope("parse MSF structure") + { + msf = msf_parsed_from_data(arena, in->debug_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB auth_guid & named streams table + // + PDB_NamedStreamTable *named_streams = 0; + Guid auth_guid = {0}; + if(msf != 0) ProfScope("parse PDB auth_guid & named streams table") + { + Temp scratch = scratch_begin(&arena, 1); + String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_Info); + PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); + named_streams = pdb_named_stream_table_from_info(arena, info); + MemoryCopyStruct(&auth_guid, &info->auth_guid); + scratch_end(scratch); + + if (info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { + fprintf(stderr, "ERROR: PDB was linked with /DEBUG:FASTLINK (partial debug info is not supported). Please relink using /DEBUG:FULL."); + os_abort(1); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB strtbl + // + PDB_Strtbl *strtbl = 0; + String8 raw_strtbl = str8_zero(); + if(named_streams != 0) ProfScope("parse PDB strtbl") + { + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; + String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); + strtbl = pdb_strtbl_from_data(arena, strtbl_data); + raw_strtbl = str8_substr(strtbl_data, rng_1u64(strtbl->strblock_min, strtbl->strblock_max)); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse dbi + // + PDB_DbiParsed *dbi = 0; + if(msf != 0) ProfScope("parse dbi") + { + String8 dbi_data = msf_data_from_stream(msf, PDB_FixedStream_Dbi); + dbi = pdb_dbi_from_data(arena, dbi_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse tpi + // + PDB_TpiParsed *tpi = 0; + if(msf != 0) ProfScope("parse tpi") + { + String8 tpi_data = msf_data_from_stream(msf, PDB_FixedStream_Tpi); + tpi = pdb_tpi_from_data(arena, tpi_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse ipi + // + PDB_TpiParsed *ipi = 0; + if(msf != 0) ProfScope("parse ipi") + { + String8 ipi_data = msf_data_from_stream(msf, PDB_FixedStream_Ipi); + ipi = pdb_tpi_from_data(arena, ipi_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse coff sections + // + COFF_SectionHeaderArray coff_sections = {0}; + if(dbi != 0) ProfScope("parse coff sections") + { + MSF_StreamNumber section_stream = dbi->dbg_streams[PDB_DbiStream_SECTION_HEADER]; + String8 section_data = msf_data_from_stream(msf, section_stream); + coff_sections = pdb_coff_section_array_from_data(arena, section_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse gsi + // + PDB_GsiParsed *gsi = 0; + if(dbi != 0) ProfScope("parse gsi") + { + String8 gsi_data = msf_data_from_stream(msf, dbi->gsi_sn); + gsi = pdb_gsi_from_data(arena, gsi_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse psi + // + PDB_GsiParsed *psi_gsi_part = 0; + if(dbi != 0) ProfScope("parse psi") + { + String8 psi_data = msf_data_from_stream(msf, dbi->psi_sn); + String8 psi_data_gsi_part = str8_range(psi_data.str + sizeof(PDB_PsiHeader), psi_data.str + psi_data.size); + psi_gsi_part = pdb_gsi_from_data(arena, psi_data_gsi_part); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff EXE hash + // + P2R_EXEHashIn exe_hash_in = {in->image_data}; + ASYNC_Task *exe_hash_task = async_task_launch(scratch.arena, p2r_exe_hash_work, .input = &exe_hash_in); + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff TPI hash parse + // + P2R_TPIHashParseIn tpi_hash_in = {0}; + ASYNC_Task *tpi_hash_task = 0; + if(tpi != 0) + { + tpi_hash_in.strtbl = strtbl; + tpi_hash_in.tpi = tpi; + tpi_hash_in.hash_data = msf_data_from_stream(msf, tpi->hash_sn); + tpi_hash_in.aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); + tpi_hash_task = async_task_launch(scratch.arena, p2r_tpi_hash_parse_work, .input = &tpi_hash_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff TPI leaf parse + // + P2R_TPILeafParseIn tpi_leaf_in = {0}; + ASYNC_Task *tpi_leaf_task = 0; + if(tpi != 0) + { + tpi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(tpi); + tpi_leaf_in.itype_first = tpi->itype_first; + tpi_leaf_task = async_task_launch(scratch.arena, p2r_tpi_leaf_parse_work, .input = &tpi_leaf_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff IPI hash parse + // + P2R_TPIHashParseIn ipi_hash_in = {0}; + ASYNC_Task *ipi_hash_task = 0; + if(ipi != 0) + { + ipi_hash_in.strtbl = strtbl; + ipi_hash_in.tpi = ipi; + ipi_hash_in.hash_data = msf_data_from_stream(msf, ipi->hash_sn); + ipi_hash_in.aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); + ipi_hash_task = async_task_launch(scratch.arena, p2r_tpi_hash_parse_work, .input = &ipi_hash_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff IPI leaf parse + // + P2R_TPILeafParseIn ipi_leaf_in = {0}; + ASYNC_Task *ipi_leaf_task = 0; + if(ipi != 0) + { + ipi_leaf_in.leaf_data = pdb_leaf_data_from_tpi(ipi); + ipi_leaf_in.itype_first = ipi->itype_first; + ipi_leaf_task = async_task_launch(scratch.arena, p2r_tpi_leaf_parse_work, .input = &ipi_leaf_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff top-level global symbol stream parse + // + P2R_SymbolStreamParseIn sym_parse_in = {dbi ? msf_data_from_stream(msf, dbi->sym_sn) : str8_zero()}; + ASYNC_Task *sym_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_symbol_stream_parse_work, .input = &sym_parse_in); + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff compilation unit parses + // + P2R_CompUnitParseIn comp_unit_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo) : str8_zero()}; + P2R_CompUnitContributionsParseIn comp_unit_contributions_parse_in = {dbi ? pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon) : str8_zero(), coff_sections}; + ASYNC_Task *comp_unit_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_comp_unit_parse_work, .input = &comp_unit_parse_in); + ASYNC_Task *comp_unit_contributions_parse_task = !dbi ? 0 : async_task_launch(scratch.arena, p2r_comp_unit_contributions_parse_work, .input = &comp_unit_contributions_parse_in); + + ////////////////////////////////////////////////////////////// + //- rjf: join compilation unit parses + // + PDB_CompUnitArray *comp_units = 0; + U64 comp_unit_count = 0; + PDB_CompUnitContributionArray *comp_unit_contributions = 0; + U64 comp_unit_contribution_count = 0; + { + comp_units = async_task_join_struct(comp_unit_parse_task, PDB_CompUnitArray); + comp_unit_contributions = async_task_join_struct(comp_unit_contributions_parse_task, PDB_CompUnitContributionArray); + comp_unit_count = comp_units ? comp_units->count : 0; + comp_unit_contribution_count = comp_unit_contributions ? comp_unit_contributions->count : 0; + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse syms & line info for each compilation unit + // + CV_SymParsed **sym_for_unit = push_array(arena, CV_SymParsed *, comp_unit_count); + CV_C13Parsed **c13_for_unit = push_array(arena, CV_C13Parsed *, comp_unit_count); + if(comp_units != 0) ProfScope("parse syms & line info for each compilation unit") + { + //- rjf: kick off tasks + P2R_SymbolStreamParseIn *sym_tasks_inputs = push_array(scratch.arena, P2R_SymbolStreamParseIn, comp_unit_count); + ASYNC_Task **sym_tasks = push_array(scratch.arena, ASYNC_Task *, comp_unit_count); + P2R_C13StreamParseIn *c13_tasks_inputs = push_array(scratch.arena, P2R_C13StreamParseIn, comp_unit_count); + ASYNC_Task **c13_tasks = push_array(scratch.arena, ASYNC_Task *, comp_unit_count); + for(U64 idx = 0; idx < comp_unit_count; idx += 1) + { + PDB_CompUnit *unit = comp_units->units[idx]; + sym_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_Symbols); + sym_tasks[idx] = async_task_launch(scratch.arena, p2r_symbol_stream_parse_work, .input = &sym_tasks_inputs[idx]); + c13_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); + c13_tasks_inputs[idx].strtbl = raw_strtbl; + c13_tasks_inputs[idx].coff_sections = coff_sections; + c13_tasks[idx] = async_task_launch(scratch.arena, p2r_c13_stream_parse_work, .input = &c13_tasks_inputs[idx]); + } + + //- rjf: join tasks + for(U64 idx = 0; idx < comp_unit_count; idx += 1) + { + sym_for_unit[idx] = async_task_join_struct(sym_tasks[idx], CV_SymParsed); + c13_for_unit[idx] = async_task_join_struct(c13_tasks[idx], CV_C13Parsed); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: determine architecture + // + RDI_Arch arch = c2r_rdi_arch_from_coff_machine(dbi->machine_type); + U64 arch_addr_size = rdi_addr_size_from_arch(arch); + + ////////////////////////////////////////////////////////////// + //- rjf: join EXE hash + // + U64 exe_hash = *async_task_join_struct(exe_hash_task, U64); + + ////////////////////////////////////////////////////////////// + //- rjf: build binary sections list + // + RDIM_BinarySectionList binary_sections = c2r_rdi_binary_sections_from_coff_sections(arena, str8_zero(), str8_zero(), coff_sections.count, coff_sections.v); + + ////////////////////////////////////////////////////////////// + //- rjf: produce top-level-info + // + RDIM_TopLevelInfo top_level_info = rdim_make_top_level_info(in->image_name, arch_from_coff_machine(dbi->machine_type), exe_hash, binary_sections); + + ////////////////////////////////////////////////////////////// + //- rjf: kick off unit conversion & source file collection + // + P2R_UnitConvertIn unit_convert_in = {strtbl, coff_sections, comp_units, comp_unit_contributions, sym_for_unit, c13_for_unit}; + ASYNC_Task *unit_convert_task = async_task_launch(scratch.arena, p2r_units_convert_work, .input = &unit_convert_in); + + ////////////////////////////////////////////////////////////// + //- rjf: join global sym stream parse + // + CV_SymParsed *sym = async_task_join_struct(sym_parse_task, CV_SymParsed); + + ////////////////////////////// + //- rjf: predict symbol count + // + U64 symbol_count_prediction = 0; + ProfScope("predict symbol count") + { + U64 rec_range_count = 0; + if(sym != 0) + { + rec_range_count += sym->sym_ranges.count; + } + for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) + { + CV_SymParsed *unit_sym = sym_for_unit[comp_unit_idx]; + rec_range_count += unit_sym->sym_ranges.count; + } + symbol_count_prediction = rec_range_count/8; + if(symbol_count_prediction < 256) + { + symbol_count_prediction = 256; + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: kick off link name map production + // + P2R_LinkNameMap link_name_map__in_progress = {0}; + P2R_LinkNameMapBuildIn link_name_map_build_in = {0}; + ASYNC_Task *link_name_map_task = 0; + if(sym != 0) ProfScope("kick off link name map build task") + { + link_name_map__in_progress.buckets_count = symbol_count_prediction; + link_name_map__in_progress.buckets = push_array(arena, P2R_LinkNameNode *, link_name_map__in_progress.buckets_count); + link_name_map_build_in.sym = sym; + link_name_map_build_in.coff_sections = coff_sections; + link_name_map_build_in.link_name_map = &link_name_map__in_progress; + link_name_map_task = async_task_launch(scratch.arena, p2r_link_name_map_build_work, .input = &link_name_map_build_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: join ipi/tpi hash/leaf parses + // + PDB_TpiHashParsed *tpi_hash = 0; + CV_LeafParsed *tpi_leaf = 0; + PDB_TpiHashParsed *ipi_hash = 0; + CV_LeafParsed *ipi_leaf = 0; + { + tpi_hash = async_task_join_struct(tpi_hash_task, PDB_TpiHashParsed); + tpi_leaf = async_task_join_struct(tpi_leaf_task, CV_LeafParsed); + ipi_hash = async_task_join_struct(ipi_hash_task, PDB_TpiHashParsed); + ipi_leaf = async_task_join_struct(ipi_leaf_task, CV_LeafParsed); + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 1: construct all types from TPI + // + // this doesn't gather struct/class/union/enum members, which is done by + // subsequent passes, to build RDI "UDT" information, which is distinct + // from regular type info. + // + RDIM_Type **itype_type_ptrs = 0; + RDIM_TypeChunkList all_types = rdim_init_type_chunk_list(arena, arch); +#define p2r_type_ptr_from_itype(itype) (((itype) < tpi_leaf->itype_opl) ? itype_type_ptrs[itype] : 0) + if(in->flags & RC_Flag_Types) ProfScope("types pass 1: construct all root/stub types from TPI") + { + itype_type_ptrs = push_array(arena, RDIM_Type *, tpi_leaf->itype_opl); + + ////////////////////////// + //- build basic types + // + { + RDIM_DataModel data_model = rdim_infer_data_model(OperatingSystem_Windows, top_level_info.arch); + RDI_TypeKind short_type = rdim_short_type_from_data_model(data_model); + RDI_TypeKind long_type = rdim_long_type_from_data_model(data_model); + RDI_TypeKind long_long_type = rdim_long_long_type_from_data_model(data_model); + RDI_TypeKind ushort_type = rdim_unsigned_short_type_from_data_model(data_model); + RDI_TypeKind ulong_type = rdim_unsigned_long_type_from_data_model(data_model); + RDI_TypeKind ulong_long_type = rdim_unsigned_long_long_type_from_data_model(data_model); + RDI_TypeKind ptr_type = rdim_pointer_size_t_type_from_data_model(data_model); + + struct + { + char * name; + RDI_TypeKind kind_rdi; + CV_LeafKind kind_cv; + B32 make_pointer_near; + B32 make_pointer_32; + B32 make_pointer_64; + } + table[] = + { + { "" , RDI_TypeKind_NULL , CV_BasicType_NOTYPE , 0, 0, 0 }, + { "void" , RDI_TypeKind_Void , CV_BasicType_VOID , 1, 1, 1 }, + { "HRESULT" , RDI_TypeKind_Handle , CV_BasicType_HRESULT , 0, 1, 1 }, + { "signed char" , RDI_TypeKind_Char8 , CV_BasicType_CHAR , 1, 1, 1 }, + { "short" , short_type , CV_BasicType_SHORT , 1, 1, 1 }, + { "long" , long_type , CV_BasicType_LONG , 1, 1, 1 }, + { "long long" , long_long_type , CV_BasicType_QUAD , 1, 1, 1 }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_OCT , 1, 1, 1 }, // Clang type + { "unsigned char" , RDI_TypeKind_UChar8 , CV_BasicType_UCHAR , 1, 1, 1 }, + { "unsigned short" , ushort_type , CV_BasicType_USHORT , 1, 1, 1 }, + { "unsigned long" , ulong_type , CV_BasicType_ULONG , 1, 1, 1 }, + { "unsigned long long" , ulong_long_type , CV_BasicType_UQUAD , 1, 1, 1 }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UOCT , 1, 1, 1 }, // Clang type + { "bool" , RDI_TypeKind_S8 , CV_BasicType_BOOL8 , 1, 1, 1 }, + { "__bool16" , RDI_TypeKind_S16 , CV_BasicType_BOOL16 , 1, 1, 1 }, // not real C type + { "__bool32" , RDI_TypeKind_S32 , CV_BasicType_BOOL32 , 1, 1, 1 }, // not real C type + { "float" , RDI_TypeKind_F32 , CV_BasicType_FLOAT32 , 1, 1, 1 }, + { "double" , RDI_TypeKind_F64 , CV_BasicType_FLOAT64 , 1, 1, 1 }, + { "long double" , RDI_TypeKind_F80 , CV_BasicType_FLOAT80 , 1, 1, 1 }, + { "__float128" , RDI_TypeKind_F128 , CV_BasicType_FLOAT128 , 1, 1, 1 }, // Clang type + { "__float48" , RDI_TypeKind_F48 , CV_BasicType_FLOAT48 , 1, 1, 1 }, // not real C type + { "__float32pp" , RDI_TypeKind_F32PP , CV_BasicType_FLOAT32PP , 1, 1, 1 }, // not real C type + { "_Complex float" , RDI_TypeKind_ComplexF32 , CV_BasicType_COMPLEX32 , 0, 0, 0 }, + { "_Complex double" , RDI_TypeKind_ComplexF64 , CV_BasicType_COMPLEX64 , 0, 0, 0 }, + { "_Complex long double" , RDI_TypeKind_ComplexF80 , CV_BasicType_COMPLEX80 , 0, 0, 0 }, + { "_Complex __float128" , RDI_TypeKind_ComplexF128, CV_BasicType_COMPLEX128 , 0, 0, 0 }, + { "__int8" , RDI_TypeKind_S8 , CV_BasicType_INT8 , 1, 1, 1 }, + { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 , 1, 1, 1 }, + { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 , 1, 1, 1 }, + { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 , 1, 1, 1 }, + { "int" , RDI_TypeKind_S32 , CV_BasicType_INT32 , 1, 1, 1 }, + { "unsigned int" , RDI_TypeKind_U32 , CV_BasicType_UINT32 , 1, 1, 1 }, + { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 , 1, 1, 1 }, + { "__uint64" , RDI_TypeKind_U64 , CV_BasicType_UINT64 , 1, 1, 1 }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_INT128 , 1, 1, 1 }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UINT128 , 1, 1, 1 }, + { "char" , RDI_TypeKind_Char8 , CV_BasicType_RCHAR , 1, 1, 1 }, // always ASCII + { "wchar_t" , RDI_TypeKind_UChar16 , CV_BasicType_WCHAR , 1, 1, 1 }, // on windows always UTF-16 + { "char8_t" , RDI_TypeKind_Char8 , CV_BasicType_CHAR8 , 1, 1, 1 }, // always UTF-8 + { "char16_t" , RDI_TypeKind_Char16 , CV_BasicType_CHAR16 , 1, 1, 1 }, // always UTF-16 + { "char32_t" , RDI_TypeKind_Char32 , CV_BasicType_CHAR32 , 1, 1, 1 }, // always UTF-32 + { "__pointer" , ptr_type , CV_BasicType_PTR , 0, 0, 0 } + }; + + for(U64 i = 0; i < ArrayCount(table); i += 1) + { + RDIM_Type *type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + type->kind = RDI_TypeKind_Alias; + type->name = str8_cstring(table[i].name); + type->direct_type = rdim_builtin_type_from_kind(all_types, table[i].kind_rdi); + itype_type_ptrs[table[i].kind_cv] = type; + + if(table[i].make_pointer_near) + { + CV_TypeIndex near_ptr_itype = table[i].kind_cv | 0x100; + RDIM_Type *ptr_near = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + ptr_near->kind = RDI_TypeKind_Ptr; + ptr_near->byte_size = 2; + ptr_near->direct_type = type; + itype_type_ptrs[near_ptr_itype] = ptr_near; + } + if(table[i].make_pointer_32) + { + CV_TypeIndex ptr_32_itype = table[i].kind_cv | 0x400; + RDIM_Type *ptr_32 = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + ptr_32->kind = RDI_TypeKind_Ptr; + ptr_32->byte_size = 4; + ptr_32->direct_type = type; + itype_type_ptrs[ptr_32_itype] = ptr_32; + } + if(table[i].make_pointer_64) + { + CV_TypeIndex ptr_64_itype = table[i].kind_cv | 0x600; + RDIM_Type *ptr_64 = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + ptr_64->kind = RDI_TypeKind_Ptr; + ptr_64->byte_size = 8; + ptr_64->direct_type = type; + itype_type_ptrs[ptr_64_itype] = ptr_64; + } + } + } + + ////////////////////////// + //- rjf: build complex type + // + for(CV_TypeId itype = tpi_leaf->itype_first; itype < tpi_leaf->itype_opl; itype += 1) + { + RDIM_Type *dst_type = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-tpi_leaf->itype_first]; + CV_LeafKind kind = range->hdr.kind; + U64 header_struct_size = cv_header_struct_size_from_leaf_kind(kind); + + if(range->off+range->hdr.size <= tpi_leaf->data.size && + range->off+2+header_struct_size <= tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: + { + // rjf: unpack leaf + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: cv -> rdi flags + RDI_TypeModifierFlags flags = 0; + if(lf->flags & CV_ModifierFlag_Const) {flags |= RDI_TypeModifierFlag_Const;} + if(lf->flags & CV_ModifierFlag_Volatile) {flags |= RDI_TypeModifierFlag_Volatile;} + + // rjf: fill type + if(flags == 0) + { + dst_type = p2r_type_ptr_from_itype(lf->itype); + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = flags; + dst_type->direct_type = p2r_type_ptr_from_itype(lf->itype); + dst_type->byte_size = dst_type->direct_type ? dst_type->direct_type->byte_size : 0; + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: + { + // TODO(rjf): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead + + // rjf: unpack leaf + CV_LeafPointer *lf = (CV_LeafPointer *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + CV_PointerKind ptr_kind = CV_PointerAttribs_Extract_Kind(lf->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_Extract_Mode(lf->attribs); + U32 ptr_size = CV_PointerAttribs_Extract_Size(lf->attribs); + + // rjf: cv -> rdi modifier flags + RDI_TypeModifierFlags modifier_flags = 0; + if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} + if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} + if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} + + // rjf: cv info -> rdi pointer type kind + RDI_TypeKind type_kind = RDI_TypeKind_Ptr; + { + if(lf->attribs & CV_PointerAttrib_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(lf->attribs & CV_PointerAttrib_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + if(ptr_mode == CV_PointerMode_LRef) + { + type_kind = RDI_TypeKind_LRef; + } + else if(ptr_mode == CV_PointerMode_RRef) + { + type_kind = RDI_TypeKind_RRef; + } + } + + // rjf: fill type + if(modifier_flags != 0) + { + RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = RDI_TypeKind_Modifier; + dst_type->flags = modifier_flags; + dst_type->direct_type = pointer_type; + dst_type->byte_size = arch_addr_size; + pointer_type->kind = type_kind; + pointer_type->byte_size = arch_addr_size; + pointer_type->direct_type = direct_type; + } + else + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = type_kind; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = direct_type; + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + // TODO(rjf): handle call_kind & attribs + + // rjf: unpack leaf + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type's basics + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = RDI_TypeKind_Function; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count; + dst_type->param_types = params; + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + // TODO(rjf): handle call_kind & attribs + // TODO(rjf): preserve "this_adjust" + + // rjf: unpack leaf + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + RDIM_Type *ret_type = p2r_type_ptr_from_itype(lf->ret_itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = (lf->this_itype != 0) ? RDI_TypeKind_Method : RDI_TypeKind_Function; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = ret_type; + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &tpi_leaf->leaf_ranges.ranges[lf->arg_itype-tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = tpi_leaf->data.str + arglist_range->off + 2; + U8 *arglist_opl = arglist_first+arglist_range->hdr.size-2; + if(arglist_first + sizeof(CV_LeafArgList) > arglist_opl) + { + break; + } + + // rjf: unpack arglist info + CV_LeafArgList *arglist = (CV_LeafArgList*)arglist_first; + CV_TypeId *arglist_itypes_base = (CV_TypeId *)(arglist+1); + U32 arglist_itypes_count = arglist->count; + + // rjf: build param type array + U64 num_this_extras = 1; + if(lf->this_itype == 0) + { + num_this_extras = 0; + } + RDIM_Type **params = push_array(arena, RDIM_Type *, arglist_itypes_count+num_this_extras); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx+num_this_extras] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + if(lf->this_itype != 0) + { + params[0] = p2r_type_ptr_from_itype(lf->this_itype); + } + + // rjf: fill dst type + dst_type->count = arglist_itypes_count+num_this_extras; + dst_type->param_types = params; + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + // rjf: unpack leaf + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->itype); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = RDI_TypeKind_Bitfield; + dst_type->off = lf->pos; + dst_type->count = lf->len; + dst_type->byte_size = direct_type?direct_type->byte_size:0; + dst_type->direct_type = direct_type; + }break; + + //- rjf: ARRAY + case CV_LeafKind_ARRAY: + { + // rjf: unpack leaf + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->entry_itype); + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 full_size = cv_u64_from_numeric(&array_count); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + dst_type->kind = RDI_TypeKind_Array; + dst_type->direct_type = direct_type; + dst_type->byte_size = full_size; + }break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct *lf = (CV_LeafStruct *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + } + + B32 do_unique_name_lookup = (((lf->props & CV_TypeProp_Scoped) != 0) && + ((lf->props & CV_TypeProp_HasUniqueName) != 0)); + if(do_unique_name_lookup) + { + U8 *unique_name_ptr = name_ptr + name.size + 1; + dst_type->link_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + } + + dst_type->name = name; + dst_type->byte_size = safe_cast_u32(size_u64); + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafStruct2 *lf = (CV_LeafStruct2 *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS2 ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + + B32 do_unique_name_lookup = (((lf->props & CV_TypeProp_Scoped) != 0) && + ((lf->props & CV_TypeProp_HasUniqueName) != 0)); + if(do_unique_name_lookup) + { + U8 *unique_name_ptr = name_ptr + name.size + 1; + dst_type->link_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafUnion *lf = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8*)(lf + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U64 size_u64 = cv_u64_from_numeric(&size); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteUnion; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Union; + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + + B32 do_unique_name_lookup = (((lf->props & CV_TypeProp_Scoped) != 0) && + ((lf->props & CV_TypeProp_HasUniqueName) != 0)); + if(do_unique_name_lookup) + { + U8 *unique_name_ptr = name_ptr + name.size + 1; + dst_type->link_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // TODO(rjf): handle props + + // rjf: unpack leaf + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + RDIM_Type *direct_type = p2r_type_ptr_from_itype(lf->base_itype); + U8 *name_ptr = (U8 *)(lf + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + + // rjf: fill type + dst_type = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = RDI_TypeKind_IncompleteEnum; + dst_type->name = name; + } + else + { + dst_type->kind = RDI_TypeKind_Enum; + dst_type->direct_type = direct_type; + dst_type->byte_size = direct_type ? direct_type->byte_size : 0; + dst_type->name = name; + } + + B32 do_unique_name_lookup = (((lf->props & CV_TypeProp_Scoped) != 0) && + ((lf->props & CV_TypeProp_HasUniqueName) != 0)); + if(do_unique_name_lookup) + { + U8 *unique_name_ptr = name_ptr + name.size + 1; + dst_type->link_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + } + }break; + } + } + + //- rjf: store finalized type to this itype's slot + itype_type_ptrs[itype] = dst_type; + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 2: kick off UDT build + // + U64 udt_task_size_itypes = 4096; + U64 udt_tasks_count = (tpi_leaf->itype_opl+(udt_task_size_itypes-1))/udt_task_size_itypes; + P2R_UDTConvertIn *udt_tasks_inputs = push_array(scratch.arena, P2R_UDTConvertIn, udt_tasks_count); + ASYNC_Task **udt_tasks = push_array(scratch.arena, ASYNC_Task *, udt_tasks_count); + if(in->flags & RC_Flag_UDTs) ProfScope("types pass 2: kick off UDT build") + { + for(U64 idx = 0; idx < udt_tasks_count; idx += 1) + { + udt_tasks_inputs[idx].tpi_leaf = tpi_leaf; + udt_tasks_inputs[idx].itype_first = idx*udt_task_size_itypes; + udt_tasks_inputs[idx].itype_opl = udt_tasks_inputs[idx].itype_first + udt_task_size_itypes; + udt_tasks_inputs[idx].itype_opl = ClampTop(udt_tasks_inputs[idx].itype_opl, tpi_leaf->itype_opl); + udt_tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; + udt_tasks[idx] = async_task_launch(scratch.arena, p2r_udt_convert_work, .input = &udt_tasks_inputs[idx]); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: join link name map building task + // + P2R_LinkNameMap *link_name_map = 0; + ProfScope("join link name map building task") + { + async_task_join(link_name_map_task); + link_name_map = &link_name_map__in_progress; + } + + ////////////////////////////////////////////////////////////// + //- rjf: join unit conversion & src file & line table tasks + // + RDIM_UnitChunkList all_units = {0}; + RDIM_SrcFileChunkList all_src_files = {0}; + RDIM_LineTableChunkList all_line_tables = {0}; + RDIM_LineTable **units_first_inline_site_line_tables = 0; + ProfScope("join unit conversion & src file tasks") + { + P2R_UnitConvertOut *out = async_task_join_struct(unit_convert_task, P2R_UnitConvertOut); + all_units = out->units; + all_src_files = out->src_files; + all_line_tables = out->line_tables; + units_first_inline_site_line_tables = out->units_first_inline_site_line_tables; + } + + ////////////////////////////////////////////////////////////// + //- rjf: produce symbols from all streams + // + RDIM_SymbolChunkList all_procedures = {0}; + RDIM_SymbolChunkList all_global_variables = {0}; + RDIM_SymbolChunkList all_thread_variables = {0}; + RDIM_ScopeChunkList all_scopes = {0}; + RDIM_InlineSiteChunkList all_inline_sites = {0}; + ProfScope("produce symbols from all streams") + { + //////////////////////////// + //- rjf: kick off all symbol conversion tasks + // + U64 global_stream_subdivision_tasks_count = sym ? (sym->sym_ranges.count+16383)/16384 : 0; + U64 global_stream_syms_per_task = sym ? sym->sym_ranges.count/global_stream_subdivision_tasks_count : 0; + U64 tasks_count = comp_unit_count + global_stream_subdivision_tasks_count; + P2R_SymbolStreamConvertIn *tasks_inputs = push_array(scratch.arena, P2R_SymbolStreamConvertIn, tasks_count); + ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, tasks_count); + ProfScope("kick off all symbol conversion tasks") + { + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + tasks_inputs[idx].arch = arch; + tasks_inputs[idx].coff_sections = coff_sections; + tasks_inputs[idx].tpi_hash = tpi_hash; + tasks_inputs[idx].tpi_leaf = tpi_leaf; + tasks_inputs[idx].ipi_leaf = ipi_leaf; + tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; + tasks_inputs[idx].link_name_map = link_name_map; + if(idx < global_stream_subdivision_tasks_count) + { + tasks_inputs[idx].sym = sym; + tasks_inputs[idx].sym_ranges_first= idx*global_stream_syms_per_task; + tasks_inputs[idx].sym_ranges_opl = tasks_inputs[idx].sym_ranges_first + global_stream_syms_per_task; + tasks_inputs[idx].sym_ranges_opl = ClampTop(tasks_inputs[idx].sym_ranges_opl, sym->sym_ranges.count); + } + else + { + tasks_inputs[idx].sym = sym_for_unit[idx-global_stream_subdivision_tasks_count]; + tasks_inputs[idx].sym_ranges_first= 0; + tasks_inputs[idx].sym_ranges_opl = sym_for_unit[idx-global_stream_subdivision_tasks_count]->sym_ranges.count; + tasks_inputs[idx].first_inline_site_line_table = units_first_inline_site_line_tables[idx-global_stream_subdivision_tasks_count]; + } + tasks[idx] = async_task_launch(scratch.arena, p2r_symbol_stream_convert_work, .input = &tasks_inputs[idx]); + } + } + + //////////////////////////// + //- rjf: join tasks, merge with top-level collections + // + ProfScope("join tasks, merge with top-level collections") + { + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + P2R_SymbolStreamConvertOut *out = async_task_join_struct(tasks[idx], P2R_SymbolStreamConvertOut); + rdim_symbol_chunk_list_concat_in_place(&all_procedures, &out->procedures); + rdim_symbol_chunk_list_concat_in_place(&all_global_variables, &out->global_variables); + rdim_symbol_chunk_list_concat_in_place(&all_thread_variables, &out->thread_variables); + rdim_scope_chunk_list_concat_in_place(&all_scopes, &out->scopes); + rdim_inline_site_chunk_list_concat_in_place(&all_inline_sites,&out->inline_sites); + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 5: join UDT build tasks + // + RDIM_UDTChunkList all_udts = {0}; + for(U64 idx = 0; idx < udt_tasks_count; idx += 1) + { + RDIM_UDTChunkList *udts = async_task_join_struct(udt_tasks[idx], RDIM_UDTChunkList); + rdim_udt_chunk_list_concat_in_place(&all_udts, udts); + } + + ////////////////////////////////////////////////////////////// + //- rjf: fill output + // + RDIM_BakeParams *out = push_array(arena, RDIM_BakeParams, 1); + { + out->top_level_info = top_level_info; + out->binary_sections = binary_sections; + out->units = all_units; + out->types = all_types; + out->udts = all_udts; + out->src_files = all_src_files; + out->line_tables = all_line_tables; + out->global_variables = all_global_variables; + out->thread_variables = all_thread_variables; + out->procedures = all_procedures; + out->scopes = all_scopes; + out->inline_sites = all_inline_sites; + } + + scratch_end(scratch); + return out; +} + +//////////////////////////////// + +internal B32 +p2r_has_symbol_ref(String8 msf_data, String8List symbol_list, MSF_RawStreamTable *st) +{ + Temp scratch = scratch_begin(0,0); + + B32 has_ref = 0; + + String8 dbi_data = msf_data_from_stream_number(scratch.arena, msf_data, st, PDB_FixedStream_Dbi); + PDB_DbiParsed *dbi = pdb_dbi_from_data(scratch.arena, dbi_data); + if(dbi) + { + String8 gsi_data = msf_data_from_stream_number(scratch.arena, msf_data, st, dbi->gsi_sn); + PDB_GsiParsed *gsi_parsed = pdb_gsi_from_data(scratch.arena, gsi_data); + if(gsi_parsed) + { + String8 symbol_data = msf_data_from_stream_number(scratch.arena, msf_data, st, dbi->sym_sn); + + for(String8Node *symbol_n = symbol_list.first; symbol_n != 0; symbol_n = symbol_n->next) + { + U64 symbol_off = pdb_gsi_symbol_from_string(gsi_parsed, symbol_data, symbol_n->string); + if(symbol_off < symbol_data.size) + { + has_ref = 1; + break; + } + } + } + } + + scratch_end(scratch); + return has_ref; +} + +internal B32 +p2r_has_file_ref(String8 msf_data, String8List file_list, MSF_RawStreamTable *st) +{ + Temp scratch = scratch_begin(0,0); + + B32 has_ref = 0; + + String8 info_data = msf_data_from_stream_number(scratch.arena, msf_data, st, PDB_FixedStream_Info); + PDB_Info *info = pdb_info_from_data(scratch.arena, info_data); + if(info) + { + PDB_NamedStreamTable *named_streams = pdb_named_stream_table_from_info(scratch.arena, info); + if(named_streams) + { + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_StringTable]; + String8 strtbl_data = msf_data_from_stream_number(scratch.arena, msf_data, st, strtbl_sn); + PDB_Strtbl *strtbl = pdb_strtbl_from_data(scratch.arena, strtbl_data); + if(strtbl) + { + for(String8Node *file_n = file_list.first; file_n != 0; file_n = file_n->next) + { + U32 off = pdb_strtbl_off_from_string(strtbl, file_n->string); + if(off != max_U32) + { + has_ref = 1; + break; + } + } + } + } + } + + scratch_end(scratch); + return has_ref; +} + +internal B32 +p2r_has_symbol_or_file_ref(String8 msf_data, String8List symbol_list, String8List file_list) +{ + Temp scratch = scratch_begin(0,0); + + B32 has_ref = 0; + + MSF_RawStreamTable *st = msf_raw_stream_table_from_data(scratch.arena, msf_data); + + if(!has_ref && symbol_list.node_count) + { + has_ref = p2r_has_symbol_ref(msf_data, symbol_list, st); + } + + if(!has_ref && file_list.node_count) + { + has_ref = p2r_has_file_ref(msf_data, file_list, st); + } + + scratch_end(scratch); + return has_ref; +} + diff --git a/src/radcon/radcon_pdb.h b/src/radcon/radcon_pdb.h new file mode 100644 index 00000000..7f7aaf72 --- /dev/null +++ b/src/radcon/radcon_pdb.h @@ -0,0 +1,238 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADCON_PDB_H +#define RADCON_PDB_H + +//////////////////////////////// +//~ rjf: Initial PDB Information Extraction & Conversion Preparation Task Types + +//- rjf: tpi hash parsing + +typedef struct P2R_TPIHashParseIn P2R_TPIHashParseIn; +struct P2R_TPIHashParseIn +{ + PDB_Strtbl *strtbl; + PDB_TpiParsed *tpi; + String8 hash_data; + String8 aux_data; +}; + +//- rjf: tpi leaves parsing + +typedef struct P2R_TPILeafParseIn P2R_TPILeafParseIn; +struct P2R_TPILeafParseIn +{ + String8 leaf_data; + CV_TypeId itype_first; +}; + +//- rjf: exe hashing + +typedef struct P2R_EXEHashIn P2R_EXEHashIn; +struct P2R_EXEHashIn +{ + String8 exe_data; +}; + +//- rjf: symbol stream parsing + +typedef struct P2R_SymbolStreamParseIn P2R_SymbolStreamParseIn; +struct P2R_SymbolStreamParseIn +{ + String8 data; +}; + +//- rjf: c13 line info stream parsing + +typedef struct P2R_C13StreamParseIn P2R_C13StreamParseIn; +struct P2R_C13StreamParseIn +{ + String8 data; + String8 strtbl; + COFF_SectionHeaderArray coff_sections; +}; + +//- rjf: comp unit parsing + +typedef struct P2R_CompUnitParseIn P2R_CompUnitParseIn; +struct P2R_CompUnitParseIn +{ + String8 data; +}; + +//- rjf: comp unit contribution table parsing + +typedef struct P2R_CompUnitContributionsParseIn P2R_CompUnitContributionsParseIn; +struct P2R_CompUnitContributionsParseIn +{ + String8 data; + COFF_SectionHeaderArray coff_sections; +}; + +//////////////////////////////// +//~ rjf: Conversion Data Structure & Task Types + +//- rjf: link name map (voff -> string) + +typedef struct P2R_LinkNameNode P2R_LinkNameNode; +struct P2R_LinkNameNode +{ + P2R_LinkNameNode *next; + U64 voff; + String8 name; +}; + +typedef struct P2R_LinkNameMap P2R_LinkNameMap; +struct P2R_LinkNameMap +{ + P2R_LinkNameNode **buckets; + U64 buckets_count; + U64 bucket_collision_count; + U64 link_name_count; +}; + +//- rjf: normalized file path -> source file map + +typedef struct P2R_SrcFileNode P2R_SrcFileNode; +struct P2R_SrcFileNode +{ + P2R_SrcFileNode *next; + RDIM_SrcFile *src_file; +}; + +typedef struct P2R_SrcFileMap P2R_SrcFileMap; +struct P2R_SrcFileMap +{ + P2R_SrcFileNode **slots; + U64 slots_count; +}; + +//- rjf: unit conversion tasks + +typedef struct P2R_UnitConvertIn P2R_UnitConvertIn; +struct P2R_UnitConvertIn +{ + PDB_Strtbl *pdb_strtbl; + COFF_SectionHeaderArray coff_sections; + PDB_CompUnitArray *comp_units; + PDB_CompUnitContributionArray *comp_unit_contributions; + CV_SymParsed **comp_unit_syms; + CV_C13Parsed **comp_unit_c13s; +}; + +typedef struct P2R_UnitConvertOut P2R_UnitConvertOut; +struct P2R_UnitConvertOut +{ + RDIM_UnitChunkList units; + RDIM_SrcFileChunkList src_files; + RDIM_LineTableChunkList line_tables; + RDIM_LineTable **units_first_inline_site_line_tables; +}; + +//- rjf: link name map building tasks + +typedef struct P2R_LinkNameMapBuildIn P2R_LinkNameMapBuildIn; +struct P2R_LinkNameMapBuildIn +{ + CV_SymParsed *sym; + COFF_SectionHeaderArray coff_sections; + P2R_LinkNameMap *link_name_map; +}; + +//- rjf: udt conversion + +typedef struct P2R_UDTConvertIn P2R_UDTConvertIn; +struct P2R_UDTConvertIn +{ + CV_LeafParsed *tpi_leaf; + CV_TypeId itype_first; + CV_TypeId itype_opl; + RDIM_Type **itype_type_ptrs; +}; + +//- rjf: symbol stream conversion + +typedef struct P2R_SymbolStreamConvertIn P2R_SymbolStreamConvertIn; +struct P2R_SymbolStreamConvertIn +{ + RDI_Arch arch; + COFF_SectionHeaderArray coff_sections; + PDB_TpiHashParsed *tpi_hash; + CV_LeafParsed *tpi_leaf; + CV_LeafParsed *ipi_leaf; + CV_SymParsed *sym; + U64 sym_ranges_first; + U64 sym_ranges_opl; + RDIM_Type **itype_type_ptrs; + P2R_LinkNameMap *link_name_map; + RDIM_LineTable *first_inline_site_line_table; +}; + +typedef struct P2R_SymbolStreamConvertOut P2R_SymbolStreamConvertOut; +struct P2R_SymbolStreamConvertOut +{ + RDIM_SymbolChunkList procedures; + RDIM_SymbolChunkList global_variables; + RDIM_SymbolChunkList thread_variables; + RDIM_ScopeChunkList scopes; + RDIM_InlineSiteChunkList inline_sites; +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 p2r_end_of_cplusplus_container_name(String8 str); +internal U64 p2r_hash_from_voff(U64 voff); + +//////////////////////////////// +//~ rjf: Location Info Building Helpers + +internal RDIM_Location *p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); +internal RDI_RegCode p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg); +internal void p2r_location_over_lvar_addr_range(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Location *location, CV_LvarAddrRange *range, COFF_SectionHeader *section, CV_LvarAddrGap *gaps, U64 gap_count); + +//////////////////////////////// +//~ rjf: Initial Parsing & Preparation Pass Tasks + +ASYNC_WORK_DEF(p2r_exe_hash_work); +ASYNC_WORK_DEF(p2r_tpi_hash_parse_work); +ASYNC_WORK_DEF(p2r_tpi_leaf_work); +ASYNC_WORK_DEF(p2r_symbol_stream_parse_work); +ASYNC_WORK_DEF(p2r_c13_stream_parse_work); +ASYNC_WORK_DEF(p2r_comp_unit_parse_work); +ASYNC_WORK_DEF(p2r_comp_unit_contributions_parse_work); + +//////////////////////////////// +//~ rjf: Unit Conversion Tasks + +ASYNC_WORK_DEF(p2r_units_convert_work); + +//////////////////////////////// +//~ rjf: Link Name Map Building Tasks + +ASYNC_WORK_DEF(p2r_link_name_map_build_work); + +//////////////////////////////// +//~ rjf: UDT Conversion Tasks + +ASYNC_WORK_DEF(p2r_udt_convert_work); + +//////////////////////////////// +//~ rjf: Symbol Stream Conversion Tasks + +ASYNC_WORK_DEF(p2r_symbol_stream_convert_work); + +//////////////////////////////// +//~ rjf: Top-Level Conversion Entry Point + +internal RDIM_BakeParams *p2r_convert(Arena *arena, RDIM_LocalState *local_state, RC_Context *in); + +//////////////////////////////// + +internal B32 p2r_has_symbol_ref(String8 msf_data, String8List symbol_list, MSF_RawStreamTable *st); +internal B32 p2r_has_file_ref(String8 msf_data, String8List file_list, MSF_RawStreamTable *st); +internal B32 p2r_has_symbol_or_file_ref(String8 msf_data, String8List symbol_list, String8List file_list); + +#endif // RADCON_PDB_H + diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 7594e916..89359b92 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -4,194 +4,438 @@ //- GENERATED CODE C_LINKAGE_BEGIN -String8 rd_cfg_src_string_table[4] = +String8 rd_tab_fast_path_view_name_table[24] = { -str8_lit_comp("user"), -str8_lit_comp("project"), -str8_lit_comp("command_line"), -str8_lit_comp("transient"), -}; - -RD_CmdKind rd_cfg_src_load_cmd_kind_table[4] = -{ -RD_CmdKind_OpenUser, -RD_CmdKind_OpenProject, -RD_CmdKind_Null, -RD_CmdKind_Null, -}; - -RD_CmdKind rd_cfg_src_write_cmd_kind_table[4] = -{ -RD_CmdKind_WriteUserData, -RD_CmdKind_WriteProjectData, -RD_CmdKind_Null, -RD_CmdKind_Null, -}; - -RD_CmdKind rd_cfg_src_apply_cmd_kind_table[4] = -{ -RD_CmdKind_ApplyUserData, -RD_CmdKind_ApplyProjectData, -RD_CmdKind_Null, -RD_CmdKind_Null, -}; - -String8 d_entity_kind_display_string_table[27] = -{ -str8_lit_comp("Nil"), -str8_lit_comp("Root"), -str8_lit_comp("Auto View Rule"), -str8_lit_comp("File Path Map"), -str8_lit_comp("Watch Pin"), -str8_lit_comp("Watch"), -str8_lit_comp("View Rule"), -str8_lit_comp("Breakpoint"), -str8_lit_comp("Condition"), -str8_lit_comp("Location"), -str8_lit_comp("Target"), -str8_lit_comp("Executable"), -str8_lit_comp("Arguments"), -str8_lit_comp("Working Directory"), -str8_lit_comp("Entry Point"), -str8_lit_comp("Standard Output Path"), -str8_lit_comp("Standard Error Path"), -str8_lit_comp("Standard Input Path"), -str8_lit_comp("Window"), -str8_lit_comp("Panel"), -str8_lit_comp("View"), -str8_lit_comp("Recent Project"), -str8_lit_comp("Recent File"), -str8_lit_comp("Source"), -str8_lit_comp("Destination"), -str8_lit_comp("Conversion Task"), -str8_lit_comp("Conversion Failure"), -}; - -String8 d_entity_kind_name_lower_table[27] = -{ -str8_lit_comp("nil"), -str8_lit_comp("root"), -str8_lit_comp("auto_view_rule"), -str8_lit_comp("file_path_map"), -str8_lit_comp("watch_pin"), str8_lit_comp("watch"), -str8_lit_comp("view_rule"), -str8_lit_comp("breakpoint"), -str8_lit_comp("condition"), -str8_lit_comp("location"), -str8_lit_comp("target"), -str8_lit_comp("executable"), -str8_lit_comp("arguments"), -str8_lit_comp("working_directory"), -str8_lit_comp("entry_point"), -str8_lit_comp("stdout_path"), -str8_lit_comp("stderr_path"), -str8_lit_comp("stdin_path"), -str8_lit_comp("window"), -str8_lit_comp("panel"), -str8_lit_comp("view"), -str8_lit_comp("recent_project"), -str8_lit_comp("recent_file"), -str8_lit_comp("source"), -str8_lit_comp("dest"), -str8_lit_comp("conversion_task"), -str8_lit_comp("conversion_fail"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("watch"), +str8_lit_comp("text"), +str8_lit_comp("text"), +str8_lit_comp("disasm"), +str8_lit_comp("memory"), +str8_lit_comp("bitmap"), +str8_lit_comp("color"), +str8_lit_comp("geo3d"), }; -String8 d_entity_kind_name_lower_plural_table[27] = +String8 rd_tab_fast_path_query_name_table[24] = { -str8_lit_comp("nils"), -str8_lit_comp("roots"), -str8_lit_comp("auto_view_rules"), -str8_lit_comp("file_path_maps"), -str8_lit_comp("watch_pins"), -str8_lit_comp("watches"), -str8_lit_comp("view_rules"), -str8_lit_comp("breakpoints"), -str8_lit_comp("conditions"), -str8_lit_comp("locations"), -str8_lit_comp("targets"), -str8_lit_comp("executables"), -str8_lit_comp("argumentses"), -str8_lit_comp("working_directories"), -str8_lit_comp("entry_points"), -str8_lit_comp("stdout_paths"), -str8_lit_comp("stderr_paths"), -str8_lit_comp("stdin_paths"), -str8_lit_comp("windows"), -str8_lit_comp("panels"), -str8_lit_comp("views"), -str8_lit_comp("recent_projects"), -str8_lit_comp("recent_files"), -str8_lit_comp("sources"), -str8_lit_comp("dests"), -str8_lit_comp("conversion_tasks"), -str8_lit_comp("conversion_fails"), +str8_lit_comp(""), +str8_lit_comp("query:locals"), +str8_lit_comp("query:registers"), +str8_lit_comp("query:globals"), +str8_lit_comp("query:thread_locals"), +str8_lit_comp("query:types"), +str8_lit_comp("query:procedures"), +str8_lit_comp("query:call_stack"), +str8_lit_comp("query:targets"), +str8_lit_comp("query:breakpoints"), +str8_lit_comp("query:watch_pins"), +str8_lit_comp("query:threads"), +str8_lit_comp("query:processes"), +str8_lit_comp("query:machines"), +str8_lit_comp("query:modules"), +str8_lit_comp("query:file_path_maps"), +str8_lit_comp("query:type_views"), +str8_lit_comp("query:output"), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), }; -String8 d_entity_kind_name_label_table[27] = +RD_VocabInfo rd_vocab_info_table[343] = { -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Expression"), -str8_lit_comp("Expression"), -str8_lit_comp("Expression"), -str8_lit_comp("Label"), -str8_lit_comp("Expression"), -str8_lit_comp("Location"), -str8_lit_comp("Label"), -str8_lit_comp("Executable"), -str8_lit_comp("Arguments"), -str8_lit_comp("Path"), -str8_lit_comp("Symbol Name"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), +{str8_lit_comp("type_view"), str8_lit_comp("type_views"), str8_lit_comp("Type View"), str8_lit_comp("Type Views"), RD_IconKind_Binoculars}, +{str8_lit_comp("file_path_map"), str8_lit_comp("file_path_maps"), str8_lit_comp("File Path Map"), str8_lit_comp("File Path Maps"), RD_IconKind_FileOutline}, +{str8_lit_comp("watch_pin"), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pin"), str8_lit_comp("Watch Pins"), RD_IconKind_Pin}, +{str8_lit_comp("watch"), str8_lit_comp("watches"), str8_lit_comp("Watch"), str8_lit_comp("Watches"), RD_IconKind_Binoculars}, +{str8_lit_comp("view"), str8_lit_comp("views"), str8_lit_comp("View"), str8_lit_comp("Views"), RD_IconKind_Binoculars}, +{str8_lit_comp("breakpoint"), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled}, +{str8_lit_comp("condition"), str8_lit_comp("conditions"), str8_lit_comp("Condition"), str8_lit_comp("Conditions"), RD_IconKind_Null}, +{str8_lit_comp("location"), str8_lit_comp("locations"), str8_lit_comp("Location"), str8_lit_comp("Locations"), RD_IconKind_Null}, +{str8_lit_comp("source_location"), str8_lit_comp("source_locations"), str8_lit_comp("Source Location"), str8_lit_comp("Source Locations"), RD_IconKind_Null}, +{str8_lit_comp("address_location"), str8_lit_comp("address_locations"), str8_lit_comp("Address Location"), str8_lit_comp("Address Locations"), RD_IconKind_Null}, +{str8_lit_comp("target"), str8_lit_comp("targets"), str8_lit_comp("Target"), str8_lit_comp("Targets"), RD_IconKind_Target}, +{str8_lit_comp("color"), str8_lit_comp("colors"), str8_lit_comp("Color"), str8_lit_comp("Colors"), RD_IconKind_Palette}, +{str8_lit_comp("theme_color"), str8_lit_comp("theme_colors"), str8_lit_comp("Theme Color"), str8_lit_comp("Theme Colors"), RD_IconKind_Palette}, +{str8_lit_comp("executable"), str8_lit_comp("executables"), str8_lit_comp("Executable"), str8_lit_comp("Executables"), RD_IconKind_Module}, +{str8_lit_comp("arguments"), str8_lit_comp("arguments"), str8_lit_comp("Arguments"), str8_lit_comp("Arguments"), RD_IconKind_Null}, +{str8_lit_comp("exe"), str8_lit_comp("exes"), str8_lit_comp("Executable"), str8_lit_comp("Executables"), RD_IconKind_Module}, +{str8_lit_comp("dbg"), str8_lit_comp("dbgs"), str8_lit_comp("Debug Info Path"), str8_lit_comp("Debug Info Paths"), RD_IconKind_Module}, +{str8_lit_comp("vaddr_range"), str8_lit_comp("vaddr_ranges"), str8_lit_comp("Virtual Address Range"), str8_lit_comp("Virtual Address Ranges"), RD_IconKind_Null}, +{str8_lit_comp("min"), str8_lit_comp("mins"), str8_lit_comp("Minimum"), str8_lit_comp("Minimums"), RD_IconKind_Null}, +{str8_lit_comp("max"), str8_lit_comp("maxs"), str8_lit_comp("Maximum"), str8_lit_comp("Maximums"), RD_IconKind_Null}, +{str8_lit_comp("working_directory"), str8_lit_comp("working_directories"), str8_lit_comp("Working Directory"), str8_lit_comp("Working Directories"), RD_IconKind_FolderClosedFilled}, +{str8_lit_comp("entry_point"), str8_lit_comp("entry_points"), str8_lit_comp("Entry Point"), str8_lit_comp("Entry Points"), RD_IconKind_Null}, +{str8_lit_comp("stdout_path"), str8_lit_comp("stdout_paths"), str8_lit_comp("Standard Output Path"), str8_lit_comp("Standard Output Paths"), RD_IconKind_Null}, +{str8_lit_comp("stderr_path"), str8_lit_comp("stderr_paths"), str8_lit_comp("Standard Error Path"), str8_lit_comp("Standard Error Paths"), RD_IconKind_Null}, +{str8_lit_comp("stdin_path"), str8_lit_comp("stdin_paths"), str8_lit_comp("Standard Input Path"), str8_lit_comp("Standard Input Paths"), RD_IconKind_Null}, +{str8_lit_comp("window"), str8_lit_comp("windows"), str8_lit_comp("Window"), str8_lit_comp("Windows"), RD_IconKind_Window}, +{str8_lit_comp("panel"), str8_lit_comp("panels"), str8_lit_comp("Panel"), str8_lit_comp("Panels"), RD_IconKind_Null}, +{str8_lit_comp("tab"), str8_lit_comp("tabs"), str8_lit_comp("Tab"), str8_lit_comp("Tabs"), RD_IconKind_Null}, +{str8_lit_comp("recent_project"), str8_lit_comp("recent_projects"), str8_lit_comp("Recent Project"), str8_lit_comp("Recent Projects"), RD_IconKind_Briefcase}, +{str8_lit_comp("recent_file"), str8_lit_comp("recent_files"), str8_lit_comp("Recent File"), str8_lit_comp("Recent Files"), RD_IconKind_FileOutline}, +{str8_lit_comp("src"), str8_lit_comp("srcs"), str8_lit_comp("Source"), str8_lit_comp("Sources"), RD_IconKind_Null}, +{str8_lit_comp("dst"), str8_lit_comp("dsts"), str8_lit_comp("Destination"), str8_lit_comp("Destinations"), RD_IconKind_Null}, +{str8_lit_comp("source"), str8_lit_comp("sources"), str8_lit_comp("Source"), str8_lit_comp("Sources"), RD_IconKind_Null}, +{str8_lit_comp("dest"), str8_lit_comp("dests"), str8_lit_comp("Destination"), str8_lit_comp("Destinations"), RD_IconKind_Null}, +{str8_lit_comp("conversion_task"), str8_lit_comp("conversion_tasks"), str8_lit_comp("Conversion Task"), str8_lit_comp("Conversion Tasks"), RD_IconKind_Null}, +{str8_lit_comp("conversion_fail"), str8_lit_comp("conversion_fails"), str8_lit_comp("Conversion Fail"), str8_lit_comp("Conversion Fails"), RD_IconKind_Null}, +{str8_lit_comp("lang"), str8_lit_comp("langs"), str8_lit_comp("Language"), str8_lit_comp("Languages"), RD_IconKind_Null}, +{str8_lit_comp("arch"), str8_lit_comp("archs"), str8_lit_comp("Architecture"), str8_lit_comp("Architectures"), RD_IconKind_Null}, +{str8_lit_comp("expr"), str8_lit_comp("exprs"), str8_lit_comp("Expression"), str8_lit_comp("Expressions"), RD_IconKind_Null}, +{str8_lit_comp("expression"), str8_lit_comp("expressions"), str8_lit_comp("Expression"), str8_lit_comp("Expressions"), RD_IconKind_Null}, +{str8_lit_comp("size"), str8_lit_comp("sizes"), str8_lit_comp("Size"), str8_lit_comp("Sizes"), RD_IconKind_Null}, +{str8_lit_comp("count"), str8_lit_comp("counts"), str8_lit_comp("Count"), str8_lit_comp("Counts"), RD_IconKind_Null}, +{str8_lit_comp("bool"), str8_lit_comp("bools"), str8_lit_comp("Boolean"), str8_lit_comp("Booleans"), RD_IconKind_Null}, +{str8_lit_comp("w"), str8_lit_comp("ws"), str8_lit_comp("Width"), str8_lit_comp("Widths"), RD_IconKind_Null}, +{str8_lit_comp("h"), str8_lit_comp("hs"), str8_lit_comp("Height"), str8_lit_comp("Heights"), RD_IconKind_Null}, +{str8_lit_comp("fmt"), str8_lit_comp("fmts"), str8_lit_comp("Format"), str8_lit_comp("Formats"), RD_IconKind_Null}, +{str8_lit_comp("addresses"), str8_lit_comp("addresses"), str8_lit_comp("Addresses"), str8_lit_comp("Addresses"), RD_IconKind_Null}, +{str8_lit_comp("code_bytes"), str8_lit_comp("code_bytes"), str8_lit_comp("Code Bytes"), str8_lit_comp("Code Bytes"), RD_IconKind_Null}, +{str8_lit_comp("vtx"), str8_lit_comp("vtxs"), str8_lit_comp("Vertex Buffer"), str8_lit_comp("Vertex Buffers"), RD_IconKind_Null}, +{str8_lit_comp("vtx_size"), str8_lit_comp("vtx_sizes"), str8_lit_comp("Vertex Buffer Size"), str8_lit_comp("Vertex Buffer Sizes"), RD_IconKind_Null}, +{str8_lit_comp("label"), str8_lit_comp("labels"), str8_lit_comp("Label"), str8_lit_comp("Labels"), RD_IconKind_Null}, +{str8_lit_comp("thread"), str8_lit_comp("threads"), str8_lit_comp("Thread"), str8_lit_comp("Threads"), RD_IconKind_Thread}, +{str8_lit_comp("threads"), str8_lit_comp(""), str8_lit_comp("Threads"), str8_lit_comp(""), RD_IconKind_Threads}, +{str8_lit_comp("process"), str8_lit_comp("processes"), str8_lit_comp("Process"), str8_lit_comp("Processes"), RD_IconKind_Scheduler}, +{str8_lit_comp("processes"), str8_lit_comp(""), str8_lit_comp("Processes"), str8_lit_comp(""), RD_IconKind_Scheduler}, +{str8_lit_comp("machine"), str8_lit_comp("machines"), str8_lit_comp("Machine"), str8_lit_comp("Machines"), RD_IconKind_Machine}, +{str8_lit_comp("module"), str8_lit_comp("modules"), str8_lit_comp("Module"), str8_lit_comp("Modules"), RD_IconKind_Module}, +{str8_lit_comp("getting_started"), str8_lit_comp(""), str8_lit_comp("Getting Started"), str8_lit_comp(""), RD_IconKind_QuestionMark}, +{str8_lit_comp("disasm"), str8_lit_comp(""), str8_lit_comp("Disassembly"), str8_lit_comp(""), RD_IconKind_Glasses}, +{str8_lit_comp("text"), str8_lit_comp(""), str8_lit_comp("Text"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("type"), str8_lit_comp("types"), str8_lit_comp("Type"), str8_lit_comp("Types"), RD_IconKind_Null}, +{str8_lit_comp("procedure"), str8_lit_comp("procedures"), str8_lit_comp("Procedure"), str8_lit_comp("Procedures"), RD_IconKind_Null}, +{str8_lit_comp("global_variable"), str8_lit_comp("global_variables"), str8_lit_comp("Global Variable"), str8_lit_comp("Global Variables"), RD_IconKind_Null}, +{str8_lit_comp("global"), str8_lit_comp("globals"), str8_lit_comp("Global"), str8_lit_comp("Globals"), RD_IconKind_Null}, +{str8_lit_comp("thread_variable"), str8_lit_comp("thread_variables"), str8_lit_comp("Thread Variable"), str8_lit_comp("Thread Variables"), RD_IconKind_Null}, +{str8_lit_comp("thread_local"), str8_lit_comp("thread_locals"), str8_lit_comp("Thread Local"), str8_lit_comp("Thread Locals"), RD_IconKind_Null}, +{str8_lit_comp("call_stack"), str8_lit_comp("call_stacks"), str8_lit_comp("Call Stack"), str8_lit_comp("Call Stacks"), RD_IconKind_Thread}, +{str8_lit_comp("output"), str8_lit_comp("outputs"), str8_lit_comp("Output"), str8_lit_comp("Outputs"), RD_IconKind_List}, +{str8_lit_comp("scheduler"), str8_lit_comp("schedulers"), str8_lit_comp("Scheduler"), str8_lit_comp("Schedulers"), RD_IconKind_Scheduler}, +{str8_lit_comp("register"), str8_lit_comp("registers"), str8_lit_comp("Register"), str8_lit_comp("Registers"), RD_IconKind_Null}, +{str8_lit_comp("local"), str8_lit_comp("locals"), str8_lit_comp("Local"), str8_lit_comp("Locals"), RD_IconKind_Null}, +{str8_lit_comp("memory"), str8_lit_comp("memories"), str8_lit_comp("Memory"), str8_lit_comp("Memories"), RD_IconKind_Grid}, +{str8_lit_comp("hit_count"), str8_lit_comp("hit_counts"), str8_lit_comp("Hit Count"), str8_lit_comp("Hit Counts"), RD_IconKind_Null}, +{str8_lit_comp("enabled"), str8_lit_comp(""), str8_lit_comp("Enabled"), str8_lit_comp("Enabled"), RD_IconKind_Null}, +{str8_lit_comp("disabled"), str8_lit_comp(""), str8_lit_comp("Disabled"), str8_lit_comp("Disabled"), RD_IconKind_Null}, +{str8_lit_comp("debug_subprocesses"), str8_lit_comp(""), str8_lit_comp("Debug Subprocesses"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("environment"), str8_lit_comp("environments"), str8_lit_comp("Environment"), str8_lit_comp("Environments"), RD_IconKind_Null}, +{str8_lit_comp("frozen"), str8_lit_comp(""), str8_lit_comp("Frozen"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("id"), str8_lit_comp("ids"), str8_lit_comp("ID"), str8_lit_comp("IDs"), RD_IconKind_Null}, +{str8_lit_comp("last_modified_time"), str8_lit_comp("last_modified_times"), str8_lit_comp("Last Modified Time"), str8_lit_comp("Last Modified Times"), RD_IconKind_Null}, +{str8_lit_comp("creation_time"), str8_lit_comp("creation_times"), str8_lit_comp("Creation Time"), str8_lit_comp("Creation Times"), RD_IconKind_Null}, +{str8_lit_comp("data"), str8_lit_comp("datas"), str8_lit_comp("Data"), str8_lit_comp("Datas"), RD_IconKind_Null}, +{str8_lit_comp("unattached_processes"), str8_lit_comp(""), str8_lit_comp("Unattached Processes"), str8_lit_comp(""), RD_IconKind_Scheduler}, +{str8_lit_comp("user"), str8_lit_comp("users"), str8_lit_comp("User"), str8_lit_comp("Users"), RD_IconKind_Person}, +{str8_lit_comp("project"), str8_lit_comp("projects"), str8_lit_comp("Project"), str8_lit_comp("Projects"), RD_IconKind_Briefcase}, +{str8_lit_comp("recent_project"), str8_lit_comp("recent_projects"), str8_lit_comp("Recent Project"), str8_lit_comp("Recent Projects"), RD_IconKind_Briefcase}, +{str8_lit_comp("recent_file"), str8_lit_comp("recent_files"), str8_lit_comp("Recent File"), str8_lit_comp("Recent Files"), RD_IconKind_FileOutline}, +{str8_lit_comp("show_addresses"), str8_lit_comp(""), str8_lit_comp("Show Addresses"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("show_code_bytes"), str8_lit_comp(""), str8_lit_comp("Show Code Bytes"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("show_source_lines"), str8_lit_comp(""), str8_lit_comp("Show Source Lines"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("show_symbol_names"), str8_lit_comp(""), str8_lit_comp("Show Symbol Names"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("show_line_numbers"), str8_lit_comp(""), str8_lit_comp("Show Line Numbers"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("syntax"), str8_lit_comp("syntaxes"), str8_lit_comp("Syntax"), str8_lit_comp("Syntaxes"), RD_IconKind_Null}, +{str8_lit_comp("num_columns"), str8_lit_comp(""), str8_lit_comp("Number of Columns"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("bytes_per_cell"), str8_lit_comp(""), str8_lit_comp("Bytes Per Cell"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("bitmap"), str8_lit_comp("bitmaps"), str8_lit_comp("Bitmap"), str8_lit_comp("Bitmaps"), RD_IconKind_Bitmap}, +{str8_lit_comp("geo3d"), str8_lit_comp(""), str8_lit_comp("Geometry (3D)"), str8_lit_comp(""), RD_IconKind_Cube}, +{str8_lit_comp("address_range_size"), str8_lit_comp("address_range_sizes"), str8_lit_comp("Address Range Size"), str8_lit_comp("Address Range Sizes"), RD_IconKind_Null}, +{str8_lit_comp("break_on_read"), str8_lit_comp(""), str8_lit_comp("Break On Read"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("break_on_write"), str8_lit_comp(""), str8_lit_comp("Break On Write"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("break_on_execute"), str8_lit_comp(""), str8_lit_comp("Break On Execution"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("yaw"), str8_lit_comp(""), str8_lit_comp("Yaw"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("pitch"), str8_lit_comp(""), str8_lit_comp("Pitch"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("zoom"), str8_lit_comp(""), str8_lit_comp("Zoom"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("font_size"), str8_lit_comp(""), str8_lit_comp("Font Size"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("row_height"), str8_lit_comp(""), str8_lit_comp("Row Height"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("tab_height"), str8_lit_comp(""), str8_lit_comp("Tab Height"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("rgba"), str8_lit_comp(""), str8_lit_comp("RGBA"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("launch_and_run"), str8_lit_comp(""), str8_lit_comp("Launch and Run"), str8_lit_comp(""), RD_IconKind_Play}, +{str8_lit_comp("launch_and_step_into"), str8_lit_comp(""), str8_lit_comp("Launch and Step Into"), str8_lit_comp(""), RD_IconKind_PlayStepForward}, +{str8_lit_comp("kill"), str8_lit_comp(""), str8_lit_comp("Kill"), str8_lit_comp(""), RD_IconKind_X}, +{str8_lit_comp("kill_all"), str8_lit_comp(""), str8_lit_comp("Kill All"), str8_lit_comp(""), RD_IconKind_Stop}, +{str8_lit_comp("detach"), str8_lit_comp(""), str8_lit_comp("Detach"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("continue"), str8_lit_comp(""), str8_lit_comp("Continue"), str8_lit_comp(""), RD_IconKind_Play}, +{str8_lit_comp("step_into_inst"), str8_lit_comp(""), str8_lit_comp("Step Into (Assembly)"), str8_lit_comp(""), RD_IconKind_StepInto}, +{str8_lit_comp("step_over_inst"), str8_lit_comp(""), str8_lit_comp("Step Over (Assembly)"), str8_lit_comp(""), RD_IconKind_StepOver}, +{str8_lit_comp("step_into_line"), str8_lit_comp(""), str8_lit_comp("Step Into (Line)"), str8_lit_comp(""), RD_IconKind_StepInto}, +{str8_lit_comp("step_over_line"), str8_lit_comp(""), str8_lit_comp("Step Over (Line)"), str8_lit_comp(""), RD_IconKind_StepOver}, +{str8_lit_comp("step_out"), str8_lit_comp(""), str8_lit_comp("Step Out"), str8_lit_comp(""), RD_IconKind_StepOut}, +{str8_lit_comp("halt"), str8_lit_comp(""), str8_lit_comp("Halt"), str8_lit_comp(""), RD_IconKind_Pause}, +{str8_lit_comp("soft_halt_refresh"), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), str8_lit_comp(""), RD_IconKind_Refresh}, +{str8_lit_comp("set_thread_ip"), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("run_to_line"), str8_lit_comp(""), str8_lit_comp("Run To Line"), str8_lit_comp(""), RD_IconKind_Play}, +{str8_lit_comp("run"), str8_lit_comp(""), str8_lit_comp("Run"), str8_lit_comp(""), RD_IconKind_Play}, +{str8_lit_comp("restart"), str8_lit_comp(""), str8_lit_comp("Restart"), str8_lit_comp(""), RD_IconKind_Redo}, +{str8_lit_comp("step_into"), str8_lit_comp(""), str8_lit_comp("Step Into"), str8_lit_comp(""), RD_IconKind_StepInto}, +{str8_lit_comp("step_over"), str8_lit_comp(""), str8_lit_comp("Step Over"), str8_lit_comp(""), RD_IconKind_StepOver}, +{str8_lit_comp("freeze_thread"), str8_lit_comp(""), str8_lit_comp("Freeze Thread"), str8_lit_comp(""), RD_IconKind_Locked}, +{str8_lit_comp("thaw_thread"), str8_lit_comp(""), str8_lit_comp("Thaw Thread"), str8_lit_comp(""), RD_IconKind_Unlocked}, +{str8_lit_comp("freeze_process"), str8_lit_comp(""), str8_lit_comp("Freeze Process"), str8_lit_comp(""), RD_IconKind_Locked}, +{str8_lit_comp("thaw_process"), str8_lit_comp(""), str8_lit_comp("Thaw Process"), str8_lit_comp(""), RD_IconKind_Unlocked}, +{str8_lit_comp("freeze_machine"), str8_lit_comp(""), str8_lit_comp("Freeze Machine"), str8_lit_comp(""), RD_IconKind_Locked}, +{str8_lit_comp("thaw_machine"), str8_lit_comp(""), str8_lit_comp("Thaw Machine"), str8_lit_comp(""), RD_IconKind_Unlocked}, +{str8_lit_comp("freeze_local_machine"), str8_lit_comp(""), str8_lit_comp("Freeze Local Machine"), str8_lit_comp(""), RD_IconKind_Machine}, +{str8_lit_comp("thaw_local_machine"), str8_lit_comp(""), str8_lit_comp("Thaw Local Machine"), str8_lit_comp(""), RD_IconKind_Machine}, +{str8_lit_comp("freeze_entity"), str8_lit_comp(""), str8_lit_comp("Freeze Entity"), str8_lit_comp(""), RD_IconKind_Unlocked}, +{str8_lit_comp("thaw_entity"), str8_lit_comp(""), str8_lit_comp("Thaw Entity"), str8_lit_comp(""), RD_IconKind_Locked}, +{str8_lit_comp("set_entity_color"), str8_lit_comp(""), str8_lit_comp("Set Entity Color"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("set_entity_name"), str8_lit_comp(""), str8_lit_comp("Set Entity Name"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("attach"), str8_lit_comp(""), str8_lit_comp("Attach"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("exit"), str8_lit_comp(""), str8_lit_comp("Exit"), str8_lit_comp(""), RD_IconKind_X}, +{str8_lit_comp("open_palette"), str8_lit_comp(""), str8_lit_comp("Open Palette"), str8_lit_comp(""), RD_IconKind_List}, +{str8_lit_comp("run_command"), str8_lit_comp(""), str8_lit_comp("Run Command"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("os_event"), str8_lit_comp(""), str8_lit_comp("OS Event"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("select_thread"), str8_lit_comp(""), str8_lit_comp("Select Thread"), str8_lit_comp(""), RD_IconKind_Thread}, +{str8_lit_comp("select_unwind"), str8_lit_comp(""), str8_lit_comp("Select Unwind"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("up_one_frame"), str8_lit_comp(""), str8_lit_comp("Up One Frame"), str8_lit_comp(""), RD_IconKind_UpArrow}, +{str8_lit_comp("down_one_frame"), str8_lit_comp(""), str8_lit_comp("Down One Frame"), str8_lit_comp(""), RD_IconKind_DownArrow}, +{str8_lit_comp("select_entity"), str8_lit_comp(""), str8_lit_comp("Select"), str8_lit_comp(""), RD_IconKind_RadioHollow}, +{str8_lit_comp("deselect_entity"), str8_lit_comp(""), str8_lit_comp("Deselect"), str8_lit_comp(""), RD_IconKind_RadioFilled}, +{str8_lit_comp("inc_window_font_size"), str8_lit_comp(""), str8_lit_comp("Increase Window Font Size"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("dec_window_font_size"), str8_lit_comp(""), str8_lit_comp("Decrease Window Font Size"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("inc_view_font_size"), str8_lit_comp(""), str8_lit_comp("Increase View Font Size"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("dec_view_font_size"), str8_lit_comp(""), str8_lit_comp("Decrease View Font Size"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("open_window"), str8_lit_comp(""), str8_lit_comp("Open New Window"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("window_settings"), str8_lit_comp(""), str8_lit_comp("Window Settings"), str8_lit_comp(""), RD_IconKind_Gear}, +{str8_lit_comp("close_window"), str8_lit_comp(""), str8_lit_comp("Close Window"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("toggle_fullscreen"), str8_lit_comp(""), str8_lit_comp("Toggle Fullscreen"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("bring_to_front"), str8_lit_comp(""), str8_lit_comp("Bring To Front"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("popup_accept"), str8_lit_comp(""), str8_lit_comp("Popup Accept"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("popup_cancel"), str8_lit_comp(""), str8_lit_comp("Popup Cancel"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("reset_to_default_bindings"), str8_lit_comp(""), str8_lit_comp("Reset To Default Bindings"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("reset_to_default_panels"), str8_lit_comp(""), str8_lit_comp("Reset To Default Panel Layout"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("reset_to_compact_panels"), str8_lit_comp(""), str8_lit_comp("Reset To Compact Panel Layout"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("reset_to_simple_panels"), str8_lit_comp(""), str8_lit_comp("Reset To Simple Panel Layout"), str8_lit_comp(""), RD_IconKind_Window}, +{str8_lit_comp("new_panel_left"), str8_lit_comp(""), str8_lit_comp("Split Panel Left"), str8_lit_comp(""), RD_IconKind_XSplit}, +{str8_lit_comp("new_panel_up"), str8_lit_comp(""), str8_lit_comp("Split Panel Up"), str8_lit_comp(""), RD_IconKind_YSplit}, +{str8_lit_comp("new_panel_right"), str8_lit_comp(""), str8_lit_comp("Split Panel Right"), str8_lit_comp(""), RD_IconKind_XSplit}, +{str8_lit_comp("new_panel_down"), str8_lit_comp(""), str8_lit_comp("Split Panel Down"), str8_lit_comp(""), RD_IconKind_YSplit}, +{str8_lit_comp("split_panel"), str8_lit_comp(""), str8_lit_comp("Split Panel"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("rotate_panel_columns"), str8_lit_comp(""), str8_lit_comp("Rotate Panel Columns"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("next_panel"), str8_lit_comp(""), str8_lit_comp("Focus Next Panel"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("prev_panel"), str8_lit_comp(""), str8_lit_comp("Focus Previous Panel"), str8_lit_comp(""), RD_IconKind_LeftArrow}, +{str8_lit_comp("focus_panel"), str8_lit_comp(""), str8_lit_comp("Focus Panel"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("focus_panel_right"), str8_lit_comp(""), str8_lit_comp("Focus Panel Right"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("focus_panel_left"), str8_lit_comp(""), str8_lit_comp("Focus Panel Left"), str8_lit_comp(""), RD_IconKind_LeftArrow}, +{str8_lit_comp("focus_panel_up"), str8_lit_comp(""), str8_lit_comp("Focus Panel Up"), str8_lit_comp(""), RD_IconKind_UpArrow}, +{str8_lit_comp("focus_panel_down"), str8_lit_comp(""), str8_lit_comp("Focus Panel Down"), str8_lit_comp(""), RD_IconKind_DownArrow}, +{str8_lit_comp("undo"), str8_lit_comp(""), str8_lit_comp("Undo"), str8_lit_comp(""), RD_IconKind_Undo}, +{str8_lit_comp("redo"), str8_lit_comp(""), str8_lit_comp("Redo"), str8_lit_comp(""), RD_IconKind_Redo}, +{str8_lit_comp("go_back"), str8_lit_comp(""), str8_lit_comp("Go Back"), str8_lit_comp(""), RD_IconKind_LeftArrow}, +{str8_lit_comp("go_forward"), str8_lit_comp(""), str8_lit_comp("Go Forward"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("close_panel"), str8_lit_comp(""), str8_lit_comp("Close Panel"), str8_lit_comp(""), RD_IconKind_ClosePanel}, +{str8_lit_comp("focus_tab"), str8_lit_comp(""), str8_lit_comp("Focus Tab"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("next_tab"), str8_lit_comp(""), str8_lit_comp("Focus Next Tab"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("prev_tab"), str8_lit_comp(""), str8_lit_comp("Focus Previous Tab"), str8_lit_comp(""), RD_IconKind_LeftArrow}, +{str8_lit_comp("move_tab_right"), str8_lit_comp(""), str8_lit_comp("Move Tab Right"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("move_tab_left"), str8_lit_comp(""), str8_lit_comp("Move Tab Left"), str8_lit_comp(""), RD_IconKind_LeftArrow}, +{str8_lit_comp("open_tab"), str8_lit_comp(""), str8_lit_comp("Open New Tab"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("build_tab"), str8_lit_comp(""), str8_lit_comp("Build Tab"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("duplicate_tab"), str8_lit_comp(""), str8_lit_comp("Duplicate Tab"), str8_lit_comp(""), RD_IconKind_Duplicate}, +{str8_lit_comp("copy_tab_full_path"), str8_lit_comp(""), str8_lit_comp("Copy Full Path"), str8_lit_comp(""), RD_IconKind_Clipboard}, +{str8_lit_comp("close_tab"), str8_lit_comp(""), str8_lit_comp("Close Tab"), str8_lit_comp(""), RD_IconKind_X}, +{str8_lit_comp("move_view"), str8_lit_comp(""), str8_lit_comp("Move View"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("tab_bar_top"), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Top"), str8_lit_comp(""), RD_IconKind_UpArrow}, +{str8_lit_comp("tab_bar_bottom"), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Bottom"), str8_lit_comp(""), RD_IconKind_DownArrow}, +{str8_lit_comp("tab_settings"), str8_lit_comp(""), str8_lit_comp("Tab Settings"), str8_lit_comp(""), RD_IconKind_Gear}, +{str8_lit_comp("set_current_path"), str8_lit_comp(""), str8_lit_comp("Set Current Path"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("open"), str8_lit_comp(""), str8_lit_comp("Open"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("switch"), str8_lit_comp(""), str8_lit_comp("Switch"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("switch_to_partner_file"), str8_lit_comp(""), str8_lit_comp("Switch To Partner File"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("record_file_in_project"), str8_lit_comp(""), str8_lit_comp("Record File In Project"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("show_file_in_explorer"), str8_lit_comp(""), str8_lit_comp("Show File In Explorer"), str8_lit_comp(""), RD_IconKind_FolderClosedFilled}, +{str8_lit_comp("go_to_disassembly"), str8_lit_comp(""), str8_lit_comp("Go To Disassembly"), str8_lit_comp(""), RD_IconKind_Glasses}, +{str8_lit_comp("go_to_source"), str8_lit_comp(""), str8_lit_comp("Go To Source"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("set_file_replacement_path"), str8_lit_comp(""), str8_lit_comp("Set File Replacement Path"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("new_user"), str8_lit_comp(""), str8_lit_comp("New User"), str8_lit_comp(""), RD_IconKind_Add}, +{str8_lit_comp("new_project"), str8_lit_comp(""), str8_lit_comp("New Project"), str8_lit_comp(""), RD_IconKind_Add}, +{str8_lit_comp("open_user"), str8_lit_comp(""), str8_lit_comp("Open User"), str8_lit_comp(""), RD_IconKind_Person}, +{str8_lit_comp("open_project"), str8_lit_comp(""), str8_lit_comp("Open Project"), str8_lit_comp(""), RD_IconKind_Briefcase}, +{str8_lit_comp("open_recent_project"), str8_lit_comp(""), str8_lit_comp("Open Recent Project"), str8_lit_comp(""), RD_IconKind_Briefcase}, +{str8_lit_comp("save_user"), str8_lit_comp(""), str8_lit_comp("Save User"), str8_lit_comp(""), RD_IconKind_Save}, +{str8_lit_comp("save_project"), str8_lit_comp(""), str8_lit_comp("Save Project"), str8_lit_comp(""), RD_IconKind_Save}, +{str8_lit_comp("write_user_data"), str8_lit_comp(""), str8_lit_comp("Write User Data"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("write_project_data"), str8_lit_comp(""), str8_lit_comp("Write Project Data"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("user_settings"), str8_lit_comp(""), str8_lit_comp("User Settings"), str8_lit_comp(""), RD_IconKind_Gear}, +{str8_lit_comp("project_settings"), str8_lit_comp(""), str8_lit_comp("Project Settings"), str8_lit_comp(""), RD_IconKind_Gear}, +{str8_lit_comp("edit"), str8_lit_comp(""), str8_lit_comp("Edit"), str8_lit_comp(""), RD_IconKind_Pencil}, +{str8_lit_comp("accept"), str8_lit_comp(""), str8_lit_comp("Accept"), str8_lit_comp(""), RD_IconKind_CheckFilled}, +{str8_lit_comp("cancel"), str8_lit_comp(""), str8_lit_comp("Cancel"), str8_lit_comp(""), RD_IconKind_X}, +{str8_lit_comp("move_left"), str8_lit_comp(""), str8_lit_comp("Move Left"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_right"), str8_lit_comp(""), str8_lit_comp("Move Right"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up"), str8_lit_comp(""), str8_lit_comp("Move Up"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down"), str8_lit_comp(""), str8_lit_comp("Move Down"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_left_select"), str8_lit_comp(""), str8_lit_comp("Move Left Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_right_select"), str8_lit_comp(""), str8_lit_comp("Move Right Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_select"), str8_lit_comp(""), str8_lit_comp("Move Up Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_select"), str8_lit_comp(""), str8_lit_comp("Move Down Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_left_chunk"), str8_lit_comp(""), str8_lit_comp("Move Left Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_right_chunk"), str8_lit_comp(""), str8_lit_comp("Move Right Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_chunk"), str8_lit_comp(""), str8_lit_comp("Move Up Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_chunk"), str8_lit_comp(""), str8_lit_comp("Move Down Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_page"), str8_lit_comp(""), str8_lit_comp("Move Up Page"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_page"), str8_lit_comp(""), str8_lit_comp("Move Down Page"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_whole"), str8_lit_comp(""), str8_lit_comp("Move Up Whole"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_whole"), str8_lit_comp(""), str8_lit_comp("Move Down Whole"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_left_chunk_select"), str8_lit_comp(""), str8_lit_comp("Move Left Chunk Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_right_chunk_select"), str8_lit_comp(""), str8_lit_comp("Move Right Chunk Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_chunk_select"), str8_lit_comp(""), str8_lit_comp("Move Up Chunk Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_chunk_select"), str8_lit_comp(""), str8_lit_comp("Move Down Chunk Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_page_select"), str8_lit_comp(""), str8_lit_comp("Move Up Page Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_page_select"), str8_lit_comp(""), str8_lit_comp("Move Down Page Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_whole_select"), str8_lit_comp(""), str8_lit_comp("Move Up Whole Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_whole_select"), str8_lit_comp(""), str8_lit_comp("Move Down Whole Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_up_reorder"), str8_lit_comp(""), str8_lit_comp("Move Up Reorder"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_down_reorder"), str8_lit_comp(""), str8_lit_comp("Move Down Reorder"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_home"), str8_lit_comp(""), str8_lit_comp("Move Home"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_end"), str8_lit_comp(""), str8_lit_comp("Move End"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_home_select"), str8_lit_comp(""), str8_lit_comp("Move Home Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_end_select"), str8_lit_comp(""), str8_lit_comp("Move End Select"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("select_all"), str8_lit_comp(""), str8_lit_comp("Select All"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("delete_single"), str8_lit_comp(""), str8_lit_comp("Delete Single"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("delete_chunk"), str8_lit_comp(""), str8_lit_comp("Delete Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("backspace_single"), str8_lit_comp(""), str8_lit_comp("Backspace Single"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("backspace_chunk"), str8_lit_comp(""), str8_lit_comp("Backspace Chunk"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("copy"), str8_lit_comp(""), str8_lit_comp("Copy"), str8_lit_comp(""), RD_IconKind_Clipboard}, +{str8_lit_comp("cut"), str8_lit_comp(""), str8_lit_comp("Cut"), str8_lit_comp(""), RD_IconKind_Clipboard}, +{str8_lit_comp("paste"), str8_lit_comp(""), str8_lit_comp("Paste"), str8_lit_comp(""), RD_IconKind_Clipboard}, +{str8_lit_comp("insert_text"), str8_lit_comp(""), str8_lit_comp("Insert Text"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_next"), str8_lit_comp(""), str8_lit_comp("Move Next"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("move_prev"), str8_lit_comp(""), str8_lit_comp("Move Previous"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("goto_line"), str8_lit_comp(""), str8_lit_comp("Go To Line"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("goto_address"), str8_lit_comp(""), str8_lit_comp("Go To Address"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("center_cursor"), str8_lit_comp(""), str8_lit_comp("Center Cursor"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("contain_cursor"), str8_lit_comp(""), str8_lit_comp("Contain Cursor"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("find_next"), str8_lit_comp(""), str8_lit_comp("Find Next"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("find_prev"), str8_lit_comp(""), str8_lit_comp("Find Previous"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("find_thread"), str8_lit_comp(""), str8_lit_comp("Find Thread"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("find_selected_thread"), str8_lit_comp(""), str8_lit_comp("Find Selected Thread"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("goto_name"), str8_lit_comp(""), str8_lit_comp("Go To Name"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("goto_name_at_cursor"), str8_lit_comp(""), str8_lit_comp("Go To Name At Cursor"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("toggle_watch_expr"), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("toggle_watch_expr_at_cursor"), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Cursor"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("toggle_watch_expr_at_mouse"), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Mouse"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("enable_cfg"), str8_lit_comp(""), str8_lit_comp("Enable"), str8_lit_comp(""), RD_IconKind_CheckHollow}, +{str8_lit_comp("disable_cfg"), str8_lit_comp(""), str8_lit_comp("Disable"), str8_lit_comp(""), RD_IconKind_CheckFilled}, +{str8_lit_comp("select_cfg"), str8_lit_comp(""), str8_lit_comp("Select"), str8_lit_comp(""), RD_IconKind_RadioHollow}, +{str8_lit_comp("deselect_cfg"), str8_lit_comp(""), str8_lit_comp("Deselect"), str8_lit_comp(""), RD_IconKind_RadioFilled}, +{str8_lit_comp("remove_cfg"), str8_lit_comp(""), str8_lit_comp("Remove"), str8_lit_comp(""), RD_IconKind_Trash}, +{str8_lit_comp("name_cfg"), str8_lit_comp(""), str8_lit_comp("Name"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("condition_cfg"), str8_lit_comp(""), str8_lit_comp("Condition"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("duplicate_cfg"), str8_lit_comp(""), str8_lit_comp("Duplicate"), str8_lit_comp(""), RD_IconKind_Duplicate}, +{str8_lit_comp("relocate_cfg"), str8_lit_comp(""), str8_lit_comp("Relocate"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("save_cfg_to_project"), str8_lit_comp(""), str8_lit_comp("Save To Project"), str8_lit_comp(""), RD_IconKind_Briefcase}, +{str8_lit_comp("add_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Line Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled}, +{str8_lit_comp("add_address_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Address Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled}, +{str8_lit_comp("add_function_breakpoint"), str8_lit_comp(""), str8_lit_comp("Add Function Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled}, +{str8_lit_comp("toggle_breakpoint"), str8_lit_comp(""), str8_lit_comp("Toggle Line Breakpoint"), str8_lit_comp(""), RD_IconKind_CircleFilled}, +{str8_lit_comp("enable_breakpoint"), str8_lit_comp(""), str8_lit_comp("Enable Breakpoint"), str8_lit_comp(""), RD_IconKind_CheckFilled}, +{str8_lit_comp("disable_breakpoint"), str8_lit_comp(""), str8_lit_comp("Disable Breakpoint"), str8_lit_comp(""), RD_IconKind_CheckHollow}, +{str8_lit_comp("clear_breakpoints"), str8_lit_comp(""), str8_lit_comp("Clear Breakpoints"), str8_lit_comp(""), RD_IconKind_Trash}, +{str8_lit_comp("add_watch_pin"), str8_lit_comp(""), str8_lit_comp("Add Watch Pin"), str8_lit_comp(""), RD_IconKind_Pin}, +{str8_lit_comp("toggle_watch_pin"), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin"), str8_lit_comp(""), RD_IconKind_Pin}, +{str8_lit_comp("add_type_view"), str8_lit_comp(""), str8_lit_comp("Add Type View"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("add_file_path_map"), str8_lit_comp(""), str8_lit_comp("Add File Path Map"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("edit_user_theme"), str8_lit_comp(""), str8_lit_comp("Edit User Theme"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("edit_project_theme"), str8_lit_comp(""), str8_lit_comp("Edit Project Theme"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("add_theme_color"), str8_lit_comp(""), str8_lit_comp("Add Theme Color"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("fork_theme"), str8_lit_comp(""), str8_lit_comp("Fork Theme"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("save_theme"), str8_lit_comp(""), str8_lit_comp("Save Theme"), str8_lit_comp(""), RD_IconKind_Save}, +{str8_lit_comp("save_and_set_theme"), str8_lit_comp(""), str8_lit_comp("Save And Set Theme"), str8_lit_comp(""), RD_IconKind_Save}, +{str8_lit_comp("set_next_statement"), str8_lit_comp(""), str8_lit_comp("Set Next Statement"), str8_lit_comp(""), RD_IconKind_RightArrow}, +{str8_lit_comp("add_target"), str8_lit_comp(""), str8_lit_comp("Add Target"), str8_lit_comp(""), RD_IconKind_Target}, +{str8_lit_comp("select_target"), str8_lit_comp(""), str8_lit_comp("Select Target"), str8_lit_comp(""), RD_IconKind_Target}, +{str8_lit_comp("enable_target"), str8_lit_comp(""), str8_lit_comp("Enable Target"), str8_lit_comp(""), RD_IconKind_CheckFilled}, +{str8_lit_comp("disable_target"), str8_lit_comp(""), str8_lit_comp("Disable Target"), str8_lit_comp(""), RD_IconKind_CheckHollow}, +{str8_lit_comp("register_as_jit_debugger"), str8_lit_comp(""), str8_lit_comp("Register As Just-In-Time (JIT) Debugger"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("find_code_location"), str8_lit_comp(""), str8_lit_comp("Find Code Location"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("search"), str8_lit_comp(""), str8_lit_comp("Search"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("search_backwards"), str8_lit_comp(""), str8_lit_comp("Search Backwards"), str8_lit_comp(""), RD_IconKind_Find}, +{str8_lit_comp("pick_file"), str8_lit_comp(""), str8_lit_comp("Pick File"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("pick_folder"), str8_lit_comp(""), str8_lit_comp("Pick Folder"), str8_lit_comp(""), RD_IconKind_FolderOpenFilled}, +{str8_lit_comp("pick_file_or_folder"), str8_lit_comp(""), str8_lit_comp("Pick File/Folder"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("push_query"), str8_lit_comp(""), str8_lit_comp("Push Query"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("complete_query"), str8_lit_comp(""), str8_lit_comp("Complete Query"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("cancel_query"), str8_lit_comp(""), str8_lit_comp("Cancel Query"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("update_query"), str8_lit_comp(""), str8_lit_comp("Update Query"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("toggle_dev_menu"), str8_lit_comp(""), str8_lit_comp("Toggle Developer Menu"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("log_marker"), str8_lit_comp(""), str8_lit_comp("Log Marker"), str8_lit_comp(""), RD_IconKind_Null}, +{str8_lit_comp("watches"), str8_lit_comp(""), str8_lit_comp("Watch"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("locals"), str8_lit_comp(""), str8_lit_comp("Locals"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("registers"), str8_lit_comp(""), str8_lit_comp("Registers"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("globals"), str8_lit_comp(""), str8_lit_comp("Globals"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("thread_locals"), str8_lit_comp(""), str8_lit_comp("Thread Locals"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("types"), str8_lit_comp(""), str8_lit_comp("Types"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("procedures"), str8_lit_comp(""), str8_lit_comp("Procedures"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("call_stack"), str8_lit_comp(""), str8_lit_comp("Call Stack"), str8_lit_comp(""), RD_IconKind_Thread}, +{str8_lit_comp("targets"), str8_lit_comp(""), str8_lit_comp("Targets"), str8_lit_comp(""), RD_IconKind_Target}, +{str8_lit_comp("breakpoints"), str8_lit_comp(""), str8_lit_comp("Breakpoints"), str8_lit_comp(""), RD_IconKind_CircleFilled}, +{str8_lit_comp("watch_pins"), str8_lit_comp(""), str8_lit_comp("Watch Pins"), str8_lit_comp(""), RD_IconKind_Pin}, +{str8_lit_comp("threads"), str8_lit_comp(""), str8_lit_comp("Threads"), str8_lit_comp(""), RD_IconKind_Threads}, +{str8_lit_comp("processes"), str8_lit_comp(""), str8_lit_comp("Processes"), str8_lit_comp(""), RD_IconKind_Scheduler}, +{str8_lit_comp("machines"), str8_lit_comp(""), str8_lit_comp("Machines"), str8_lit_comp(""), RD_IconKind_Machine}, +{str8_lit_comp("modules"), str8_lit_comp(""), str8_lit_comp("Modules"), str8_lit_comp(""), RD_IconKind_Module}, +{str8_lit_comp("file_path_maps"), str8_lit_comp(""), str8_lit_comp("File Path Map"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("type_views"), str8_lit_comp(""), str8_lit_comp("Type Views"), str8_lit_comp(""), RD_IconKind_Binoculars}, +{str8_lit_comp("output"), str8_lit_comp(""), str8_lit_comp("Output"), str8_lit_comp(""), RD_IconKind_List}, +{str8_lit_comp("text"), str8_lit_comp(""), str8_lit_comp("Text"), str8_lit_comp(""), RD_IconKind_FileOutline}, +{str8_lit_comp("disasm"), str8_lit_comp(""), str8_lit_comp("Disassembly"), str8_lit_comp(""), RD_IconKind_Glasses}, +{str8_lit_comp("memory"), str8_lit_comp(""), str8_lit_comp("Memory"), str8_lit_comp(""), RD_IconKind_Grid}, +{str8_lit_comp("bitmap"), str8_lit_comp(""), str8_lit_comp("Bitmap"), str8_lit_comp(""), RD_IconKind_Bitmap}, +{str8_lit_comp("color"), str8_lit_comp(""), str8_lit_comp("Color"), str8_lit_comp(""), RD_IconKind_Palette}, +{str8_lit_comp("geo3d"), str8_lit_comp(""), str8_lit_comp("Geometry (3D)"), str8_lit_comp(""), RD_IconKind_Cube}, }; -RD_EntityKindFlags rd_entity_kind_flags_table[27] = +RD_NameSchemaInfo rd_name_schema_info_table[24] = { -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (1*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (1*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (1*RD_EntityKindFlag_CanEnable) | (1*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (1*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (1*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (1*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(1*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (1*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (1*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (1*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (1*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (0*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), -(0*RD_EntityKindFlag_CanDelete) | (0*RD_EntityKindFlag_CanFreeze) | (0*RD_EntityKindFlag_CanEdit) | (1*RD_EntityKindFlag_CanRename) | (0*RD_EntityKindFlag_CanEnable) | (0*RD_EntityKindFlag_CanCondition) | (0*RD_EntityKindFlag_CanDuplicate) | (0*RD_EntityKindFlag_NameIsCode) | (0*RD_EntityKindFlag_NameIsPath) | (0*RD_EntityKindFlag_UserDefinedLifetime) | (0*RD_EntityKindFlag_IsSerializedToConfig), +{str8_lit_comp("user"), str8_lit_comp("@expand_commands(edit_user_theme) x:\n{\n //- rjf: animations\n @display_name('Animations') @description(\"Enables animations.\")\n @default(1) 'animations': bool,\n @display_name('Scrolling Animations') @description(\"Enables scrolling animations.\")\n @expand_if(\"$.animations\") @default(1) 'scrolling_animations': bool,\n @display_name('Tooltip Animations') @description(\"Enables tooltip animations.\")\n @expand_if(\"$.animations\") @default(1) 'tooltip_animations': bool,\n @display_name('Menu Animations') @description(\"Enables menu animations.\")\n @expand_if(\"$.animations\") @default(1) 'menu_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name of, or path to, the font used when displaying non-code UI elements.\")\n @default('') 'main_font': string,\n @display_name('Code Font') @description(\"The name of, or path to, the font used when displaying code.\")\n @default('') 'code_font': string,\n\n //- rjf: theme\n @default(\"Default (Dark)\") @display_name('User Theme')\n @description(\"The user's theme, which describes all colors used throughout the UI.\")\n 'theme': string,\n @no_expand @display_name('User Theme')\n 'theme_colors': query,\n\n //- rjf: autocompletion\n @display_name('Autocompletion Lister') @description(\"Enables the autocompletion lister while typing expressions.\") @default(1)\n 'autocompletion_lister': bool,\n @display_name('View Call Argument Helper') @description(\"Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.\") @default(1)\n 'view_call_argument_helper': bool,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n\n //- rjf: native filesystem dialogues\n @default(0) @display_name('Use Native File System Dialog') @description(\"Uses the operating system's file system dialog box, rather than the debugger's built-in UI.\")\n 'use_native_file_system_dialog': bool,\n}\n")}, +{str8_lit_comp("project"), str8_lit_comp("@expand_commands(edit_project_theme) x:\n{\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: visualizers\n @display_name('Use Default C++ STL Type Visualizers') @description(\"Enables the built-in type views for C++ STL types.\")\n @default(1) use_default_stl_type_views: bool,\n // @display_name('Use Default Unreal Engine Type Visualizers') @description(\"Enables the built-in type views for Unreal Engine types.\")\n // @default(1) use_default_ue_type_views: bool,\n\n //- rjf: theme\n @default(\"None\") @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme': string,\n @no_expand @display_name('Project Theme') @description(\"The project's theme, which describes all colors used throughout the UI, and can override the user's theme.\")\n 'theme_colors': query,\n\n //- rjf: exception settings\n @default(1) @display_name(\"Break On Win32 Control-C Exceptions\") @description(\"Code: 0x40010005\")\n win32_ctrl_c: bool;\n @default(1) @display_name(\"Break On Win32 Control-Break Exceptions\") @description(\"Code: 0x40010008\")\n win32_ctrl_break: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Originate Error Exceptions\") @description(\"Code: 0x40080201\")\n win32_win_rt_originate_error: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Transform Error Exceptions\") @description(\"Code: 0x40080202\")\n win32_win_rt_transform_error: bool;\n @default(0) @display_name(\"Break On Win32 RPC Call Cancelled Exceptions\") @description(\"Code: 0x0000071a\")\n win32_rpc_call_cancelled: bool;\n @default(0) @display_name(\"Break On Win32 Data Type Misalignment Exceptions\") @description(\"Code: 0x80000002\")\n win32_datatype_misalignment: bool;\n @default(1) @display_name(\"Break On Win32 Access Violation Exceptions\") @description(\"Code: 0xc0000005\")\n win32_access_violation: bool;\n @default(0) @display_name(\"Break On Win32 In Page Error Exceptions\") @description(\"Code: 0xc0000006\")\n win32_in_page_error: bool;\n @default(1) @display_name(\"Break On Win32 Invalid Handle Specified Exceptions\") @description(\"Code: 0xc0000008\")\n win32_invalid_handle: bool;\n @default(0) @display_name(\"Break On Win32 Not Enough Quota Exceptions\") @description(\"Code: 0xc0000017\")\n win32_not_enough_quota: bool;\n @default(0) @display_name(\"Break On Win32 Illegal Instruction Exceptions\") @description(\"Code: 0xc000001d\")\n win32_illegal_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Cannot Continue From Exception Exceptions\") @description(\"Code: 0xc0000025\")\n win32_cannot_continue_exception: bool;\n @default(0) @display_name(\"Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions\") @description(\"Code: 0xc0000026\")\n win32_invalid_exception_disposition: bool;\n @default(0) @display_name(\"Break On Win32 Array Bounds Exceeded Exceptions\") @description(\"Code: 0xc000008c\")\n win32_array_bounds_exceeded: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Denormal Operand Exceptions\") @description(\"Code: 0xc000008d\")\n win32_floating_point_denormal_operand: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Division By Zero Exceptions\") @description(\"Code: 0xc000008e\")\n win32_floating_point_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Inexact Result Exceptions\") @description(\"Code: 0xc000008f\")\n win32_floating_point_inexact_result: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Invalid Operation Exceptions\") @description(\"Code: 0xc0000090\")\n win32_floating_point_invalid_operation: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Overflow Exceptions\") @description(\"Code: 0xc0000091\")\n win32_floating_point_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Stack Check Exceptions\") @description(\"Code: 0xc0000092\")\n win32_floating_point_stack_check: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Underflow Exceptions\") @description(\"Code: 0xc0000093\")\n win32_floating_point_underflow: bool;\n @default(0) @display_name(\"Break On Win32 Integer Division By Zero Exceptions\") @description(\"Code: 0xc0000094\")\n win32_integer_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Integer Overflow Exceptions\") @description(\"Code: 0xc0000095\")\n win32_integer_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Privileged Instruction Exceptions\") @description(\"Code: 0xc0000096\")\n win32_privileged_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Stack Overflow Exceptions\") @description(\"Code: 0xc00000fd\")\n win32_stack_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Unable To Locate DLL Exceptions\") @description(\"Code: 0xc0000135\")\n win32_unable_to_locate_dll: bool;\n @default(0) @display_name(\"Break On Win32 Ordinal Not Found Exceptions\") @description(\"Code: 0xc0000138\")\n win32_ordinal_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Entry Point Not Found Exceptions\") @description(\"Code: 0xc0000139\")\n win32_entry_point_not_found: bool;\n @default(0) @display_name(\"Break On Win32 DLL Initialization Failed Exceptions\") @description(\"Code: 0xc0000142\")\n win32_dll_initialization_failed: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Faults Exceptions\") @description(\"Code: 0xc00002b4\")\n win32_floating_point_sse_multiple_faults: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Traps Exceptions\") @description(\"Code: 0xc00002b5\")\n win32_floating_point_sse_multiple_traps: bool;\n @default(1) @display_name(\"Break On Win32 Assertion Failed Exceptions\") @description(\"Code: 0xc0000420\")\n win32_assertion_failed: bool;\n @default(0) @display_name(\"Break On Win32 Module Not Found Exceptions\") @description(\"Code: 0xc06d007e\")\n win32_module_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Procedure Not Found Exceptions\") @description(\"Code: 0xc06d007f\")\n win32_procedure_not_found: bool;\n @default(1) @display_name(\"Break On Win32 Sanitizer Error Detected Exceptions\") @description(\"Code: 0xe073616e\")\n win32_sanitizer_error_detected: bool;\n @default(0) @display_name(\"Break On Win32 Sanitizer Raw Access Violation Exceptions\") @description(\"Code: 0xe0736171\")\n win32_sanitizer_raw_access_violation: bool;\n @default(1) @display_name(\"Break On Win32 DirectX Debug Layer Exceptions\") @description(\"Code: 0x0000087a\")\n win32_directx_debug_layer: bool;\n}\n")}, +{str8_lit_comp("theme_color"), str8_lit_comp("@collection_commands(add_theme_color, fork_theme, save_theme, save_and_set_theme)\n@row_commands(duplicate_cfg, remove_cfg)\nx:\n{\n @display_name('Tags') tags: string,\n @display_name('Value') value: @color @hex u32,\n}\n")}, +{str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n\n //- rjf: theme settings\n @default(1) @display_name('Use Project Theme') @description(\"Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.\")\n 'use_project_theme': bool,\n}\n")}, +{str8_lit_comp("tab"), str8_lit_comp("@row_commands(@file copy_tab_full_path, @file show_file_in_explorer, duplicate_tab, close_tab)\nx:\n{\n @override @display_name('Tab Font Size') @description(\"Controls the tab's font size.\") @no_callee_helper\n 'font_size': @range[6, 72] u64,\n}\n")}, +{str8_lit_comp("watch"), str8_lit_comp("@inherit(tab) x:\n{\n @override @display_name('Tab Row Height') @description(\"Controls the tab's row height, in multiples of the font size.\")\n 'row_height': @range[1.75f, 5.f] f32,\n 'label': code_string,\n @description(\"The root expression which is evaluated to produce the watch window.\")\n 'expression': expr_string,\n @no_expand 'watches': query,\n}\n")}, +{str8_lit_comp("text"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe data which should be viewed as text or code.\")\n 'expression': expr_string,\n @description(\"The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.\")\n 'lang': code_string,\n @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers':bool,\n @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description(\"Scrolls to the bottom if the text is changed.\")\n 'scroll_to_bottom_on_change':bool,\n @no_callee_helper @no_revert @default(0) @display_name('Transient') @description(\"Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.\")\n 'auto': bool,\n}\n")}, +{str8_lit_comp("disasm"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression to describe the base address or offset of the disassembly.\")\n 'expression': expr_string,\n 'arch': code_string,\n 'syntax': code_string,\n 'size': expr_string,\n @no_callee_helper @default(1) @description(\"Controls whether or not addresses are shown in the disassembly text.\")\n 'show_addresses': bool,\n @no_callee_helper @default(0) @description(\"Controls whether or not code bytes are shown in the disassembly text.\")\n 'show_code_bytes': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.\")\n 'show_source_lines': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not disassembly text is decorated with symbol names.\")\n 'show_symbol_names': bool,\n @no_callee_helper @default(1) @description(\"Controls whether or not line numbers are shown.\")\n 'show_line_numbers': bool,\n}\n")}, +{str8_lit_comp("memory"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the data which should be viewed as memory.\")\n 'expression': expr_string,\n @display_name(\"Address Range Size\") @description(\"The number of bytes of the viewed memory range.\")\n 'size': expr_string,\n @display_name(\"Cursor Address\") @description(\"The address of the cursor.\")\n 'cursor': expr_string,\n @display_name(\"Cursor Size\") @description(\"The size, in bytes, of the cursor.\")\n 'cursor_size': @range[1, 16] u64,\n @default(16) @description(\"The number of columns to build before building new rows.\")\n 'num_columns': @range[1, 64] u64,\n}\n")}, +{str8_lit_comp("bitmap"), str8_lit_comp("@inherit(tab) x:\n{\n @description(\"An expression which refers to the data which should be viewed as a bitmap.\")\n 'expression': expr_string,\n @description(\"An expression describing the width of the bitmap, in pixels.\") @order(0) 'w': u64,\n @description(\"An expression describing the height of the bitmap, in pixels.\") @order(1) 'h': u64,\n @display_name(\"Bitmap Format\") @description(\"The pixel format that the bitmap data should be interpreted as being within.\")\n 'fmt': code_string,\n}\n")}, +{str8_lit_comp("color"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Value\") @description(\"An expression to describe the value or location of the color.\")\n 'expression': expr_string,\n}\n")}, +{str8_lit_comp("geo3d"), str8_lit_comp("@inherit(tab) x:\n{\n @display_name(\"Expression\") @description(\"An expression to describe the base address of the index buffer.\")\n 'expression': expr_string,\n 'count': expr_string,\n 'vtx': expr_string,\n 'vtx_size': expr_string,\n 'yaw': @range[0, 1] f32,\n 'pitch': @range[-0.5, 0] f32,\n 'zoom': @range[0, 100] f32,\n}\n")}, +{str8_lit_comp("getting_started"), str8_lit_comp("@inherit(tab) x:\n{\n}\n")}, +{str8_lit_comp("target"), str8_lit_comp("@row_commands(@cmd_line save_cfg_to_project, enable_cfg, launch_and_run, launch_and_step_into, duplicate_cfg, remove_cfg)\n@collection_commands(add_target)\nx:\n{\n 'label': code_string,\n 'executable': path,\n 'arguments': string,\n 'working_directory': path,\n 'entry_point': expr_string,\n 'stdout_path': @no_relativize path,\n 'stderr_path': @no_relativize path,\n 'stdin_path': @no_relativize path,\n 'environment': query,\n 'debug_subprocesses': bool,\n @no_revert @no_expand @default(0) 'enabled': bool,\n}\n")}, +{str8_lit_comp("breakpoint"), str8_lit_comp("@row_commands(enable_cfg, duplicate_cfg, remove_cfg)\n@collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint, clear_breakpoints)\nx:\n{\n 'label': code_string,\n 'condition': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n 'hit_count': u64,\n 'address_range_size': @or(0, 1, 2, 4, 8) u64,\n 'break_on_write': bool,\n 'break_on_read': bool,\n 'break_on_execute': bool,\n @no_revert @no_expand @default(1) 'enabled': bool,\n}\n")}, +{str8_lit_comp("watch_pin"), str8_lit_comp("@row_commands(duplicate_cfg, remove_cfg)\n@collection_commands(add_watch_pin, toggle_watch_pin)\nx:\n{\n 'expression': expr_string,\n 'source_location': path_pt,\n 'address_location': expr_string,\n}\n")}, +{str8_lit_comp("file_path_map"), str8_lit_comp("@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @no_relativize path, 'dest': @no_relativize path}")}, +{str8_lit_comp("type_view"), str8_lit_comp("@collection_commands(add_type_view) @row_commands(remove_cfg) x:{'type':expr_string, 'expr':expr_string}")}, +{str8_lit_comp("recent_project"), str8_lit_comp("x:{'path':path}")}, +{str8_lit_comp("recent_file"), str8_lit_comp("x:{'path':path}")}, +{str8_lit_comp("machine"), str8_lit_comp("x:{'label':code_string, @no_expand 'active':bool, 'unattached_processes':query, 'processes':query}")}, +{str8_lit_comp("process"), str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'modules':query, 'threads':query}")}, +{str8_lit_comp("module"), str8_lit_comp("x:{'exe':path, 'dbg':path, 'vaddr_range':vaddr_range}")}, +{str8_lit_comp("thread"), str8_lit_comp("x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':query}")}, }; -Rng1U64 rd_reg_slot_range_table[34] = +Rng1U64 rd_reg_slot_range_table[44] = { {0}, {OffsetOf(RD_Regs, machine), OffsetOf(RD_Regs, machine) + sizeof(CTRL_Handle)}, @@ -199,19 +443,20 @@ Rng1U64 rd_reg_slot_range_table[34] = {OffsetOf(RD_Regs, process), OffsetOf(RD_Regs, process) + sizeof(CTRL_Handle)}, {OffsetOf(RD_Regs, thread), OffsetOf(RD_Regs, thread) + sizeof(CTRL_Handle)}, {OffsetOf(RD_Regs, ctrl_entity), OffsetOf(RD_Regs, ctrl_entity) + sizeof(CTRL_Handle)}, -{OffsetOf(RD_Regs, window), OffsetOf(RD_Regs, window) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, panel), OffsetOf(RD_Regs, panel) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, view), OffsetOf(RD_Regs, view) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, prev_view), OffsetOf(RD_Regs, prev_view) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, dst_panel), OffsetOf(RD_Regs, dst_panel) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, entity), OffsetOf(RD_Regs, entity) + sizeof(RD_Handle)}, -{OffsetOf(RD_Regs, entity_list), OffsetOf(RD_Regs, entity_list) + sizeof(RD_HandleList)}, +{OffsetOf(RD_Regs, window), OffsetOf(RD_Regs, window) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, panel), OffsetOf(RD_Regs, panel) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, tab), OffsetOf(RD_Regs, tab) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, view), OffsetOf(RD_Regs, view) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, prev_tab), OffsetOf(RD_Regs, prev_tab) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, dst_panel), OffsetOf(RD_Regs, dst_panel) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, cfg), OffsetOf(RD_Regs, cfg) + sizeof(RD_CfgID)}, +{OffsetOf(RD_Regs, cfg_list), OffsetOf(RD_Regs, cfg_list) + sizeof(RD_CfgIDList)}, {OffsetOf(RD_Regs, unwind_count), OffsetOf(RD_Regs, unwind_count) + sizeof(U64)}, {OffsetOf(RD_Regs, inline_depth), OffsetOf(RD_Regs, inline_depth) + sizeof(U64)}, {OffsetOf(RD_Regs, file_path), OffsetOf(RD_Regs, file_path) + sizeof(String8)}, {OffsetOf(RD_Regs, cursor), OffsetOf(RD_Regs, cursor) + sizeof(TxtPt)}, {OffsetOf(RD_Regs, mark), OffsetOf(RD_Regs, mark) + sizeof(TxtPt)}, -{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(U128)}, +{OffsetOf(RD_Regs, text_key), OffsetOf(RD_Regs, text_key) + sizeof(HS_Key)}, {OffsetOf(RD_Regs, lang_kind), OffsetOf(RD_Regs, lang_kind) + sizeof(TXT_LangKind)}, {OffsetOf(RD_Regs, lines), OffsetOf(RD_Regs, lines) + sizeof(D_LineList)}, {OffsetOf(RD_Regs, dbgi_key), OffsetOf(RD_Regs, dbgi_key) + sizeof(DI_Key)}, @@ -219,9 +464,18 @@ Rng1U64 rd_reg_slot_range_table[34] = {OffsetOf(RD_Regs, voff), OffsetOf(RD_Regs, voff) + sizeof(U64)}, {OffsetOf(RD_Regs, vaddr_range), OffsetOf(RD_Regs, vaddr_range) + sizeof(Rng1U64)}, {OffsetOf(RD_Regs, voff_range), OffsetOf(RD_Regs, voff_range) + sizeof(Rng1U64)}, +{OffsetOf(RD_Regs, expr), OffsetOf(RD_Regs, expr) + sizeof(String8)}, +{OffsetOf(RD_Regs, ui_key), OffsetOf(RD_Regs, ui_key) + sizeof(UI_Key)}, +{OffsetOf(RD_Regs, off_px), OffsetOf(RD_Regs, off_px) + sizeof(Vec2F32)}, +{OffsetOf(RD_Regs, reg_slot), OffsetOf(RD_Regs, reg_slot) + sizeof(RD_RegSlot)}, {OffsetOf(RD_Regs, pid), OffsetOf(RD_Regs, pid) + sizeof(U32)}, {OffsetOf(RD_Regs, force_confirm), OffsetOf(RD_Regs, force_confirm) + sizeof(B32)}, +{OffsetOf(RD_Regs, force_focus), OffsetOf(RD_Regs, force_focus) + sizeof(B32)}, {OffsetOf(RD_Regs, prefer_disasm), OffsetOf(RD_Regs, prefer_disasm) + sizeof(B32)}, +{OffsetOf(RD_Regs, no_rich_tooltip), OffsetOf(RD_Regs, no_rich_tooltip) + sizeof(B32)}, +{OffsetOf(RD_Regs, do_implicit_root), OffsetOf(RD_Regs, do_implicit_root) + sizeof(B32)}, +{OffsetOf(RD_Regs, do_lister), OffsetOf(RD_Regs, do_lister) + sizeof(B32)}, +{OffsetOf(RD_Regs, do_big_rows), OffsetOf(RD_Regs, do_big_rows) + sizeof(B32)}, {OffsetOf(RD_Regs, dir2), OffsetOf(RD_Regs, dir2) + sizeof(Dir2)}, {OffsetOf(RD_Regs, string), OffsetOf(RD_Regs, string) + sizeof(String8)}, {OffsetOf(RD_Regs, cmd_name), OffsetOf(RD_Regs, cmd_name) + sizeof(String8)}, @@ -229,224 +483,247 @@ Rng1U64 rd_reg_slot_range_table[34] = {OffsetOf(RD_Regs, os_event), OffsetOf(RD_Regs, os_event) + sizeof(OS_Event *)}, }; -RD_CmdKindInfo rd_cmd_kind_info_table[213] = +RD_CmdKindInfo rd_cmd_kind_info_table[236] = { {0}, -{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp("Launch and Run"), RD_IconKind_Play, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Target, CTRL_EntityKind_Null}}, -{ str8_lit_comp("launch_and_init"), str8_lit_comp("Starts debugging a new instance of a target, then stops at the program's entry point."), str8_lit_comp("launch,start,entry,point"), str8_lit_comp("Launch and Initialize"), RD_IconKind_PlayStepForward, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Target, CTRL_EntityKind_Null}}, -{ str8_lit_comp("kill"), str8_lit_comp("Kills the specified existing attached process(es)."), str8_lit_comp("stop,kill"), str8_lit_comp("Kill"), RD_IconKind_X, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Process}}, -{ str8_lit_comp("kill_all"), str8_lit_comp("Kills all attached processes."), str8_lit_comp("stop,kill,all"), str8_lit_comp("Kill All"), RD_IconKind_Stop, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("detach"), str8_lit_comp("Detaches the specified attached process(es)."), str8_lit_comp("detach"), str8_lit_comp("Detach"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Process}}, -{ str8_lit_comp("continue"), str8_lit_comp("Continues executing all attached processes."), str8_lit_comp(""), str8_lit_comp("Continue"), RD_IconKind_Play, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_into_inst"), str8_lit_comp("Performs a step that goes into calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Into (Assembly)"), RD_IconKind_StepInto, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_over_inst"), str8_lit_comp("Performs a step that skips calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp("Step Over (Assembly)"), RD_IconKind_StepOver, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Into (Line)"), RD_IconKind_StepInto, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp("Step Over (Line)"), RD_IconKind_StepOver, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_out"), str8_lit_comp("Runs to the end of the current function and exits it."), str8_lit_comp(""), str8_lit_comp("Step Out"), RD_IconKind_StepOut, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("halt"), str8_lit_comp("Halts all attached processes."), str8_lit_comp("pause"), str8_lit_comp("Halt"), RD_IconKind_Pause, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all attached processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp("Soft Halt Refresh"), RD_IconKind_Refresh, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the specified thread's instruction pointer at the specified address."), str8_lit_comp(""), str8_lit_comp("Set Thread IP"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("run_to_line"), str8_lit_comp("Runs until a particular source line is hit."), str8_lit_comp(""), str8_lit_comp("Run To Line"), RD_IconKind_Play, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("run_to_address"), str8_lit_comp("Runs until a particular address is hit."), str8_lit_comp(""), str8_lit_comp("Run To Address"), RD_IconKind_PlayStepForward, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("run"), str8_lit_comp("Runs all targets after starting them if they have not been started yet."), str8_lit_comp("play"), str8_lit_comp("Run"), RD_IconKind_Play, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("restart"), str8_lit_comp("Kills all attached processes, then launches all active targets."), str8_lit_comp("restart,retry"), str8_lit_comp("Restart"), RD_IconKind_Redo, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_into"), str8_lit_comp("Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)."), str8_lit_comp(""), str8_lit_comp("Step Into"), RD_IconKind_StepInto, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("step_over"), str8_lit_comp("Steps once, always over function calls, for either source lines or instructions."), str8_lit_comp(""), str8_lit_comp("Step Over"), RD_IconKind_StepOver, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("freeze_thread"), str8_lit_comp("Freezes the passed thread."), str8_lit_comp("callstack,unwind"), str8_lit_comp("Freeze Thread"), RD_IconKind_Locked, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Thread}}, -{ str8_lit_comp("thaw_thread"), str8_lit_comp("Thaws the passed thread."), str8_lit_comp(""), str8_lit_comp("Thaw Thread"), RD_IconKind_Unlocked, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Thread}}, -{ str8_lit_comp("freeze_process"), str8_lit_comp("Freezes the passed process."), str8_lit_comp(""), str8_lit_comp("Freeze Process"), RD_IconKind_Locked, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Process}}, -{ str8_lit_comp("thaw_process"), str8_lit_comp("Thaws the passed process."), str8_lit_comp(""), str8_lit_comp("Thaw Process"), RD_IconKind_Unlocked, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Process}}, -{ str8_lit_comp("freeze_machine"), str8_lit_comp("Freezes the passed machine."), str8_lit_comp(""), str8_lit_comp("Freeze Machine"), RD_IconKind_Locked, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Machine, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Machine}}, -{ str8_lit_comp("thaw_machine"), str8_lit_comp("Thaws the passed machine."), str8_lit_comp(""), str8_lit_comp("Thaw Machine"), RD_IconKind_Unlocked, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Machine, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Machine}}, -{ str8_lit_comp("freeze_local_machine"), str8_lit_comp("Freezes the local machine."), str8_lit_comp(""), str8_lit_comp("Freeze Local Machine"), RD_IconKind_Machine, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("thaw_local_machine"), str8_lit_comp("Thaws the local machine."), str8_lit_comp(""), str8_lit_comp("Thaw Local Machine"), RD_IconKind_Machine, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("freeze_entity"), str8_lit_comp("Freezes an entity."), str8_lit_comp(""), str8_lit_comp("Freeze Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("thaw_entity"), str8_lit_comp("Thaws an entity."), str8_lit_comp(""), str8_lit_comp("Thaw Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_entity_color"), str8_lit_comp("Sets the passed entity's color."), str8_lit_comp(""), str8_lit_comp("Set Entity Color"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_entity_name"), str8_lit_comp("Sets the passed entity's name."), str8_lit_comp(""), str8_lit_comp("Set Entity Name"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("attach"), str8_lit_comp("Attaches to a process that is already running on the local machine."), str8_lit_comp(""), str8_lit_comp("Attach"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_PID, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("exit"), str8_lit_comp("Exits the debugger."), str8_lit_comp("quit,close,abort"), str8_lit_comp("Exit"), RD_IconKind_X, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("run_command"), str8_lit_comp("Runs a command from the command palette."), str8_lit_comp("help,cmd"), str8_lit_comp("Run Command"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_CmdName, str8_lit_comp("commands"), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("os_event"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp("OS Event"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("select_thread"), str8_lit_comp("Selects a thread."), str8_lit_comp(""), str8_lit_comp("Select Thread"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Thread}}, -{ str8_lit_comp("select_unwind"), str8_lit_comp("Selects an unwind frame number for the selected thread."), str8_lit_comp(""), str8_lit_comp("Select Unwind"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("up_one_frame"), str8_lit_comp("Selects the call stack frame above the currently selected."), str8_lit_comp(""), str8_lit_comp("Up One Frame"), RD_IconKind_UpArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("down_one_frame"), str8_lit_comp("Selects the call stack frame below the currently selected."), str8_lit_comp("callstack,unwind"), str8_lit_comp("Down One Frame"), RD_IconKind_DownArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("inc_ui_font_scale"), str8_lit_comp("Increases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Increase UI Font Scale"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("dec_ui_font_scale"), str8_lit_comp("Decreases the font size used for UI."), str8_lit_comp(""), str8_lit_comp("Decrease UI Font Scale"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("inc_code_font_scale"), str8_lit_comp("Increases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Increase Code Font Scale"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("dec_code_font_scale"), str8_lit_comp("Decreases the font size used for code."), str8_lit_comp(""), str8_lit_comp("Decrease Code Font Scale"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open_window"), str8_lit_comp("Opens a new window."), str8_lit_comp(""), str8_lit_comp("Open New Window"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("close_window"), str8_lit_comp("Closes an opened window."), str8_lit_comp(""), str8_lit_comp("Close Window"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_fullscreen"), str8_lit_comp("Toggles fullscreen view on the active window."), str8_lit_comp(""), str8_lit_comp("Toggle Fullscreen"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("bring_to_front"), str8_lit_comp("Brings all windows to the front, and focuses the most recently focused window."), str8_lit_comp("top"), str8_lit_comp("Bring To Front"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("popup_accept"), str8_lit_comp("Accepts the active popup prompt."), str8_lit_comp(""), str8_lit_comp("Popup Accept"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("popup_cancel"), str8_lit_comp("Cancels the active popup prompt."), str8_lit_comp(""), str8_lit_comp("Popup Cancel"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("reset_to_default_panels"), str8_lit_comp("Resets the window to the default panel layout."), str8_lit_comp("panel"), str8_lit_comp("Reset To Default Panel Layout"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("reset_to_compact_panels"), str8_lit_comp("Resets the window to the compact panel layout."), str8_lit_comp("panel"), str8_lit_comp("Reset To Compact Panel Layout"), RD_IconKind_Window, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("new_panel_left"), str8_lit_comp("Creates a new panel to the left of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Left"), RD_IconKind_XSplit, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("new_panel_up"), str8_lit_comp("Creates a new panel at the top of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Up"), RD_IconKind_YSplit, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("new_panel_right"), str8_lit_comp("Creates a new panel to the right of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Right"), RD_IconKind_XSplit, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("new_panel_down"), str8_lit_comp("Creates a new panel at the bottom of the active panel."), str8_lit_comp("panel"), str8_lit_comp("Split Panel Down"), RD_IconKind_YSplit, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("split_panel"), str8_lit_comp("Creates a new panel in a given direction, and moves a tab to it, if specified."), str8_lit_comp(""), str8_lit_comp("Split Panel"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("rotate_panel_columns"), str8_lit_comp("Rotates all panels at the closest column level of the panel hierarchy."), str8_lit_comp(""), str8_lit_comp("Rotate Panel Columns"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("next_panel"), str8_lit_comp("Cycles the active panel forward."), str8_lit_comp(""), str8_lit_comp("Focus Next Panel"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("prev_panel"), str8_lit_comp("Cycles the active panel backwards."), str8_lit_comp(""), str8_lit_comp("Focus Previous Panel"), RD_IconKind_LeftArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("focus_panel"), str8_lit_comp("Focuses a new panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("focus_panel_right"), str8_lit_comp("Focuses a panel rightward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Right"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("focus_panel_left"), str8_lit_comp("Focuses a panel leftward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Left"), RD_IconKind_LeftArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("focus_panel_up"), str8_lit_comp("Focuses a panel upward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Up"), RD_IconKind_UpArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("focus_panel_down"), str8_lit_comp("Focuses a panel downward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp("Focus Panel Down"), RD_IconKind_DownArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("undo"), str8_lit_comp("Undoes the previous action."), str8_lit_comp(""), str8_lit_comp("Undo"), RD_IconKind_Undo, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("redo"), str8_lit_comp("Redoes the first previously undone action."), str8_lit_comp(""), str8_lit_comp("Redo"), RD_IconKind_Redo, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("go_back"), str8_lit_comp("Returns to the previously selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Back"), RD_IconKind_LeftArrow, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("go_forward"), str8_lit_comp("Returns to the next selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp("Go Forward"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("close_panel"), str8_lit_comp("Closes the currently active panel."), str8_lit_comp(""), str8_lit_comp("Close Panel"), RD_IconKind_ClosePanel, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("next_tab"), str8_lit_comp("Focuses the next tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Next Tab"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("prev_tab"), str8_lit_comp("Focuses the previous tab on the active panel."), str8_lit_comp(""), str8_lit_comp("Focus Previous Tab"), RD_IconKind_LeftArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_tab_right"), str8_lit_comp("Moves the selected tab right one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Right"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_tab_left"), str8_lit_comp("Moves the selected tab left one slot."), str8_lit_comp(""), str8_lit_comp("Move Tab Left"), RD_IconKind_LeftArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open_tab"), str8_lit_comp("Opens a new tab with the parameterized view specification."), str8_lit_comp(""), str8_lit_comp("Open Tab"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("close_tab"), str8_lit_comp("Closes the currently opened tab."), str8_lit_comp(""), str8_lit_comp("Close Tab"), RD_IconKind_X, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_tab"), str8_lit_comp("Moves a tab to a new panel."), str8_lit_comp(""), str8_lit_comp("Move Tab"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("tab_bar_top"), str8_lit_comp("Anchors a panel's tab bar to the top of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Top"), RD_IconKind_UpArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("tab_bar_bottom"), str8_lit_comp("Anchors a panel's tab bar to the bottom of the panel."), str8_lit_comp(""), str8_lit_comp("Anchor Tab Bar To Bottom"), RD_IconKind_DownArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp("Set Current Path"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp("Open"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("switch"), str8_lit_comp("Switches to a recent file."), str8_lit_comp("code,source,file"), str8_lit_comp("Switch"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_RecentFile, CTRL_EntityKind_Null}}, -{ str8_lit_comp("switch_to_partner_file"), str8_lit_comp("Switches to the focused file's partner; or from header to implementation or vice versa."), str8_lit_comp("code,source,file"), str8_lit_comp("Switch To Partner File"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("record_file_in_project"), str8_lit_comp("Records the passed file path as a recent file in the currently loaded project."), str8_lit_comp(""), str8_lit_comp("Record File In Project"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("go_to_disassembly"), str8_lit_comp("Goes to the disassembly, if any, for a given source code line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp("Go To Disassembly"), RD_IconKind_Glasses, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("go_to_source"), str8_lit_comp("Goes to the source code, if any, for a given disassembly line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp("Go To Source"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_file_replacement_path"), str8_lit_comp("Sets the path which should be used as the replacement for the passed file."), str8_lit_comp(""), str8_lit_comp("Set File Replacement Path"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open_user"), str8_lit_comp("Opens a user file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("load,user,project,layout"), str8_lit_comp("Open User"), RD_IconKind_Person, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open_project"), str8_lit_comp("Opens a project file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("project,project,session"), str8_lit_comp("Open Project"), RD_IconKind_Briefcase, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("open_recent_project"), str8_lit_comp("Opens a recently used project file."), str8_lit_comp("project,project,session"), str8_lit_comp("Open Recent Project"), RD_IconKind_Briefcase, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_RecentProject, CTRL_EntityKind_Null}}, -{ str8_lit_comp("apply_user_data"), str8_lit_comp("Applies user data from the active user file."), str8_lit_comp(""), str8_lit_comp("Apply User Data"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("apply_project_data"), str8_lit_comp("Applies project data from the active project file."), str8_lit_comp(""), str8_lit_comp("Apply Project Data"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("write_user_data"), str8_lit_comp("Writes user data to the active user file."), str8_lit_comp(""), str8_lit_comp("Write User Data"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("write_project_data"), str8_lit_comp("Writes project data to the active project file."), str8_lit_comp(""), str8_lit_comp("Write Project Data"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("edit"), str8_lit_comp("Edits the current selection."), str8_lit_comp(""), str8_lit_comp("Edit"), RD_IconKind_Pencil, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("accept"), str8_lit_comp("Accepts current changes, or answers prompts in the affirmative."), str8_lit_comp(""), str8_lit_comp("Accept"), RD_IconKind_CheckFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("cancel"), str8_lit_comp("Rejects current changes, exits temporary menus, or answers prompts in the negative."), str8_lit_comp(""), str8_lit_comp("Cancel"), RD_IconKind_X, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp("Move Left"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp("Move Right"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp("Move Up"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down"), str8_lit_comp("Moves the cursor or selection down."), str8_lit_comp(""), str8_lit_comp("Move Down"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_left_select"), str8_lit_comp("Moves the cursor or selection left, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_right_select"), str8_lit_comp("Moves the cursor or selection right, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_select"), str8_lit_comp("Moves the cursor or selection up, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_select"), str8_lit_comp("Moves the cursor or selection down, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_left_chunk"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_right_chunk"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_chunk"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_chunk"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_page"), str8_lit_comp("Moves the cursor or selection up one page."), str8_lit_comp(""), str8_lit_comp("Move Up Page"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_page"), str8_lit_comp("Moves the cursor or selection down one page."), str8_lit_comp(""), str8_lit_comp("Move Down Page"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_whole"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Up Whole"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_whole"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content."), str8_lit_comp(""), str8_lit_comp("Move Down Whole"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_left_chunk_select"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp("Move Left Chunk Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_right_chunk_select"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp("Move Right Chunk Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_chunk_select"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp("Move Up Chunk Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_chunk_select"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp("Move Down Chunk Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_page_select"), str8_lit_comp("Moves the cursor or selection up one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Page Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_page_select"), str8_lit_comp("Moves the cursor or selection down one page, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Page Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_whole_select"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Up Whole Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_whole_select"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Down Whole Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_up_reorder"), str8_lit_comp("Moves the cursor or selection up, while swapping the currently selected element with that upward."), str8_lit_comp(""), str8_lit_comp("Move Up Reorder"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_down_reorder"), str8_lit_comp("Moves the cursor or selection down, while swapping the currently selected element with that downward."), str8_lit_comp(""), str8_lit_comp("Move Down Reorder"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_home"), str8_lit_comp("Moves the cursor to the beginning of the line."), str8_lit_comp(""), str8_lit_comp("Move Home"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_end"), str8_lit_comp("Moves the cursor to the end of the line."), str8_lit_comp(""), str8_lit_comp("Move End"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_home_select"), str8_lit_comp("Moves the cursor to the beginning of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move Home Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("move_end_select"), str8_lit_comp("Moves the cursor to the end of the line, while selecting."), str8_lit_comp(""), str8_lit_comp("Move End Select"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("select_all"), str8_lit_comp("Selects everything possible."), str8_lit_comp(""), str8_lit_comp("Select All"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("delete_single"), str8_lit_comp("Deletes a single element to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Single"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("delete_chunk"), str8_lit_comp("Deletes a chunk to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Delete Chunk"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("backspace_single"), str8_lit_comp("Deletes a single element to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Single"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("backspace_chunk"), str8_lit_comp("Deletes a chunk to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp("Backspace Chunk"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("copy"), str8_lit_comp("Copies the active selection to the clipboard."), str8_lit_comp(""), str8_lit_comp("Copy"), RD_IconKind_Clipboard, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("cut"), str8_lit_comp("Copies the active selection to the clipboard, then deletes it."), str8_lit_comp(""), str8_lit_comp("Cut"), RD_IconKind_Clipboard, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("paste"), str8_lit_comp("Pastes the current contents of the clipboard."), str8_lit_comp(""), str8_lit_comp("Paste"), RD_IconKind_Clipboard, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp("Insert Text"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp("Go To Line"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cursor, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp("Go To Address"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp("Center Cursor"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp("Contain Cursor"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_text_forward"), str8_lit_comp("Searches the current code file forward (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Forward)"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_text_backward"), str8_lit_comp("Searches the current code file backwards (from the cursor) for a string."), str8_lit_comp(""), str8_lit_comp("Find Text (Backwards)"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_next"), str8_lit_comp("Searches the current code file forward (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Next"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_prev"), str8_lit_comp("Searches the current code file backwards (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp("Find Previous"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_thread"), str8_lit_comp("Jumps to the passed thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Thread"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Thread}}, -{ str8_lit_comp("find_selected_thread"), str8_lit_comp("Jumps to the selected thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp("Find Selected Thread"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("goto_name"), str8_lit_comp("Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp("symbol_lister"), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("goto_name_at_cursor"), str8_lit_comp("Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("Go To Name At Cursor"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_watch_expr"), str8_lit_comp("Adds or removes an expression to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_watch_expr_at_cursor"), str8_lit_comp("Adds or removes the expression that the cursor or selection is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Cursor"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_watch_expr_at_mouse"), str8_lit_comp("Adds or removes the expression that the mouse is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Expression At Mouse"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_columns"), str8_lit_comp("Sets the number of columns for a memory view."), str8_lit_comp(""), str8_lit_comp("Set Columns"), RD_IconKind_Thumbnails, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_address_visibility"), str8_lit_comp("Toggles the visibility of addresses in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Address Visibility"), RD_IconKind_Thumbnails, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_code_bytes_visibility"), str8_lit_comp("Toggles the visibility of machine code bytes in a disassembly view."), str8_lit_comp(""), str8_lit_comp("Toggle Code Bytes Visibility"), RD_IconKind_Thumbnails, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("enable_entity"), str8_lit_comp("Enables an entity."), str8_lit_comp(""), str8_lit_comp("Enable Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("disable_entity"), str8_lit_comp("Disables an entity."), str8_lit_comp(""), str8_lit_comp("Disable Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("select_entity"), str8_lit_comp("Selects an entity, disabling all others of the same kind."), str8_lit_comp(""), str8_lit_comp("Select Entity"), RD_IconKind_CheckHollow, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("remove_entity"), str8_lit_comp("Removes an entity."), str8_lit_comp(""), str8_lit_comp("Remove Entity"), RD_IconKind_Trash, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("name_entity"), str8_lit_comp("Equips an entity with a name."), str8_lit_comp(""), str8_lit_comp("Name Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("condition_entity"), str8_lit_comp("Equips an entity with a condition string."), str8_lit_comp(""), str8_lit_comp("Condition Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("duplicate_entity"), str8_lit_comp("Duplicates an entity."), str8_lit_comp(""), str8_lit_comp("Duplicate Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("relocate_entity"), str8_lit_comp("Relocates an entity."), str8_lit_comp(""), str8_lit_comp("Relocate Entity"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_breakpoint"), str8_lit_comp("Places a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp("Add Breakpoint"), RD_IconKind_CircleFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_address_breakpoint"), str8_lit_comp("Places a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("Add Address Breakpoint"), RD_IconKind_CircleFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("Places a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("Add Function Breakpoint"), RD_IconKind_CircleFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp("symbol_lister"), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_breakpoint"), str8_lit_comp("Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint"), RD_IconKind_CircleFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Enable Breakpoint"), RD_IconKind_CheckFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Breakpoint, CTRL_EntityKind_Null}}, -{ str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp("Disable Breakpoint"), RD_IconKind_CheckHollow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Breakpoint, CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_watch_pin"), str8_lit_comp("Places a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp("Add Watch Pin"), RD_IconKind_Pin, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_watch_pin"), str8_lit_comp("Places or removes a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp("Toggle Watch Pin"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("run_to_cursor"), str8_lit_comp("Runs the selected thread to the current cursor."), str8_lit_comp("line"), str8_lit_comp("Run To Cursor"), RD_IconKind_Play, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("set_next_statement"), str8_lit_comp("Sets the selected thread's instruction pointer to the cursor's position."), str8_lit_comp(""), str8_lit_comp("Set Next Statement"), RD_IconKind_RightArrow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("add_target"), str8_lit_comp("Adds a new target."), str8_lit_comp("application,executable,debug"), str8_lit_comp("Add Target"), RD_IconKind_Target, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("select_target"), str8_lit_comp("Selects a target."), str8_lit_comp(""), str8_lit_comp("Select Target"), RD_IconKind_Target, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Target, CTRL_EntityKind_Null}}, -{ str8_lit_comp("enable_target"), str8_lit_comp("Enables a target, in addition to all targets currently enabled."), str8_lit_comp(""), str8_lit_comp("Enable Target"), RD_IconKind_CheckFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Target, CTRL_EntityKind_Null}}, -{ str8_lit_comp("disable_target"), str8_lit_comp("Disables a target."), str8_lit_comp(""), str8_lit_comp("Disable Target"), RD_IconKind_CheckHollow, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Entity, str8_lit_comp(""), RD_EntityKind_Target, CTRL_EntityKind_Null}}, -{ str8_lit_comp("register_as_jit_debugger"), str8_lit_comp("Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system."), str8_lit_comp(""), str8_lit_comp("Register As Just-In-Time (JIT) Debugger"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("find_code_location"), str8_lit_comp("Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary."), str8_lit_comp(""), str8_lit_comp("Find Code Location"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("filter"), str8_lit_comp("Begins filtering the active view."), str8_lit_comp("sort,search,filter,find"), str8_lit_comp("Filter"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("apply_filter"), str8_lit_comp("Applies the typed filter to the active view."), str8_lit_comp("sort,search,filter,find,apply"), str8_lit_comp("Apply Filter"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("clear_filter"), str8_lit_comp("Clears the filter applied to the active view."), str8_lit_comp("sort,search,filter,find,clear"), str8_lit_comp("Clear Filter"), RD_IconKind_Find, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("getting_started"), str8_lit_comp("Opens the menu for information on getting started."), str8_lit_comp("tutorial,help"), str8_lit_comp("Getting Started"), RD_IconKind_QuestionMark, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("commands"), str8_lit_comp("Opens the list of all commands."), str8_lit_comp(""), str8_lit_comp("Commands"), RD_IconKind_List, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("target"), str8_lit_comp("Opens the editor for a target."), str8_lit_comp(""), str8_lit_comp("Target"), RD_IconKind_Target, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("targets"), str8_lit_comp("Opens the list of all targets."), str8_lit_comp(""), str8_lit_comp("Targets"), RD_IconKind_Target, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("file_path_map"), str8_lit_comp("Opens the file path mapping editor."), str8_lit_comp(""), str8_lit_comp("File Path Map"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("auto_view_rules"), str8_lit_comp("Opens the auto view rule editor."), str8_lit_comp(""), str8_lit_comp("Auto View Rules"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("breakpoints"), str8_lit_comp("Opens the breakpoints view."), str8_lit_comp(""), str8_lit_comp("Breakpoints"), RD_IconKind_CircleFilled, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("watch_pins"), str8_lit_comp("Opens the watch pins view."), str8_lit_comp(""), str8_lit_comp("Watch Pins"), RD_IconKind_Pin, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("scheduler"), str8_lit_comp("Opens the scheduler view, for process and thread controls."), str8_lit_comp("threads,processes,targets"), str8_lit_comp("Scheduler"), RD_IconKind_Scheduler, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("call_stack"), str8_lit_comp("Opens the call stack view."), str8_lit_comp("callstack,thread,unwind"), str8_lit_comp("Call Stack"), RD_IconKind_Thread, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("modules"), str8_lit_comp("Opens the modules view."), str8_lit_comp(""), str8_lit_comp("Modules"), RD_IconKind_Module, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("watch"), str8_lit_comp("Opens a watch view."), str8_lit_comp(""), str8_lit_comp("Watch"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("locals"), str8_lit_comp("Opens a locals view."), str8_lit_comp(""), str8_lit_comp("Locals"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("registers"), str8_lit_comp("Opens a registers view."), str8_lit_comp(""), str8_lit_comp("Registers"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("globals"), str8_lit_comp("Opens a globals view."), str8_lit_comp(""), str8_lit_comp("Globals"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("thread_locals"), str8_lit_comp("Opens a thread locals view."), str8_lit_comp(""), str8_lit_comp("Thread Locals"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("types"), str8_lit_comp("Opens a types view."), str8_lit_comp(""), str8_lit_comp("Types"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("procedures"), str8_lit_comp("Opens a procedures view."), str8_lit_comp(""), str8_lit_comp("Procedures"), RD_IconKind_Binoculars, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("pending_file"), str8_lit_comp("Opens a view which asynchronously analyzes the file path parameter, then picks an appropriate viewer for it."), str8_lit_comp(""), str8_lit_comp("Pending File"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("disasm"), str8_lit_comp("Opens the disassembly view."), str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), RD_IconKind_Glasses, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("output"), str8_lit_comp("Opens an output view."), str8_lit_comp(""), str8_lit_comp("Output"), RD_IconKind_List, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("memory"), str8_lit_comp("Opens a memory view."), str8_lit_comp(""), str8_lit_comp("Memory"), RD_IconKind_Grid, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("exception_filters"), str8_lit_comp("Opens the exception filters view."), str8_lit_comp("exceptions,filters"), str8_lit_comp("Exception Filters"), RD_IconKind_Gear, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("settings"), str8_lit_comp("Opens the settings view."), str8_lit_comp("theme,color,scheme,options"), str8_lit_comp("Settings"), RD_IconKind_Gear, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("pick_file"), str8_lit_comp("Opens the file browser to pick a file."), str8_lit_comp(""), str8_lit_comp("Pick File"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("pick_folder"), str8_lit_comp("Opens the file browser to pick a folder."), str8_lit_comp(""), str8_lit_comp("Pick Folder"), RD_IconKind_FolderOpenFilled, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*1)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("pick_file_or_folder"), str8_lit_comp("Opens the file browser to pick a file or folder."), str8_lit_comp(""), str8_lit_comp("Pick File/Folder"), RD_IconKind_FileOutline, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*1)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("complete_query"), str8_lit_comp("Completes a query."), str8_lit_comp(""), str8_lit_comp("Complete Query"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("cancel_query"), str8_lit_comp("Cancels a query."), str8_lit_comp(""), str8_lit_comp("Cancel Query"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("toggle_dev_menu"), str8_lit_comp("Opens and closes the developer menu."), str8_lit_comp(""), str8_lit_comp("Toggle Developer Menu"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, -{ str8_lit_comp("log_marker"), str8_lit_comp("Logs a marker in the application log, to denote specific points in time within the log."), str8_lit_comp(""), str8_lit_comp("Log Marker"), RD_IconKind_Null, (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), RD_EntityKind_Nil, CTRL_EntityKind_Null}}, +{ str8_lit_comp("launch_and_run"), str8_lit_comp("Starts debugging a new instance of a target, then runs."), str8_lit_comp("launch,start,run,target"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("launch_and_step_into"), str8_lit_comp("Starts debugging a new instance of a target, then stops at the program's entry point."), str8_lit_comp("launch,start,entry,point"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("kill"), str8_lit_comp("Kills the specified existing attached process(es)."), str8_lit_comp("stop,kill"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp("query:processes"), str8_lit_comp(""), CTRL_EntityKind_Process}}, +{ str8_lit_comp("kill_all"), str8_lit_comp("Kills all attached processes."), str8_lit_comp("stop,kill,all"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("detach"), str8_lit_comp("Detaches the specified attached process(es)."), str8_lit_comp("detach"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp("query:processes"), str8_lit_comp(""), CTRL_EntityKind_Process}}, +{ str8_lit_comp("continue"), str8_lit_comp("Continues executing all attached processes."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_into_inst"), str8_lit_comp("Performs a step that goes into calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_over_inst"), str8_lit_comp("Performs a step that skips calls, at the instruction level."), str8_lit_comp("single,step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_into_line"), str8_lit_comp("Performs a step that goes into calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_over_line"), str8_lit_comp("Performs a step that skips calls, at the source code line level."), str8_lit_comp("step,thread"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_out"), str8_lit_comp("Runs to the end of the current function and exits it."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("halt"), str8_lit_comp("Halts all attached processes."), str8_lit_comp("pause"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("soft_halt_refresh"), str8_lit_comp("Interrupts all attached processes to collect data, and then resumes them."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_thread_ip"), str8_lit_comp("Sets the specified thread's instruction pointer at the specified address."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("run_to_line"), str8_lit_comp("Runs until a particular source line is hit."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("run"), str8_lit_comp("Runs all targets after starting them if they have not been started yet."), str8_lit_comp("play"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("restart"), str8_lit_comp("Kills all attached processes, then launches all active targets."), str8_lit_comp("restart,retry"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_into"), str8_lit_comp("Steps once, possibly into function calls, for either source lines or instructions (whichever is selected)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("step_over"), str8_lit_comp("Steps once, always over function calls, for either source lines or instructions."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("freeze_thread"), str8_lit_comp("Freezes the passed thread."), str8_lit_comp("callstack,unwind"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp("query:threads"), str8_lit_comp(""), CTRL_EntityKind_Thread}}, +{ str8_lit_comp("thaw_thread"), str8_lit_comp("Thaws the passed thread."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp("query:threads"), str8_lit_comp(""), CTRL_EntityKind_Thread}}, +{ str8_lit_comp("freeze_process"), str8_lit_comp("Freezes the passed process."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp("query:processes"), str8_lit_comp(""), CTRL_EntityKind_Process}}, +{ str8_lit_comp("thaw_process"), str8_lit_comp("Thaws the passed process."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Process, str8_lit_comp("query:processes"), str8_lit_comp(""), CTRL_EntityKind_Process}}, +{ str8_lit_comp("freeze_machine"), str8_lit_comp("Freezes the passed machine."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Machine, str8_lit_comp("query:machines"), str8_lit_comp(""), CTRL_EntityKind_Machine}}, +{ str8_lit_comp("thaw_machine"), str8_lit_comp("Thaws the passed machine."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Machine, str8_lit_comp("query:machines"), str8_lit_comp(""), CTRL_EntityKind_Machine}}, +{ str8_lit_comp("freeze_local_machine"), str8_lit_comp("Freezes the local machine."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("thaw_local_machine"), str8_lit_comp("Thaws the local machine."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("freeze_entity"), str8_lit_comp("Freezes an entity."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("thaw_entity"), str8_lit_comp("Thaws an entity."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_entity_color"), str8_lit_comp("Sets the passed entity's color."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_entity_name"), str8_lit_comp("Sets the passed entity's name."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("attach"), str8_lit_comp("Attaches to a process that is already running on the local machine."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_PID, str8_lit_comp("query:unattached_processes"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("exit"), str8_lit_comp("Exits the debugger."), str8_lit_comp("quit,close,abort"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_palette"), str8_lit_comp("Opens the palette."), str8_lit_comp("help,cmd,lister"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("run_command"), str8_lit_comp("Runs a command from the command palette."), str8_lit_comp("help,cmd"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_CmdName, str8_lit_comp("query:commands"), str8_lit_comp("commands"), CTRL_EntityKind_Null}}, +{ str8_lit_comp("os_event"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("select_thread"), str8_lit_comp("Selects a thread."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp("query:threads"), str8_lit_comp(""), CTRL_EntityKind_Thread}}, +{ str8_lit_comp("select_unwind"), str8_lit_comp("Selects an unwind frame number for the selected thread."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp("query:call_stack"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("up_one_frame"), str8_lit_comp("Selects the call stack frame above the currently selected."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("down_one_frame"), str8_lit_comp("Selects the call stack frame below the currently selected."), str8_lit_comp("callstack,unwind"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("select_entity"), str8_lit_comp("Selects a control entity."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("deselect_entity"), str8_lit_comp("Deselects a control entity."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("inc_window_font_size"), str8_lit_comp("Increases the window's font size by one point."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("dec_window_font_size"), str8_lit_comp("Decreases the window's font size by one point."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("inc_view_font_size"), str8_lit_comp("Increases the view's font size by one point."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("dec_view_font_size"), str8_lit_comp("Decreases the view's font size by one point."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_window"), str8_lit_comp("Opens a new window."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("window_settings"), str8_lit_comp("Opens settings for a window."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("close_window"), str8_lit_comp("Closes an opened window."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_fullscreen"), str8_lit_comp("Toggles fullscreen view on the active window."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("bring_to_front"), str8_lit_comp("Brings all windows to the front, and focuses the most recently focused window."), str8_lit_comp("top"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("popup_accept"), str8_lit_comp("Accepts the active popup prompt."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("popup_cancel"), str8_lit_comp("Cancels the active popup prompt."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("reset_to_default_bindings"), str8_lit_comp("Resets all keybindings to their defaults."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("reset_to_default_panels"), str8_lit_comp("Resets the window to the default panel layout."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("reset_to_compact_panels"), str8_lit_comp("Resets the window to the compact panel layout."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("reset_to_simple_panels"), str8_lit_comp("Resets the window to the simple panel layout."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_panel_left"), str8_lit_comp("Creates a new panel to the left of the active panel."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_panel_up"), str8_lit_comp("Creates a new panel at the top of the active panel."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_panel_right"), str8_lit_comp("Creates a new panel to the right of the active panel."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_panel_down"), str8_lit_comp("Creates a new panel at the bottom of the active panel."), str8_lit_comp("panel"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("split_panel"), str8_lit_comp("Creates a new panel in a given direction, and moves a tab to it, if specified."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("rotate_panel_columns"), str8_lit_comp("Rotates all panels at the closest column level of the panel hierarchy."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("next_panel"), str8_lit_comp("Cycles the active panel forward."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("prev_panel"), str8_lit_comp("Cycles the active panel backwards."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_panel"), str8_lit_comp("Focuses a new panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_panel_right"), str8_lit_comp("Focuses a panel rightward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_panel_left"), str8_lit_comp("Focuses a panel leftward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_panel_up"), str8_lit_comp("Focuses a panel upward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_panel_down"), str8_lit_comp("Focuses a panel downward of the currently focused panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("undo"), str8_lit_comp("Undoes the previous action."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("redo"), str8_lit_comp("Redoes the first previously undone action."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("go_back"), str8_lit_comp("Returns to the previously selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("go_forward"), str8_lit_comp("Returns to the next selected panel and tab in recorded history."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("close_panel"), str8_lit_comp("Closes the currently active panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("focus_tab"), str8_lit_comp("Focuses the passed tab within its containing panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("next_tab"), str8_lit_comp("Focuses the next tab on the active panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("prev_tab"), str8_lit_comp("Focuses the previous tab on the active panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_tab_right"), str8_lit_comp("Moves the selected tab right one slot."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_tab_left"), str8_lit_comp("Moves the selected tab left one slot."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_tab"), str8_lit_comp("Opens a new tab."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_CmdName, str8_lit_comp("query:tab_commands"), str8_lit_comp("commands"), CTRL_EntityKind_Null}}, +{ str8_lit_comp("build_tab"), str8_lit_comp("Opens a new tab with the parameterized view specification."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("duplicate_tab"), str8_lit_comp("Duplicates a tab."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Tab, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("copy_tab_full_path"), str8_lit_comp("Copies the full path of the file being viewed by this tab."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Tab, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("close_tab"), str8_lit_comp("Closes the currently opened tab."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Tab, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_view"), str8_lit_comp("Moves a view to a new panel."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("tab_bar_top"), str8_lit_comp("Anchors a panel's tab bar to the top of the panel."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("tab_bar_bottom"), str8_lit_comp("Anchors a panel's tab bar to the bottom of the panel."), str8_lit_comp(""), str8_lit_comp("$tab,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("tab_settings"), str8_lit_comp("Opens settings for a tab."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_current_path"), str8_lit_comp("Sets the debugger's current path, which is used as a starting point when browsing for files."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open"), str8_lit_comp("Opens a file."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("switch"), str8_lit_comp("Switches to a recent file."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:recent_files"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("switch_to_partner_file"), str8_lit_comp("Switches to the focused file's partner; or from header to implementation or vice versa."), str8_lit_comp("code,source,file"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("record_file_in_project"), str8_lit_comp("Records the passed file path as a recent file in the currently loaded project."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("show_file_in_explorer"), str8_lit_comp("Opens the operating system's file explorer and shows the selected file."), str8_lit_comp(""), str8_lit_comp("$file,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("go_to_disassembly"), str8_lit_comp("Goes to the disassembly, if any, for a given source code line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("go_to_source"), str8_lit_comp("Goes to the source code, if any, for a given disassembly line."), str8_lit_comp("code,source,disassembly,disasm"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_file_replacement_path"), str8_lit_comp("Sets the path which should be used as the replacement for the passed file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_user"), str8_lit_comp("Creates a new user file, and sets the current user path as that file's path."), str8_lit_comp("new,user,project,layout"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("new_project"), str8_lit_comp("Creates a new project file, and sets the current project path as that file's path."), str8_lit_comp("new,user,project,layout"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_user"), str8_lit_comp("Opens a user file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("load,user,project,layout"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_project"), str8_lit_comp("Opens a project file path, immediately loading it, and begins autosaving to it."), str8_lit_comp("project,project,session"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("open_recent_project"), str8_lit_comp("Opens a recently used project file."), str8_lit_comp("project,project,session"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:recent_projects"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("save_user"), str8_lit_comp("Saves user data to a file, and sets the current user path as that path."), str8_lit_comp("load,user,project,layout"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("save_project"), str8_lit_comp("Saves project data to a file, and sets the current project path as that path."), str8_lit_comp("project,project,session"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("write_user_data"), str8_lit_comp("Writes user data to the active user file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("write_project_data"), str8_lit_comp("Writes project data to the active project file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("user_settings"), str8_lit_comp("Opens user settings."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("project_settings"), str8_lit_comp("Opens project settings."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("edit"), str8_lit_comp("Edits the current selection."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("accept"), str8_lit_comp("Accepts current changes, or answers prompts in the affirmative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("cancel"), str8_lit_comp("Rejects current changes, exits temporary menus, or answers prompts in the negative."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_left"), str8_lit_comp("Moves the cursor or selection left."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_right"), str8_lit_comp("Moves the cursor or selection right."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up"), str8_lit_comp("Moves the cursor or selection up."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down"), str8_lit_comp("Moves the cursor or selection down."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_left_select"), str8_lit_comp("Moves the cursor or selection left, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_right_select"), str8_lit_comp("Moves the cursor or selection right, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_select"), str8_lit_comp("Moves the cursor or selection up, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_select"), str8_lit_comp("Moves the cursor or selection down, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_left_chunk"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_right_chunk"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_chunk"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_chunk"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_page"), str8_lit_comp("Moves the cursor or selection up one page."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_page"), str8_lit_comp("Moves the cursor or selection down one page."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_whole"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_whole"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_left_chunk_select"), str8_lit_comp("Moves the cursor or selection left one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_right_chunk_select"), str8_lit_comp("Moves the cursor or selection right one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_chunk_select"), str8_lit_comp("Moves the cursor or selection up one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_chunk_select"), str8_lit_comp("Moves the cursor or selection down one chunk."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_page_select"), str8_lit_comp("Moves the cursor or selection up one page, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_page_select"), str8_lit_comp("Moves the cursor or selection down one page, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_whole_select"), str8_lit_comp("Moves the cursor or selection to the beginning of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_whole_select"), str8_lit_comp("Moves the cursor or selection to the end of the relevant content, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_up_reorder"), str8_lit_comp("Moves the cursor or selection up, while swapping the currently selected element with that upward."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_down_reorder"), str8_lit_comp("Moves the cursor or selection down, while swapping the currently selected element with that downward."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_home"), str8_lit_comp("Moves the cursor to the beginning of the line."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_end"), str8_lit_comp("Moves the cursor to the end of the line."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_home_select"), str8_lit_comp("Moves the cursor to the beginning of the line, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_end_select"), str8_lit_comp("Moves the cursor to the end of the line, while selecting."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("select_all"), str8_lit_comp("Selects everything possible."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("delete_single"), str8_lit_comp("Deletes a single element to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("delete_chunk"), str8_lit_comp("Deletes a chunk to the right of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("backspace_single"), str8_lit_comp("Deletes a single element to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("backspace_chunk"), str8_lit_comp("Deletes a chunk to the left of the cursor, or the active selection."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("copy"), str8_lit_comp("Copies the active selection to the clipboard."), str8_lit_comp(""), str8_lit_comp("$text_rng,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*1), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("cut"), str8_lit_comp("Copies the active selection to the clipboard, then deletes it."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("paste"), str8_lit_comp("Pastes the current contents of the clipboard."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("insert_text"), str8_lit_comp("Inserts the text that was used to cause this command."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_next"), str8_lit_comp("Moves the cursor or selection to the next element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("move_prev"), str8_lit_comp("Moves the cursor or selection to the previous element."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("goto_line"), str8_lit_comp("Jumps to a line number in the current code file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Cursor, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("goto_address"), str8_lit_comp("Jumps to an address in the current memory or disassembly view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_Vaddr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("center_cursor"), str8_lit_comp("Snaps the current code view to center the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("contain_cursor"), str8_lit_comp("Snaps the current code view to contain the cursor."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("find_next"), str8_lit_comp("Searches the current code file forward (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("find_prev"), str8_lit_comp("Searches the current code file backwards (from the cursor) for the last searched string."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("find_thread"), str8_lit_comp("Jumps to the passed thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Thread, str8_lit_comp("query:threads"), str8_lit_comp(""), CTRL_EntityKind_Thread}}, +{ str8_lit_comp("find_selected_thread"), str8_lit_comp("Jumps to the selected thread in either source code, disassembly, or both if they're already open."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("goto_name"), str8_lit_comp("Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp("query:procedures"), str8_lit_comp("symbol_lister"), CTRL_EntityKind_Null}}, +{ str8_lit_comp("goto_name_at_cursor"), str8_lit_comp("Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_watch_expr"), str8_lit_comp("Adds or removes an expression to an opened watch view."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_watch_expr_at_cursor"), str8_lit_comp("Adds or removes the expression that the cursor or selection is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_watch_expr_at_mouse"), str8_lit_comp("Adds or removes the expression that the mouse is currently over to an opened watch view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("enable_cfg"), str8_lit_comp("Enables a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("disable_cfg"), str8_lit_comp("Disables a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("select_cfg"), str8_lit_comp("Selects a config tree, disabling all others of the same kind."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("deselect_cfg"), str8_lit_comp("Deselects a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("remove_cfg"), str8_lit_comp("Removes a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("name_cfg"), str8_lit_comp("Equips a config tree with a label."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("condition_cfg"), str8_lit_comp("Equips a config tree with a condition string."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("duplicate_cfg"), str8_lit_comp("Duplicates a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("relocate_cfg"), str8_lit_comp("Relocates a config tree."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("save_cfg_to_project"), str8_lit_comp("Saves the config tree to the project."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_breakpoint"), str8_lit_comp("Places a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_address_breakpoint"), str8_lit_comp("Places a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("Places a breakpoint on the first address of the specified function."), str8_lit_comp(""), str8_lit_comp("$breakpoints,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp("query:procedures"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_breakpoint"), str8_lit_comp("Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("enable_breakpoint"), str8_lit_comp("Enables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("disable_breakpoint"), str8_lit_comp("Disables a breakpoint."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:breakpoints"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("clear_breakpoints"), str8_lit_comp("Removes all breakpoints."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_watch_pin"), str8_lit_comp("Places a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp("$watch_pins,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_watch_pin"), str8_lit_comp("Places or removes a watch pin at a given location (file path and line number or address)."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Expr, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_type_view"), str8_lit_comp("Adds a new type view."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_file_path_map"), str8_lit_comp("Adds a new file path map."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("edit_user_theme"), str8_lit_comp("Edits the current user's theme."), str8_lit_comp("color"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_String, str8_lit_comp("query:themes"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("edit_project_theme"), str8_lit_comp("Edits the current project's theme."), str8_lit_comp("color"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_String, str8_lit_comp("query:themes"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_theme_color"), str8_lit_comp("Adds a new theme color."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("fork_theme"), str8_lit_comp("Imports all colors from the current theme so they can be individually edited."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("save_theme"), str8_lit_comp("Saves all theme colors to a new theme file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("save_and_set_theme"), str8_lit_comp("Saves all theme colors to a new theme file, and then sets that theme as the selected theme."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("set_next_statement"), str8_lit_comp("Sets the selected thread's instruction pointer to the cursor's position."), str8_lit_comp(""), str8_lit_comp("$text_pt,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*1)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("add_target"), str8_lit_comp("Adds a new target."), str8_lit_comp("application,executable,debug"), str8_lit_comp("$targets,"), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("select_target"), str8_lit_comp("Selects a target."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("enable_target"), str8_lit_comp("Enables a target, in addition to all targets currently enabled."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("disable_target"), str8_lit_comp("Disables a target."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_Cfg, str8_lit_comp("query:targets"), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("register_as_jit_debugger"), str8_lit_comp("Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("find_code_location"), str8_lit_comp("Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("search"), str8_lit_comp("Begins searching within the active interface."), str8_lit_comp("sort,search,filter,find"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*1)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("search_backwards"), str8_lit_comp("Begins searching backwards within the active interface."), str8_lit_comp("sort,search,filter,find"), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*1)|(RD_QueryFlag_KeepOldInput*1)|(RD_QueryFlag_SelectOldInput*1)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*1), RD_RegSlot_String, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("pick_file"), str8_lit_comp("Opens the file browser to pick a file."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("pick_folder"), str8_lit_comp("Opens the file browser to pick a folder."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*1)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("pick_file_or_folder"), str8_lit_comp("Opens the file browser to pick a file or folder."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*1)|(RD_QueryFlag_AllowFolders*1)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*1)|(RD_QueryFlag_Required*1), RD_RegSlot_FilePath, str8_lit_comp("folder:\"$input\""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("push_query"), str8_lit_comp("Opens a new temporary query interface."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("complete_query"), str8_lit_comp("Completes and closes a query."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("cancel_query"), str8_lit_comp("Closes a query."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("update_query"), str8_lit_comp("Updates a query input."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*0)|(RD_CmdKindFlag_ListInIPCDocs*0)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("toggle_dev_menu"), str8_lit_comp("Opens and closes the developer menu."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("log_marker"), str8_lit_comp("Logs a marker in the application log, to denote specific points in time within the log."), str8_lit_comp(""), str8_lit_comp(""), (RD_CmdKindFlag_ListInUI*1)|(RD_CmdKindFlag_ListInIPCDocs*1)|(RD_CmdKindFlag_ListInTextPt*0)|(RD_CmdKindFlag_ListInTextRng*0), {(RD_QueryFlag_AllowFiles*0)|(RD_QueryFlag_AllowFolders*0)|(RD_QueryFlag_CodeInput*0)|(RD_QueryFlag_KeepOldInput*0)|(RD_QueryFlag_SelectOldInput*0)|(RD_QueryFlag_Floating*0)|(RD_QueryFlag_Required*0), RD_RegSlot_Null, str8_lit_comp(""), str8_lit_comp(""), CTRL_EntityKind_Null}}, +{ str8_lit_comp("watches"), str8_lit_comp("Opens a Watch tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("locals"), str8_lit_comp("Opens a Locals tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("registers"), str8_lit_comp("Opens a Registers tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("globals"), str8_lit_comp("Opens a Globals tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("thread_locals"), str8_lit_comp("Opens a Thread Locals tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("types"), str8_lit_comp("Opens a Types tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("procedures"), str8_lit_comp("Opens a Procedures tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("call_stack"), str8_lit_comp("Opens a Call Stack tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("targets"), str8_lit_comp("Opens a Targets tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("breakpoints"), str8_lit_comp("Opens a Breakpoints tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("watch_pins"), str8_lit_comp("Opens a Watch Pins tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("threads"), str8_lit_comp("Opens a Threads tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("processes"), str8_lit_comp("Opens a Processes tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("machines"), str8_lit_comp("Opens a Machines tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("modules"), str8_lit_comp("Opens a Modules tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("file_path_maps"), str8_lit_comp("Opens a File Path Map tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("type_views"), str8_lit_comp("Opens a Type Views tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("output"), str8_lit_comp("Opens a Output tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("text"), str8_lit_comp("Opens a Text tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("disasm"), str8_lit_comp("Opens a Disassembly tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("memory"), str8_lit_comp("Opens a Memory tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("bitmap"), str8_lit_comp("Opens a Bitmap tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("color"), str8_lit_comp("Opens a Color tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, +{ str8_lit_comp("geo3d"), str8_lit_comp("Opens a Geometry (3D) tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}, }; -RD_StringBindingPair rd_default_binding_table[110] = +struct {String8 string; RD_Binding binding;} rd_default_binding_table[116] = { {str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_Modifier_Shift }}, {str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_Modifier_Alt}}, @@ -454,17 +731,14 @@ RD_StringBindingPair rd_default_binding_table[110] = {str8_lit_comp("step_out"), {OS_Key_F11, 0 |OS_Modifier_Shift }}, {str8_lit_comp("halt"), {OS_Key_X, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("halt"), {OS_Key_Pause, 0 }}, -{str8_lit_comp("soft_halt_refresh"), {OS_Key_R, 0 |OS_Modifier_Alt}}, {str8_lit_comp("run"), {OS_Key_F5, 0 }}, {str8_lit_comp("restart"), {OS_Key_F5, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("step_into"), {OS_Key_F11, 0 }}, {str8_lit_comp("step_over"), {OS_Key_F10, 0 }}, -{str8_lit_comp("run_to_cursor"), {OS_Key_F10, 0 |OS_Modifier_Ctrl }}, +{str8_lit_comp("run_to_line"), {OS_Key_F10, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("set_next_statement"), {OS_Key_F10, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, -{str8_lit_comp("inc_ui_font_scale"), {OS_Key_Equal, 0 |OS_Modifier_Alt}}, -{str8_lit_comp("dec_ui_font_scale"), {OS_Key_Minus, 0 |OS_Modifier_Alt}}, -{str8_lit_comp("inc_code_font_scale"), {OS_Key_Equal, 0 |OS_Modifier_Shift |OS_Modifier_Alt}}, -{str8_lit_comp("dec_code_font_scale"), {OS_Key_Minus, 0 |OS_Modifier_Shift |OS_Modifier_Alt}}, +{str8_lit_comp("inc_window_font_size"), {OS_Key_Equal, 0 |OS_Modifier_Alt}}, +{str8_lit_comp("dec_window_font_size"), {OS_Key_Minus, 0 |OS_Modifier_Alt}}, {str8_lit_comp("window"), {OS_Key_N, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("toggle_fullscreen"), {OS_Key_Return, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("new_panel_right"), {OS_Key_P, 0 |OS_Modifier_Ctrl }}, @@ -490,14 +764,19 @@ RD_StringBindingPair rd_default_binding_table[110] = {str8_lit_comp("close_tab"), {OS_Key_W, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("tab_bar_top"), {OS_Key_Up, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, {str8_lit_comp("tab_bar_bottom"), {OS_Key_Down, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, +{str8_lit_comp("open_tab"), {OS_Key_T, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("open"), {OS_Key_O, 0 |OS_Modifier_Ctrl }}, -{str8_lit_comp("reload_active"), {OS_Key_R, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("switch"), {OS_Key_I, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("switch_to_partner_file"), {OS_Key_O, 0 |OS_Modifier_Alt}}, +{str8_lit_comp("open_user"), {OS_Key_N, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, +{str8_lit_comp("open_project"), {OS_Key_N, 0 |OS_Modifier_Ctrl |OS_Modifier_Alt}}, {str8_lit_comp("open_user"), {OS_Key_O, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, {str8_lit_comp("open_project"), {OS_Key_O, 0 |OS_Modifier_Ctrl |OS_Modifier_Alt}}, +{str8_lit_comp("save_user"), {OS_Key_S, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, +{str8_lit_comp("save_project"), {OS_Key_S, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("edit"), {OS_Key_F2, 0 }}, {str8_lit_comp("accept"), {OS_Key_Return, 0 }}, +{str8_lit_comp("accept"), {OS_Key_Space, 0 }}, {str8_lit_comp("cancel"), {OS_Key_Esc, 0 }}, {str8_lit_comp("move_left"), {OS_Key_Left, 0 }}, {str8_lit_comp("move_right"), {OS_Key_Right, 0 }}, @@ -540,10 +819,12 @@ RD_StringBindingPair rd_default_binding_table[110] = {str8_lit_comp("paste"), {OS_Key_V, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("paste"), {OS_Key_Insert, 0 |OS_Modifier_Shift }}, {str8_lit_comp("insert_text"), {OS_Key_Null, 0 }}, +{str8_lit_comp("move_next"), {OS_Key_Tab, 0 }}, +{str8_lit_comp("move_prev"), {OS_Key_Tab, 0 |OS_Modifier_Shift }}, {str8_lit_comp("goto_line"), {OS_Key_G, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("goto_address"), {OS_Key_G, 0 |OS_Modifier_Alt}}, -{str8_lit_comp("find_text_forward"), {OS_Key_F, 0 |OS_Modifier_Ctrl }}, -{str8_lit_comp("find_text_backward"), {OS_Key_R, 0 |OS_Modifier_Ctrl }}, +{str8_lit_comp("search"), {OS_Key_F, 0 |OS_Modifier_Ctrl }}, +{str8_lit_comp("search_backwards"), {OS_Key_R, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("find_next"), {OS_Key_F3, 0 }}, {str8_lit_comp("find_prev"), {OS_Key_F3, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("find_selected_thread"), {OS_Key_F4, 0 }}, @@ -553,11 +834,13 @@ RD_StringBindingPair rd_default_binding_table[110] = {str8_lit_comp("toggle_watch_expr_at_mouse"), {OS_Key_D, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("toggle_watch_pin"), {OS_Key_F9, 0 |OS_Modifier_Ctrl }}, {str8_lit_comp("toggle_breakpoint"), {OS_Key_F9, 0 }}, -{str8_lit_comp("add_target"), {OS_Key_T, 0 |OS_Modifier_Ctrl }}, +{str8_lit_comp("add_address_breakpoint"), {OS_Key_F9, 0 |OS_Modifier_Shift }}, +{str8_lit_comp("add_function_breakpoint"), {OS_Key_F9, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("attach"), {OS_Key_F6, 0 |OS_Modifier_Shift }}, -{str8_lit_comp("filter"), {OS_Key_Slash, 0 |OS_Modifier_Ctrl }}, -{str8_lit_comp("run_command"), {OS_Key_F1, 0 }}, +{str8_lit_comp("open_palette"), {OS_Key_F1, 0 }}, +{str8_lit_comp("open_palette"), {OS_Key_P, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift }}, {str8_lit_comp("log_marker"), {OS_Key_M, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, +{str8_lit_comp("toggle_dev_menu"), {OS_Key_D, 0 |OS_Modifier_Ctrl |OS_Modifier_Shift |OS_Modifier_Alt}}, }; String8 rd_binding_version_remap_old_name_table[8] = @@ -584,7 +867,7 @@ str8_lit_comp("add_function_breakpoint"), str8_lit_comp("toggle_breakpoint"), }; -String8 rd_icon_kind_text_table[69] = +String8 rd_icon_kind_text_table[75] = { str8_lit_comp(""), str8_lit_comp("b"), @@ -614,6 +897,7 @@ str8_lit_comp("O"), str8_lit_comp("o"), str8_lit_comp("!"), str8_lit_comp("1"), +str8_lit_comp("V"), str8_lit_comp("<"), str8_lit_comp(">"), str8_lit_comp("^"), @@ -654,234 +938,33 @@ str8_lit_comp("A"), str8_lit_comp("?"), str8_lit_comp("4"), str8_lit_comp("5"), -str8_lit_comp("c"), +str8_lit_comp("6"), +str8_lit_comp("&"), +str8_lit_comp("*"), +str8_lit_comp("("), +str8_lit_comp(")"), +str8_lit_comp("#"), }; -String8 rd_collection_name_table[18] = +String8 rd_code_color_slot_name_table[14] = { -str8_lit_comp("watches"), -str8_lit_comp("targets"), -str8_lit_comp("breakpoints"), -str8_lit_comp("watch_pins"), -str8_lit_comp("file_path_maps"), -str8_lit_comp("auto_view_rules"), -str8_lit_comp("machines"), -str8_lit_comp("processes"), -str8_lit_comp("threads"), -str8_lit_comp("modules"), -str8_lit_comp("scheduler_machine"), -str8_lit_comp("scheduler_process"), -str8_lit_comp("locals"), -str8_lit_comp("registers"), -str8_lit_comp("globals"), -str8_lit_comp("thread_locals"), -str8_lit_comp("types"), -str8_lit_comp("procedures"), +str8_lit_comp("code_default"), +str8_lit_comp("code_symbol"), +str8_lit_comp("code_type"), +str8_lit_comp("code_local"), +str8_lit_comp("code_register"), +str8_lit_comp("code_keyword"), +str8_lit_comp("code_delimiter_or_operator"), +str8_lit_comp("code_numeric"), +str8_lit_comp("code_numeric_alt_digit_group"), +str8_lit_comp("code_string"), +str8_lit_comp("code_meta"), +str8_lit_comp("code_comment"), +str8_lit_comp("code_line_numbers"), +str8_lit_comp("code_line_numbers_selected"), }; -RD_EntityKind rd_collection_entity_kind_table[18] = -{ -RD_EntityKind_Watch, -RD_EntityKind_Target, -RD_EntityKind_Breakpoint, -RD_EntityKind_WatchPin, -RD_EntityKind_FilePathMap, -RD_EntityKind_AutoViewRule, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -RD_EntityKind_Nil, -}; - -CTRL_EntityKind rd_collection_ctrl_entity_kind_table[18] = -{ -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Machine, -CTRL_EntityKind_Process, -CTRL_EntityKind_Thread, -CTRL_EntityKind_Module, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -CTRL_EntityKind_Null, -}; - -EV_ViewRuleExprExpandInfoHookFunctionType * rd_collection_expr_expand_info_hook_function_table[18] = -{ -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(watches), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(targets), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(breakpoints), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(file_path_maps), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(auto_view_rules), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(machines), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(processes), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(threads), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(modules), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(scheduler_machine), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(scheduler_process), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(locals), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(registers), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(globals), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(thread_locals), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(types), -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(procedures), -}; - -EV_ViewRuleExprExpandRangeInfoHookFunctionType * rd_collection_expr_expand_range_info_hook_function_table[18] = -{ -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(watches), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(targets), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(breakpoints), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(file_path_maps), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(auto_view_rules), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(machines), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(processes), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(threads), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(modules), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(scheduler_machine), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(scheduler_process), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(locals), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(registers), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(globals), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(thread_locals), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(types), -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(procedures), -}; - -EV_ViewRuleExprExpandIDFromNumHookFunctionType * rd_collection_expr_expand_id_from_num_hook_function_table[18] = -{ -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(targets), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(breakpoints), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(file_path_maps), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(auto_view_rules), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(machines), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(processes), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(threads), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(modules), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(scheduler_machine), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(scheduler_process), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(globals), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(thread_locals), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(types), -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(procedures), -}; - -EV_ViewRuleExprExpandIDFromNumHookFunctionType * rd_collection_expr_expand_num_from_id_hook_function_table[18] = -{ -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(targets), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(breakpoints), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watch_pins), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(file_path_maps), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(auto_view_rules), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(machines), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(processes), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(threads), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(modules), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(scheduler_machine), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(scheduler_process), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(globals), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(thread_locals), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(types), -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(procedures), -}; - -RD_ViewRuleInfo rd_view_rule_kind_info_table[35] = -{ -{{0}, {0}, {0}, {0}, RD_IconKind_Null, 0, EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(null)}, -{str8_lit_comp("empty"), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), RD_IconKind_Null, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(empty)}, -{str8_lit_comp("getting_started"), str8_lit_comp(""), str8_lit_comp("Getting Started"), str8_lit_comp(""), RD_IconKind_QuestionMark, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(getting_started)}, -{str8_lit_comp("exception_filters"), str8_lit_comp("An interface which controls whether or not the debugger will halt attached processes upon encountering specific exception codes for the first time."), str8_lit_comp("Exception Filters"), str8_lit_comp(""), RD_IconKind_Gear, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(exception_filters)}, -{str8_lit_comp("settings"), str8_lit_comp("An interface to modify general settings for the debugger's appearance and behavior."), str8_lit_comp("Settings"), str8_lit_comp(""), RD_IconKind_Gear, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(settings)}, -{str8_lit_comp("pending_file"), str8_lit_comp(""), str8_lit_comp("Pending File"), str8_lit_comp(""), RD_IconKind_FileOutline, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(pending_file)}, -{str8_lit_comp("commands"), str8_lit_comp(""), str8_lit_comp("Commands"), str8_lit_comp(""), RD_IconKind_List, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(commands)}, -{str8_lit_comp("file_system"), str8_lit_comp(""), str8_lit_comp("File System"), str8_lit_comp(""), RD_IconKind_FileOutline, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(file_system)}, -{str8_lit_comp("system_processes"), str8_lit_comp(""), str8_lit_comp("System Processes"), str8_lit_comp(""), RD_IconKind_Null, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(system_processes)}, -{str8_lit_comp("entity_lister"), str8_lit_comp(""), str8_lit_comp("Entities"), str8_lit_comp(""), RD_IconKind_Null, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(entity_lister)}, -{str8_lit_comp("ctrl_entity_lister"), str8_lit_comp(""), str8_lit_comp("Control Entities"), str8_lit_comp(""), RD_IconKind_Null, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(ctrl_entity_lister)}, -{str8_lit_comp("symbol_lister"), str8_lit_comp(""), str8_lit_comp("Symbols"), str8_lit_comp(""), RD_IconKind_Null, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(symbol_lister)}, -{str8_lit_comp("watch"), str8_lit_comp("The familiar 'watch window' debugger interface. Allows the inputting of a number of expressions. Each expression in the table is evaluated within the context of the selected thread's selected call stack frame. If applicable (depending on visualization rules and the expression's type), these expressions may be hierarchically expanded, which displays children as more rows in the table. The values of these expressions may also be edited, and if possible, can be used to write to registers or memory in attached processes. Also contains a new *view rule* column, not found in other major debuggers, which allows per-row specification of various visualization rules. These view rules may be used to visualize and inspect the evaluation of expressions in a variety of ways. To learn more, read the 'View Rules' section."), str8_lit_comp("Watch"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(watch)}, -{str8_lit_comp("locals"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with local variables found within the selected call stack frame of the selected thread, according to the associated debug info. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Locals"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(locals)}, -{str8_lit_comp("registers"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with all register names according to the selected thread's architecture. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Registers"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(registers)}, -{str8_lit_comp("globals"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with all global variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Globals"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(globals)}, -{str8_lit_comp("thread_locals"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with all thread local variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Thread Locals"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(thread_locals)}, -{str8_lit_comp("types"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with all types within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Types"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(types)}, -{str8_lit_comp("procedures"), str8_lit_comp("Nearly identical to `Watch`, but automatically filled with all procedures within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table."), str8_lit_comp("Procedures"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(procedures)}, -{str8_lit_comp("targets"), str8_lit_comp("Displays a list of all targets, as well as controls for enabling, disabling, launching, editing, or deleting each target. For more information on targets, read the `Targets` section."), str8_lit_comp("Targets"), str8_lit_comp(""), RD_IconKind_Target, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(targets)}, -{str8_lit_comp("file_path_map"), str8_lit_comp("Displays a table of *path maps*. Each path map is a pair of file or folder paths, one being a 'source' path, and one being a 'destination' path. These pairs are used by the debugger when automatically searching for specific files - for instance, when attempting to snap to a source code location specified by debug info. If debug info refers to a path on the machine on which a target executable was originally built, but that path is not valid on the debugger machine, but some alternative path exists, then path maps may be used to redirect the debugger from the debug info's specified paths to the associated appropriate debugger machine file paths."), str8_lit_comp("File Path Map"), str8_lit_comp(""), RD_IconKind_FileOutline, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(file_path_map)}, -{str8_lit_comp("auto_view_rules"), str8_lit_comp("Displays a table of *auto view rules*. Each *auto view rule* is a pair, with one element being a type, and the other being a view rule, which should be automatically applied to expressions of that type, when possible."), str8_lit_comp("Auto View Rules"), str8_lit_comp(""), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(auto_view_rules)}, -{str8_lit_comp("breakpoints"), str8_lit_comp("Displays a table of all breakpoints, containing information about each breakpoint's name, location, and hit count. Also contains per-breakpoint controls for enabling, deleting, or editing each breakpoint. For more information on breakpoints and their features, read the 'Breakpoints' section."), str8_lit_comp("Breakpoints"), str8_lit_comp(""), RD_IconKind_CircleFilled, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(breakpoints)}, -{str8_lit_comp("watch_pins"), str8_lit_comp("Displays a table of all watch pins (watched expressions, like those found in `Watch`, but instead of being within a table, being pinned to some source code location, like breakpoints). This table contains each pin's name, location, and controls for editing or deleting each pin."), str8_lit_comp("Watch Pins"), str8_lit_comp(""), RD_IconKind_Pin, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(watch_pins)}, -{str8_lit_comp("scheduler"), str8_lit_comp("Displays all processes and threads to which the debugger is currently attached, and contains controls for selecting and freezing threads."), str8_lit_comp("Scheduler"), str8_lit_comp(""), RD_IconKind_Scheduler, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(scheduler)}, -{str8_lit_comp("call_stack"), str8_lit_comp("Displays the call stack of the currently selected thread. Each frame in the call stack contains the associated module, function name, and return address. Allows selection of a particular call stack frame other than the top."), str8_lit_comp("Call Stack"), str8_lit_comp(""), RD_IconKind_Thread, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(call_stack)}, -{str8_lit_comp("modules"), str8_lit_comp("Displays a table of all modules currently loaded by any process to which the debugger is attached. This table displays each module's name, virtual address range in the containing process' address space, and which debug info file is being used by the debugger for the associated module."), str8_lit_comp("Modules"), str8_lit_comp(""), RD_IconKind_Module, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*1|RD_ViewRuleInfoFlag_FilterIsCode*1|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*1|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(modules)}, -{str8_lit_comp("text"), str8_lit_comp(""), str8_lit_comp("Text"), str8_lit_comp("x:{'lang':lang, 'size':expr}"), RD_IconKind_FileOutline, (RD_ViewRuleInfoFlag_ShowInDocs*0|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(text) , RD_VIEW_RULE_UI_FUNCTION_NAME(text)}, -{str8_lit_comp("disasm"), str8_lit_comp("Displays disassembled instructions in a textual form from the selected thread's containing process virtual address space."), str8_lit_comp("Disassembly"), str8_lit_comp("x:{'arch':arch, 'size':expr}"), RD_IconKind_Glasses, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(disasm) , RD_VIEW_RULE_UI_FUNCTION_NAME(disasm)}, -{str8_lit_comp("output"), str8_lit_comp("Displays debug strings, output from attached processes."), str8_lit_comp("Output"), str8_lit_comp(""), RD_IconKind_List, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*0|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(output)}, -{str8_lit_comp("memory"), str8_lit_comp("A hex-editor-like grid interface for viewing memory."), str8_lit_comp("Memory"), str8_lit_comp("x:{'size':expr}"), RD_IconKind_Grid, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(memory) , RD_VIEW_RULE_UI_FUNCTION_NAME(memory)}, -{str8_lit_comp("bitmap"), str8_lit_comp("Visualizes memory as a bitmap."), str8_lit_comp("Bitmap"), str8_lit_comp("x:{'w':expr, 'h':expr, 'fmt':tex2dformat}"), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(bitmap) , RD_VIEW_RULE_UI_FUNCTION_NAME(bitmap)}, -{str8_lit_comp("checkbox"), str8_lit_comp("Visualizes memory as an RGBA color."), str8_lit_comp("Checkbox"), str8_lit_comp(""), RD_IconKind_CheckFilled, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*1|RD_ViewRuleInfoFlag_CanExpand*0), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(checkbox)}, -{str8_lit_comp("color_rgba"), str8_lit_comp("Visualizes memory as an RGBA color."), str8_lit_comp("Color (RGBA)"), str8_lit_comp(""), RD_IconKind_Palette, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*1|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(color_rgba) , RD_VIEW_RULE_UI_FUNCTION_NAME(color_rgba)}, -{str8_lit_comp("geo3d"), str8_lit_comp("Visualizes memory as 3D geometry."), str8_lit_comp("Geometry (3D)"), str8_lit_comp("x:{'count':expr, 'vtx':expr, 'vtx_size':expr}"), RD_IconKind_Binoculars, (RD_ViewRuleInfoFlag_ShowInDocs*1|RD_ViewRuleInfoFlag_CanFilter*0|RD_ViewRuleInfoFlag_FilterIsCode*0|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*0|RD_ViewRuleInfoFlag_CanUseInWatchTable*1|RD_ViewRuleInfoFlag_CanFillValueCell*0|RD_ViewRuleInfoFlag_CanExpand*1), EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(geo3d) , RD_VIEW_RULE_UI_FUNCTION_NAME(geo3d)}, -}; - -RD_IconKind rd_entity_kind_icon_kind_table[27] = -{ -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Binoculars, -RD_IconKind_FileOutline, -RD_IconKind_Pin, -RD_IconKind_Binoculars, -RD_IconKind_Binoculars, -RD_IconKind_CircleFilled, -RD_IconKind_CircleFilled, -RD_IconKind_Null, -RD_IconKind_Target, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Window, -RD_IconKind_XSplit, -RD_IconKind_Null, -RD_IconKind_Briefcase, -RD_IconKind_FileOutline, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -RD_IconKind_Null, -}; - -String8 rd_theme_preset_display_string_table[9] = +String8 rd_theme_preset_display_string_table[11] = { str8_lit_comp("Default (Dark)"), str8_lit_comp("Default (Light)"), @@ -890,11 +973,13 @@ str8_lit_comp("VS (Light)"), str8_lit_comp("Solarized (Dark)"), str8_lit_comp("Solarized (Light)"), str8_lit_comp("Handmade Hero"), +str8_lit_comp("Naysayer"), str8_lit_comp("4coder"), +str8_lit_comp("Grove"), str8_lit_comp("Far Manager"), }; -String8 rd_theme_preset_code_string_table[9] = +String8 rd_theme_preset_code_string_table[11] = { str8_lit_comp("default_dark"), str8_lit_comp("default_light"), @@ -903,1068 +988,25 @@ str8_lit_comp("vs_light"), str8_lit_comp("solarized_dark"), str8_lit_comp("solarized_light"), str8_lit_comp("handmade_hero"), +str8_lit_comp("naysayer"), str8_lit_comp("four_coder"), +str8_lit_comp("grove"), str8_lit_comp("far_manager"), }; -String8 rd_theme_color_version_remap_old_name_table[22] = +String8 rd_theme_preset_cfg_string_table[11] = { -str8_lit_comp("plain_text"), -str8_lit_comp("plain_background"), -str8_lit_comp("plain_border"), -str8_lit_comp("plain_overlay"), -str8_lit_comp("code_function"), -str8_lit_comp("code_symbol"), -str8_lit_comp("code_numeric"), -str8_lit_comp("line_info_0"), -str8_lit_comp("line_info_1"), -str8_lit_comp("line_info_2"), -str8_lit_comp("line_info_3"), -str8_lit_comp("alt_background"), -str8_lit_comp("alt_border"), -str8_lit_comp("tab_inactive"), -str8_lit_comp("tab_active"), -str8_lit_comp("weak_text"), -str8_lit_comp("text_selection"), -str8_lit_comp("cursor"), -str8_lit_comp("highlight_0"), -str8_lit_comp("success_background"), -str8_lit_comp("failure_background"), -str8_lit_comp("action_background"), -}; - -String8 rd_theme_color_version_remap_new_name_table[22] = -{ -str8_lit_comp("text"), -str8_lit_comp("base_background"), -str8_lit_comp("base_border"), -str8_lit_comp("drop_site_overlay"), -str8_lit_comp("code_symbol"), -str8_lit_comp("code_delimiter_operator"), -str8_lit_comp("code_numeric_alt_digit_group"), -str8_lit_comp("line_info_background_0"), -str8_lit_comp("line_info_background_1"), -str8_lit_comp("line_info_background_2"), -str8_lit_comp("line_info_background_3"), -str8_lit_comp("menu_bar_background"), -str8_lit_comp("menu_bar_border"), -str8_lit_comp("tab_background_inactive"), -str8_lit_comp("tab_background"), -str8_lit_comp("text_weak"), -str8_lit_comp("selection"), -str8_lit_comp("cursor"), -str8_lit_comp("focus"), -str8_lit_comp("positive_pop_button_background"), -str8_lit_comp("negative_pop_button_background"), -str8_lit_comp("neutral_pop_button_background"), -}; - -Vec4F32 rd_theme_preset_colors__default_dark[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0xa4a4a4fe), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0xfda200ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x222222fe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x2c5b36ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x803425ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x355b6eff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x6f5135fe), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xcbcbcbff), -rgba_from_u32_lit_comp(0x42a2cffe), -rgba_from_u32_lit_comp(0xfec746ff), -rgba_from_u32_lit_comp(0x98bc80ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0xb38d4cff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0x98abb1ff), -rgba_from_u32_lit_comp(0x738287ff), -rgba_from_u32_lit_comp(0x98abb1ff), -rgba_from_u32_lit_comp(0xd96759ff), -rgba_from_u32_lit_comp(0x717171ff), -rgba_from_u32_lit_comp(0x7f7f7fff), -rgba_from_u32_lit_comp(0xbebebeff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x355b6eff), -}; - -Vec4F32 rd_theme_preset_colors__default_light[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x4c4c4cff), -rgba_from_u32_lit_comp(0x4d9e2eff), -rgba_from_u32_lit_comp(0xbd371eff), -rgba_from_u32_lit_comp(0x0064a7ff), -rgba_from_u32_lit_comp(0x4c4c4cff), -rgba_from_u32_lit_comp(0x699830ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0x9c5900ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000004c), -rgba_from_u32_lit_comp(0xa6a6a63f), -rgba_from_u32_lit_comp(0x4848480c), -rgba_from_u32_lit_comp(0xa4a4a43f), -rgba_from_u32_lit_comp(0x003d7a48), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0xff30005f), -rgba_from_u32_lit_comp(0xccccccfe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0xa4a4a4fe), -rgba_from_u32_lit_comp(0xeaeaea7f), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xa4a4a4fe), -rgba_from_u32_lit_comp(0xccccccc0), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0xa4a4a4fe), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x65f534ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0xff694cff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0xa6becaff), -rgba_from_u32_lit_comp(0xa6a6a6fd), -rgba_from_u32_lit_comp(0xa9a9a9fe), -rgba_from_u32_lit_comp(0xc0c0c0fe), -rgba_from_u32_lit_comp(0xa98b6fff), -rgba_from_u32_lit_comp(0xffffff4d), -rgba_from_u32_lit_comp(0x8282827f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0x4d4d4dff), -rgba_from_u32_lit_comp(0x205670fe), -rgba_from_u32_lit_comp(0x996b00ff), -rgba_from_u32_lit_comp(0x446a2bff), -rgba_from_u32_lit_comp(0x4c35a1ff), -rgba_from_u32_lit_comp(0x573700ff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0x3f6e7dff), -rgba_from_u32_lit_comp(0x1f4450ff), -rgba_from_u32_lit_comp(0x3c606bff), -rgba_from_u32_lit_comp(0xad3627ff), -rgba_from_u32_lit_comp(0x4b4b4bff), -rgba_from_u32_lit_comp(0x4b4b4bff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x945800ff), -rgba_from_u32_lit_comp(0x3f5b23ff), -rgba_from_u32_lit_comp(0x642a55ff), -rgba_from_u32_lit_comp(0x30456fff), -rgba_from_u32_lit_comp(0x264f41ff), -rgba_from_u32_lit_comp(0x736a5fff), -rgba_from_u32_lit_comp(0x472f5eff), -rgba_from_u32_lit_comp(0x405d3bff), -rgba_from_u32_lit_comp(0x49606aff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xff2800ff), -rgba_from_u32_lit_comp(0xa6becaff), -}; - -Vec4F32 rd_theme_preset_colors__vs_dark[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0xa4a4a4fe), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0xfda200ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x1b1b1bfd), -rgba_from_u32_lit_comp(0x1b1b1bfd), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x2c5b36ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x803425ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x355b6eff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x0079ccff), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0xfefefe14), -rgba_from_u32_lit_comp(0xffffff00), -rgba_from_u32_lit_comp(0xcbcbcbff), -rgba_from_u32_lit_comp(0xdcdcaaff), -rgba_from_u32_lit_comp(0x4ec9afff), -rgba_from_u32_lit_comp(0x9cdbfeff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0x569cd6ff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0xb5cea8ff), -rgba_from_u32_lit_comp(0x729360ff), -rgba_from_u32_lit_comp(0xd59b85ff), -rgba_from_u32_lit_comp(0xd59c85ff), -rgba_from_u32_lit_comp(0x57a54aff), -rgba_from_u32_lit_comp(0x2a91afff), -rgba_from_u32_lit_comp(0x9ddaecff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x355b6eff), -}; - -Vec4F32 rd_theme_preset_colors__vs_light[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc46451ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0x002affff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0xa3a3a37e), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x0000000c), -rgba_from_u32_lit_comp(0xfefefe53), -rgba_from_u32_lit_comp(0x3d74ab4b), -rgba_from_u32_lit_comp(0x0000001e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0xfefefefe), -rgba_from_u32_lit_comp(0xe7e7e7fe), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xfefefec7), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0x84ce93ff), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xbd3e24ff), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0x6e9db5ff), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xe8e8e8fe), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xfffffffe), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0xcdd4dc7f), -rgba_from_u32_lit_comp(0xb6b6b6ff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0xa33700ff), -rgba_from_u32_lit_comp(0x007666ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0x0000ffff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0x088658ff), -rgba_from_u32_lit_comp(0x0c3828ff), -rgba_from_u32_lit_comp(0xa31414ff), -rgba_from_u32_lit_comp(0x0000ffff), -rgba_from_u32_lit_comp(0x008000ff), -rgba_from_u32_lit_comp(0x227893ff), -rgba_from_u32_lit_comp(0x123d4bfe), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x945800ff), -rgba_from_u32_lit_comp(0x3f5b23ff), -rgba_from_u32_lit_comp(0x642a55ff), -rgba_from_u32_lit_comp(0x30456fff), -rgba_from_u32_lit_comp(0x264f41ff), -rgba_from_u32_lit_comp(0x736a5fff), -rgba_from_u32_lit_comp(0x472f5eff), -rgba_from_u32_lit_comp(0x405d3bff), -rgba_from_u32_lit_comp(0x49606aff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x6e9db5ff), -}; - -Vec4F32 rd_theme_preset_colors__solarized_dark[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x999999ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x9999998a), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0xfda200ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x002a35fe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x00202bff), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0x007fa14e), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0xfdfdfd3a), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x2c5b36ff), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x803425ff), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x355b6eff), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x005e77fe), -rgba_from_u32_lit_comp(0xfefefe3a), -rgba_from_u32_lit_comp(0x005e77fe), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xcbcbcbff), -rgba_from_u32_lit_comp(0xcb4a15ff), -rgba_from_u32_lit_comp(0xcb4a15ff), -rgba_from_u32_lit_comp(0x98bc80ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0x849803ff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0xd33582ff), -rgba_from_u32_lit_comp(0x902559ff), -rgba_from_u32_lit_comp(0x1f9d91ff), -rgba_from_u32_lit_comp(0x839802ff), -rgba_from_u32_lit_comp(0x556a6fff), -rgba_from_u32_lit_comp(0x566c73ff), -rgba_from_u32_lit_comp(0xa2aaacff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x355b6eff), -}; - -Vec4F32 rd_theme_preset_colors__solarized_light[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x333333ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x818181ff), -rgba_from_u32_lit_comp(0x586e75ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0x92743dff), -rgba_from_u32_lit_comp(0x747474ff), -rgba_from_u32_lit_comp(0xc9bfa394), -rgba_from_u32_lit_comp(0xe4dac090), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000001c), -rgba_from_u32_lit_comp(0x678cb24c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0xfcf5e2fe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xeee8d5ff), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xffffff7c), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0xbdb9aa00), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xb6ddbeff), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xf8b0a1ff), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xb2d3e3ff), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xe3dbc7fe), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xfdf6e3ff), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0xd4cfc0fe), -rgba_from_u32_lit_comp(0xbebaabfe), -rgba_from_u32_lit_comp(0x657b83ff), -rgba_from_u32_lit_comp(0xcb4a15ff), -rgba_from_u32_lit_comp(0xcb4a15ff), -rgba_from_u32_lit_comp(0x258ad2ff), -rgba_from_u32_lit_comp(0x373345ff), -rgba_from_u32_lit_comp(0x586e75ff), -rgba_from_u32_lit_comp(0x767676ff), -rgba_from_u32_lit_comp(0xd33482ef), -rgba_from_u32_lit_comp(0x8e2659ff), -rgba_from_u32_lit_comp(0x29a198ff), -rgba_from_u32_lit_comp(0xd96759ff), -rgba_from_u32_lit_comp(0x93a1a1ff), -rgba_from_u32_lit_comp(0x227893ef), -rgba_from_u32_lit_comp(0x111e22ef), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x945800ff), -rgba_from_u32_lit_comp(0x3f5b23ff), -rgba_from_u32_lit_comp(0x642a55ff), -rgba_from_u32_lit_comp(0x30456fff), -rgba_from_u32_lit_comp(0x264f41ff), -rgba_from_u32_lit_comp(0x736a5fff), -rgba_from_u32_lit_comp(0x472f5eff), -rgba_from_u32_lit_comp(0x405d3bff), -rgba_from_u32_lit_comp(0x49606aff), -rgba_from_u32_lit_comp(0xb23218ff), -rgba_from_u32_lit_comp(0xff684bff), -rgba_from_u32_lit_comp(0xb2d3e3ff), -}; - -Vec4F32 rd_theme_preset_colors__handmade_hero[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xa08462ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x6e512eff), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0xfda200ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x0c0c0cfe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0x423525fe), -rgba_from_u32_lit_comp(0x0c0c0cfe), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0x0c0c0c32), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x423425fe), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x132e19ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x803425ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x15445cff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x1f1f27fe), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x1f1f27fe), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x131315ee), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xa08462ff), -rgba_from_u32_lit_comp(0xcc5634ff), -rgba_from_u32_lit_comp(0xd8a51bff), -rgba_from_u32_lit_comp(0xc04047ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0xac7a09ff), -rgba_from_u32_lit_comp(0xa08462ff), -rgba_from_u32_lit_comp(0x698e21ff), -rgba_from_u32_lit_comp(0x3a4e11ff), -rgba_from_u32_lit_comp(0x6a8e22ff), -rgba_from_u32_lit_comp(0xdab98fff), -rgba_from_u32_lit_comp(0x686868ff), -rgba_from_u32_lit_comp(0xa08462ff), -rgba_from_u32_lit_comp(0xc8b399ff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x15445cff), -}; - -Vec4F32 rd_theme_preset_colors__four_coder[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x90b080ff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x566e4bff), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0xfda200ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x0c0c0cfe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x0c0c0cfe), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0x0c0c0c3e), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x152f1bff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x43150cff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x1b323eff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x212721fe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x212721fe), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x3a3a3a7f), -rgba_from_u32_lit_comp(0x00000019), -rgba_from_u32_lit_comp(0x90b080ff), -rgba_from_u32_lit_comp(0x42a2cffe), -rgba_from_u32_lit_comp(0xfd7c52ff), -rgba_from_u32_lit_comp(0x98bc80ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0xd08f1eff), -rgba_from_u32_lit_comp(0x90b080ff), -rgba_from_u32_lit_comp(0x4fff2eff), -rgba_from_u32_lit_comp(0x3ccd21ff), -rgba_from_u32_lit_comp(0x4fff2eff), -rgba_from_u32_lit_comp(0xa0b8a0ff), -rgba_from_u32_lit_comp(0x1e8fefff), -rgba_from_u32_lit_comp(0x7e7e7ffe), -rgba_from_u32_lit_comp(0xbebebeff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xa72911ff), -rgba_from_u32_lit_comp(0x1b323eff), -}; - -Vec4F32 rd_theme_preset_colors__far_manager[76] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x00fefeff), -rgba_from_u32_lit_comp(0x4dc221ff), -rgba_from_u32_lit_comp(0xc56452ff), -rgba_from_u32_lit_comp(0x307eb2ff), -rgba_from_u32_lit_comp(0x00a9a9ff), -rgba_from_u32_lit_comp(0x8aff00ff), -rgba_from_u32_lit_comp(0xb23217ff), -rgba_from_u32_lit_comp(0x00fefeff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0x0000003f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0xffffff1e), -rgba_from_u32_lit_comp(0x5f12005f), -rgba_from_u32_lit_comp(0x000081fe), -rgba_from_u32_lit_comp(0x2b2b2bfe), -rgba_from_u32_lit_comp(0x0000fffe), -rgba_from_u32_lit_comp(0x007d7dff), -rgba_from_u32_lit_comp(0x007d7dff), -rgba_from_u32_lit_comp(0xfefefe00), -rgba_from_u32_lit_comp(0x007c7c55), -rgba_from_u32_lit_comp(0x33333333), -rgba_from_u32_lit_comp(0x00ffff55), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x00000000), -rgba_from_u32_lit_comp(0x1b1b1bfe), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x2c5b36ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x803425ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x933100ff), -rgba_from_u32_lit_comp(0x3f3f3ffd), -rgba_from_u32_lit_comp(0x007d7dff), -rgba_from_u32_lit_comp(0x3f3f3ffe), -rgba_from_u32_lit_comp(0x007d7dff), -rgba_from_u32_lit_comp(0xfefefe4d), -rgba_from_u32_lit_comp(0x3e4c577f), -rgba_from_u32_lit_comp(0xfefefe19), -rgba_from_u32_lit_comp(0x00fefeff), -rgba_from_u32_lit_comp(0x65b1ffff), -rgba_from_u32_lit_comp(0xfec746ff), -rgba_from_u32_lit_comp(0x00ff00ff), -rgba_from_u32_lit_comp(0xb7afd5ff), -rgba_from_u32_lit_comp(0x00ffffff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x00ff00ff), -rgba_from_u32_lit_comp(0x738287ff), -rgba_from_u32_lit_comp(0x98abb1ff), -rgba_from_u32_lit_comp(0xff0000ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x007d7dff), -rgba_from_u32_lit_comp(0x00fefeff), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0x99503d3f), -rgba_from_u32_lit_comp(0xfe82493f), -rgba_from_u32_lit_comp(0xffba173f), -rgba_from_u32_lit_comp(0xcefd693f), -rgba_from_u32_lit_comp(0xffcb7fff), -rgba_from_u32_lit_comp(0xb2ff65ff), -rgba_from_u32_lit_comp(0xff99e5ff), -rgba_from_u32_lit_comp(0x6598ffff), -rgba_from_u32_lit_comp(0x65ffcbff), -rgba_from_u32_lit_comp(0xff9819ff), -rgba_from_u32_lit_comp(0x9932ffff), -rgba_from_u32_lit_comp(0x65ff4cff), -rgba_from_u32_lit_comp(0xb2ccd8ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xff2800ff), -rgba_from_u32_lit_comp(0x933100ff), -}; - -Vec4F32* rd_theme_preset_colors_table[9] = -{ -rd_theme_preset_colors__default_dark, -rd_theme_preset_colors__default_light, -rd_theme_preset_colors__vs_dark, -rd_theme_preset_colors__vs_light, -rd_theme_preset_colors__solarized_dark, -rd_theme_preset_colors__solarized_light, -rd_theme_preset_colors__handmade_hero, -rd_theme_preset_colors__four_coder, -rd_theme_preset_colors__far_manager, -}; - -String8 rd_theme_color_display_string_table[76] = -{ -str8_lit_comp("Null"), -str8_lit_comp("Text"), -str8_lit_comp("Text (Positive)"), -str8_lit_comp("Text (Negative)"), -str8_lit_comp("Text (Neutral)"), -str8_lit_comp("Text (Weak)"), -str8_lit_comp("Cursor"), -str8_lit_comp("Cursor (Inactive)"), -str8_lit_comp("Focus"), -str8_lit_comp("Hover"), -str8_lit_comp("Drop Shadow"), -str8_lit_comp("Disabled Overlay"), -str8_lit_comp("Drop Site Overlay"), -str8_lit_comp("Inactive Panel Overlay"), -str8_lit_comp("Selection Overlay"), -str8_lit_comp("Highlight Overlay"), -str8_lit_comp("Error Highlight Overlay"), -str8_lit_comp("Base Background"), -str8_lit_comp("Base Background (Alternate)"), -str8_lit_comp("Base Border"), -str8_lit_comp("Menu Bar Background"), -str8_lit_comp("Menu Bar Background (Alternate)"), -str8_lit_comp("Menu Bar Border"), -str8_lit_comp("Floating Background"), -str8_lit_comp("Floating Background (Alternate)"), -str8_lit_comp("Floating Border"), -str8_lit_comp("Implicit Button Background"), -str8_lit_comp("Implicit Button Border"), -str8_lit_comp("Plain Button Background"), -str8_lit_comp("Plain Button Border"), -str8_lit_comp("Positive Pop Button Background"), -str8_lit_comp("Positive Pop Button Border"), -str8_lit_comp("Negative Pop Button Background"), -str8_lit_comp("Negative Pop Button Border"), -str8_lit_comp("Neutral Pop Button Background"), -str8_lit_comp("Neutral Pop Button Border"), -str8_lit_comp("Scroll Bar Button Background"), -str8_lit_comp("Scroll Bar Button Border"), -str8_lit_comp("Tab Background"), -str8_lit_comp("Tab Border"), -str8_lit_comp("Tab Background (Inactive)"), -str8_lit_comp("Tab Border (Inactive)"), -str8_lit_comp("Code (Default)"), -str8_lit_comp("Code (Symbol)"), -str8_lit_comp("Code (Type)"), -str8_lit_comp("Code (Local)"), -str8_lit_comp("Code (Register)"), -str8_lit_comp("Code (Keyword)"), -str8_lit_comp("Code (Delimiters/Operators)"), -str8_lit_comp("Code (Numeric)"), -str8_lit_comp("Code (Numeric, Alt. Digit Group)"), -str8_lit_comp("Code (String)"), -str8_lit_comp("Code (Meta)"), -str8_lit_comp("Code (Comment)"), -str8_lit_comp("Code Line Numbers"), -str8_lit_comp("Code Line Numbers (Selected)"), -str8_lit_comp("Line Info Background 0"), -str8_lit_comp("Line Info Background 1"), -str8_lit_comp("Line Info Background 2"), -str8_lit_comp("Line Info Background 3"), -str8_lit_comp("Line Info Background 4"), -str8_lit_comp("Line Info Background 5"), -str8_lit_comp("Line Info Background 6"), -str8_lit_comp("Line Info Background 7"), -str8_lit_comp("Thread 0"), -str8_lit_comp("Thread 1"), -str8_lit_comp("Thread 2"), -str8_lit_comp("Thread 3"), -str8_lit_comp("Thread 4"), -str8_lit_comp("Thread 5"), -str8_lit_comp("Thread 6"), -str8_lit_comp("Thread 7"), -str8_lit_comp("Thread (Unwound)"), -str8_lit_comp("Thread (Error)"), -str8_lit_comp("Breakpoint"), -str8_lit_comp("Cache Line Boundary"), -}; - -String8 rd_theme_color_cfg_string_table[76] = -{ -str8_lit_comp("null"), -str8_lit_comp("text"), -str8_lit_comp("text_positive"), -str8_lit_comp("text_negative"), -str8_lit_comp("text_neutral"), -str8_lit_comp("text_weak"), -str8_lit_comp("cursor"), -str8_lit_comp("cursor_inactive"), -str8_lit_comp("focus"), -str8_lit_comp("hover"), -str8_lit_comp("drop_shadow"), -str8_lit_comp("disabled_overlay"), -str8_lit_comp("drop_site_overlay"), -str8_lit_comp("inactive_panel_overlay"), -str8_lit_comp("selection_overlay"), -str8_lit_comp("highlight_overlay"), -str8_lit_comp("error_highlight_overlay"), -str8_lit_comp("base_background"), -str8_lit_comp("base_background_alt"), -str8_lit_comp("base_border"), -str8_lit_comp("menu_bar_background"), -str8_lit_comp("menu_bar_background_alt"), -str8_lit_comp("menu_bar_border"), -str8_lit_comp("floating_background"), -str8_lit_comp("floating_background_alt"), -str8_lit_comp("floating_border"), -str8_lit_comp("implicit_button_background"), -str8_lit_comp("implicit_button_border"), -str8_lit_comp("plain_button_background"), -str8_lit_comp("plain_button_border"), -str8_lit_comp("positive_pop_button_background"), -str8_lit_comp("positive_pop_button_border"), -str8_lit_comp("negative_pop_button_background"), -str8_lit_comp("negative_pop_button_border"), -str8_lit_comp("neutral_pop_button_background"), -str8_lit_comp("neutral_pop_button_border"), -str8_lit_comp("scroll_bar_button_background"), -str8_lit_comp("scroll_bar_button_border"), -str8_lit_comp("tab_background"), -str8_lit_comp("tab_border"), -str8_lit_comp("tab_background_inactive"), -str8_lit_comp("tab_border_inactive"), -str8_lit_comp("code_default"), -str8_lit_comp("code_symbol"), -str8_lit_comp("code_type"), -str8_lit_comp("code_local"), -str8_lit_comp("code_register"), -str8_lit_comp("code_keyword"), -str8_lit_comp("code_delimiter_operator"), -str8_lit_comp("code_numeric"), -str8_lit_comp("code_numeric_alt_digit_group"), -str8_lit_comp("code_string"), -str8_lit_comp("code_meta"), -str8_lit_comp("code_comment"), -str8_lit_comp("code_line_numbers"), -str8_lit_comp("code_line_numbers_selected"), -str8_lit_comp("line_info_background_0"), -str8_lit_comp("line_info_background_1"), -str8_lit_comp("line_info_background_2"), -str8_lit_comp("line_info_background_3"), -str8_lit_comp("line_info_background_4"), -str8_lit_comp("line_info_background_5"), -str8_lit_comp("line_info_background_6"), -str8_lit_comp("line_info_background_7"), -str8_lit_comp("thread_0"), -str8_lit_comp("thread_1"), -str8_lit_comp("thread_2"), -str8_lit_comp("thread_3"), -str8_lit_comp("thread_4"), -str8_lit_comp("thread_5"), -str8_lit_comp("thread_6"), -str8_lit_comp("thread_7"), -str8_lit_comp("thread_unwound"), -str8_lit_comp("thread_error"), -str8_lit_comp("breakpoint"), -str8_lit_comp("cache_line_boundary"), -}; - -String8 rd_setting_code_display_string_table[19] = -{ -str8_lit_comp("Hover Animations"), -str8_lit_comp("Press Animations"), -str8_lit_comp("Focus Animations"), -str8_lit_comp("Tooltip Animations"), -str8_lit_comp("Menu Animations"), -str8_lit_comp("Scrolling Animations"), -str8_lit_comp("Background Blur"), -str8_lit_comp("Thread Lines"), -str8_lit_comp("Breakpoint Lines"), -str8_lit_comp("Thread Glow"), -str8_lit_comp("Breakpoint Glow"), -str8_lit_comp("Opaque Backgrounds"), -str8_lit_comp("Tab Width"), -str8_lit_comp("Main Font Size"), -str8_lit_comp("Code Font Size"), -str8_lit_comp("Smooth UI Text"), -str8_lit_comp("Smooth Code Text"), -str8_lit_comp("Hint UI Text"), -str8_lit_comp("Hint Code Text"), -}; - -String8 rd_setting_code_lower_string_table[19] = -{ -str8_lit_comp("hover_animations"), -str8_lit_comp("press_animations"), -str8_lit_comp("focus_animations"), -str8_lit_comp("tooltip_animations"), -str8_lit_comp("menu_animations"), -str8_lit_comp("scrolling_animations"), -str8_lit_comp("background_blur"), -str8_lit_comp("thread_lines"), -str8_lit_comp("breakpoint_lines"), -str8_lit_comp("thread_glow"), -str8_lit_comp("breakpoint_glow"), -str8_lit_comp("opaque_backgrounds"), -str8_lit_comp("tab_width"), -str8_lit_comp("main_font_size"), -str8_lit_comp("code_font_size"), -str8_lit_comp("smooth_ui_text"), -str8_lit_comp("smooth_code_text"), -str8_lit_comp("hint_ui_text"), -str8_lit_comp("hint_code_text"), -}; - -B8 rd_setting_code_default_is_per_window_table[19] = -{ -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -1, -1, -1, -1, -1, -}; - -RD_SettingVal rd_setting_code_default_val_table[19] = -{ -{1, 1}, -{1, 1}, -{1, 0}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 1}, -{1, 0}, -{1, 4}, -{1, 11}, -{1, 11}, -{1, 1}, -{1, 0}, -{1, 1}, -{1, 1}, -}; - -Rng1S32 rd_setting_code_s32_range_table[19] = -{ -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, -{1, 32}, -{6, 72}, -{6, 72}, -{0, 1}, -{0, 1}, -{0, 1}, -{0, 1}, +str8_lit_comp("theme:\n{\n theme_color: {tags:\"background\", value: 0x1b1b1bff }\n theme_color: {tags:\"alt background\", value: 0x222222ff }\n theme_color: {tags:\"pop background\", value: 0x355b6eff }\n theme_color: {tags:\"fresh background\", value: 0x31393dff }\n theme_color: {tags:\"match background\", value: 0x31393dff }\n theme_color: {tags:\"border\", value: 0x404040ff }\n theme_color: {tags:\"text\", value: 0xe5e5e5ff }\n theme_color: {tags:\"weak text\", value: 0xa4a4a4ff }\n theme_color: {tags:\"good text\", value: 0x32a852ff }\n theme_color: {tags:\"neutral text\", value: 0x3a90bbff }\n theme_color: {tags:\"bad text\", value: 0xcf5242ff }\n theme_color: {tags:\"hover\", value: 0xffffffff }\n theme_color: {tags:\"focus overlay\", value: 0xfda20012 }\n theme_color: {tags:\"focus border\", value: 0xfda200ff }\n theme_color: {tags:\"cursor\", value: 0x8aff00ff }\n theme_color: {tags:\"selection\", value: 0x99ccff0f }\n theme_color: {tags:\"inactive background\", value: 0x0000002f }\n theme_color: {tags:\"drop_shadow\", value: 0x0000007f }\n theme_color: {tags:\"good_pop background\", value: 0x2c5b36ff }\n theme_color: {tags:\"good_pop border\", value: 0x568761ff }\n theme_color: {tags:\"good_pop hover\", value: 0xe3f5d3ff }\n theme_color: {tags:\"good_pop weak text\", value: 0xe3f5d3ff }\n theme_color: {tags:\"bad_pop background\", value: 0x803425ff }\n theme_color: {tags:\"bad_pop hover\", value: 0xff825cff }\n theme_color: {tags:\"code_default\", value: 0xcbcbcbff }\n theme_color: {tags:\"code_symbol\", value: 0x42a2cfff }\n theme_color: {tags:\"code_type\", value: 0xfec746ff }\n theme_color: {tags:\"code_local\", value: 0x98bc80ff }\n theme_color: {tags:\"code_register\", value: 0xb7afd5ff }\n theme_color: {tags:\"code_keyword\", value: 0xb38d4cff }\n theme_color: {tags:\"code_delimiter_or_operator\", value: 0x767676ff }\n theme_color: {tags:\"code_numeric\", value: 0x98abb1ff }\n theme_color: {tags:\"code_numeric_alt_digit_group\", value: 0x738287ff }\n theme_color: {tags:\"code_string\", value: 0x98abb1ff }\n theme_color: {tags:\"code_meta\", value: 0xd96759ff }\n theme_color: {tags:\"code_comment\", value: 0x717171ff }\n theme_color: {tags:\"line_info_0\", value: 0x4f3022ff }\n theme_color: {tags:\"line_info_1\", value: 0x4f3e15ff }\n theme_color: {tags:\"line_info_2\", value: 0x434e2aff }\n theme_color: {tags:\"line_info_3\", value: 0x36241fff }\n theme_color: {tags:\"line_info_4\", value: 0x4f3022ff }\n theme_color: {tags:\"line_info_5\", value: 0x4f3e15ff }\n theme_color: {tags:\"line_info_6\", value: 0x434e2aff }\n theme_color: {tags:\"line_info_7\", value: 0x36241fff }\n theme_color: {tags:\"thread_0\", value: 0xffcb7fff }\n theme_color: {tags:\"thread_1\", value: 0xb2ff65ff }\n theme_color: {tags:\"thread_2\", value: 0xff99e5ff }\n theme_color: {tags:\"thread_3\", value: 0x6598ffff }\n theme_color: {tags:\"thread_4\", value: 0x65ffcbff }\n theme_color: {tags:\"thread_5\", value: 0xff9819ff }\n theme_color: {tags:\"thread_6\", value: 0x9932ffff }\n theme_color: {tags:\"thread_7\", value: 0x65ff4cff }\n theme_color: {tags:\"thread_unwound\", value: 0xb2ccd8ff }\n theme_color: {tags:\"thread_error\", value: 0xb23219ff }\n theme_color: {tags:\"breakpoint\", value: 0xa72911ff }\n theme_color: {tags:\"floating background\", value: 0x1b1b1baf }\n theme_color: {tags:\"floating background alt\", value: 0x0000005f }\n theme_color: {tags:\"floating background fresh\", value: 0x31393d5f }\n theme_color: {tags:\"floating border\", value: 0xbfbfbf1f }\n theme_color: {tags:\"floating scroll_bar background\", value: 0x3b3b3b5f }\n theme_color: {tags:\"floating scroll_bar border\", value: 0x5f5f5f5f }\n theme_color: {tags:\"menu_bar background\", value: 0x2b3740ff }\n theme_color: {tags:\"menu_bar border\", value: 0x3e4c57ff }\n theme_color: {tags:\"scroll_bar background\", value: 0x2b2b2bff }\n theme_color: {tags:\"scroll_bar border\", value: 0x3f3f3fff }\n theme_color: {tags:\"implicit background\", value: 0x00000000 }\n theme_color: {tags:\"implicit border\", value: 0x00000000 }\n theme_color: {tags:\"hollow background\", value: 0x00000000 }\n theme_color: {tags:\"hollow border\", value: 0xffffff1f }\n theme_color: {tags:\"tab background\", value: 0x6f5135ff }\n theme_color: {tags:\"tab border\", value: 0x8a6e54ff }\n theme_color: {tags:\"tab inactive background\", value: 0x2b3740ff }\n theme_color: {tags:\"tab inactive border\", value: 0x3e4c57ff }\n theme_color: {tags:\"tab auto background\", value: 0x693847ff }\n theme_color: {tags:\"tab auto border\", value: 0x9e6274ff }\n theme_color: {tags:\"tab auto inactive background\", value: 0x2f2633ff }\n theme_color: {tags:\"tab auto inactive border\", value: 0x685073ff }\n theme_color: {tags:\"drop_site background\", value: 0xffffff05 }\n theme_color: {tags:\"drop_site border\", value: 0xffffff0f }\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{ tags: background , value: 0xffffffff }\n theme_color:{ tags: \"alt background\" , value: 0xf8f8f8ff }\n theme_color:{ tags: \"pop background\" , value: 0xcbe4f2ff }\n theme_color:{ tags: \"menu_bar pop background\" , value: 0x5aabd9ff }\n theme_color:{ tags: \"fresh background\" , value: 0xeaddceff }\n theme_color:{ tags: \"match background\" , value: 0xc1e9c4ff }\n theme_color:{ tags: border , value: 0xcbcbcbff }\n theme_color:{ tags: text , value: 0xff }\n theme_color:{ tags: \"weak text\" , value: 0x727272ff }\n theme_color:{ tags: \"good text\" , value: 0x217538ff }\n theme_color:{ tags: \"neutral text\" , value: 0x1a5b7cff }\n theme_color:{ tags: \"bad text\" , value: 0x972717ff }\n theme_color:{ tags: hover , value: 0xff }\n theme_color:{ tags: \"focus overlay\" , value: 0x67ff4b }\n theme_color:{ tags: \"focus border\" , value: 0x67ffff }\n theme_color:{ tags: cursor , value: 0xff }\n theme_color:{ tags: selection , value: 0x283d5166 }\n theme_color:{ tags: \"inactive background\" , value: 0x8 }\n theme_color:{ tags: drop_shadow , value: 0xb }\n theme_color:{ tags: \"good_pop background\" , value: 0x90c09aff }\n theme_color:{ tags: \"good_pop border\" , value: 0x1e7231ff }\n theme_color:{ tags: \"good_pop hover\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"good_pop weak text\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"good_pop text\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"bad_pop background\" , value: 0xa93620ff }\n theme_color:{ tags: \"bad_pop text\" , value: 0xffffffff }\n theme_color:{ tags: \"bad_pop text weak\" , value: 0xffffffff }\n theme_color:{ tags: \"menu_bar bad_pop background\" , value: 0xff2a00ff }\n theme_color:{ tags: \"menu_bar bad_pop text\" , value: 0xffffffff }\n theme_color:{ tags: \"bad_pop hover\" , value: 0xff825cff }\n theme_color:{ tags: code_default , value: 0x80808ff }\n theme_color:{ tags: code_symbol , value: 0x4ac3ff }\n theme_color:{ tags: code_type , value: 0xf46200ff }\n theme_color:{ tags: code_local , value: 0x317c00ff }\n theme_color:{ tags: code_register , value: 0x9a00ffff }\n theme_color:{ tags: code_keyword , value: 0xff0600ff }\n theme_color:{ tags: code_delimiter_or_operator , value: 0x8a8a8aff }\n theme_color:{ tags: code_numeric , value: 0x7d49ff }\n theme_color:{ tags: code_numeric_alt_digit_group , value: 0xb56aff }\n theme_color:{ tags: code_string , value: 0x63549fff }\n theme_color:{ tags: code_meta , value: 0xd96759ff }\n theme_color:{ tags: code_comment , value: 0x717171ff }\n theme_color:{ tags: line_info_0 , value: 0xe6d5cdff }\n theme_color:{ tags: line_info_1 , value: 0xdbcfb2ff }\n theme_color:{ tags: line_info_2 , value: 0xddeac1ff }\n theme_color:{ tags: line_info_3 , value: 0xddc4bdff }\n theme_color:{ tags: line_info_4 , value: 0xba917eff }\n theme_color:{ tags: thread_0 , value: 0xffa700ff }\n theme_color:{ tags: thread_1 , value: 0xb41fff }\n theme_color:{ tags: thread_2 , value: 0xff99e5ff }\n theme_color:{ tags: thread_3 , value: 0x6598ffff }\n theme_color:{ tags: thread_4 , value: 0x65ffcbff }\n theme_color:{ tags: thread_5 , value: 0xff9819ff }\n theme_color:{ tags: thread_6 , value: 0x9932ffff }\n theme_color:{ tags: thread_7 , value: 0x65ff4cff }\n theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff }\n theme_color:{ tags: thread_error , value: 0xb23219ff }\n theme_color:{ tags: breakpoint , value: 0xff2800ff }\n theme_color:{ tags: \"floating background\" , value: 0xffffffc7 }\n theme_color:{ tags: \"floating background alt\" , value: 0x23 }\n theme_color:{ tags: \"floating background fresh\" , value: 0xeaddceff }\n theme_color:{ tags: \"floating border\" , value: 0x88888884 }\n theme_color:{ tags: \"scroll_bar background\" , value: 0xe9e9e9ff }\n theme_color:{ tags: \"scroll_bar border\" , value: 0x5f5f5f5f }\n theme_color:{ tags: \"floating scroll_bar background\" , value: 0xe9e9e9ff }\n theme_color:{ tags: \"floating scroll_bar border\" , value: 0x5f5f5f5f }\n theme_color:{ tags: \"menu_bar background\" , value: 0x2b6b9aff }\n theme_color:{ tags: \"menu_bar border\" , value: 0x4d }\n theme_color:{ tags: \"menu_bar text\" , value: 0xffffffff }\n theme_color:{ tags: \"menu_bar text weak\" , value: 0xffffffff }\n theme_color:{ tags: \"good menu_bar text\" , value: 0x70db8dff }\n theme_color:{ tags: \"bad menu_bar text\" , value: 0xffa79bff }\n theme_color:{ tags: \"neutral menu_bar text\" , value: 0xc4dbe7ff }\n theme_color:{ tags: \"implicit background\" , value: 0x00000000 }\n theme_color:{ tags: \"implicit border\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow background\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow border\" , value: 0xffffff1f }\n theme_color:{ tags: \"tab text\" , value: 0xffffffff }\n theme_color:{ tags: \"tab text weak\" , value: 0xffffffff }\n theme_color:{ tags: \"tab background\" , value: 0xb67e48ff }\n theme_color:{ tags: \"tab border\" , value: 0x875b31ff }\n theme_color:{ tags: \"tab inactive background\" , value: 0xcacacaff }\n theme_color:{ tags: \"tab inactive border\" , value: 0xb5b5b5ff }\n theme_color:{ tags: \"tab auto background\" , value: 0xc41c69ff }\n theme_color:{ tags: \"tab auto border\" , value: 0x981039ff }\n theme_color:{ tags: \"tab auto inactive background\" , value: 0x9b88a3ff }\n theme_color:{ tags: \"tab auto inactive border\" , value: 0x373737ff }\n theme_color:{ tags: \"drop_site background\" , value: 0xffffff05 }\n theme_color:{ tags: \"drop_site border\" , value: 0xffffff0f }\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{ tags: background , value: 0x1f1f1fff }\n theme_color:{ tags: \"alt background\" , value: 0x222222ff }\n theme_color:{ tags: \"pop background\" , value: 0x383167ff }\n theme_color:{ tags: \"fresh background\" , value: 0x31393dff }\n theme_color:{ tags: \"match background\" , value: 0x31393dff }\n theme_color:{ tags: border , value: 0x404040ff }\n theme_color:{ tags: text , value: 0xe5e5e5ff }\n theme_color:{ tags: \"weak text\" , value: 0xa4a4a4ff }\n theme_color:{ tags: \"good text\" , value: 0x32a852ff }\n theme_color:{ tags: \"neutral text\" , value: 0x3a90bbff }\n theme_color:{ tags: \"bad text\" , value: 0xcf5242ff }\n theme_color:{ tags: hover , value: 0xffffffff }\n theme_color:{ tags: \"focus overlay\" , value: 0x7160e81e }\n theme_color:{ tags: \"focus border\" , value: 0x7160e8ff }\n theme_color:{ tags: cursor , value: 0x8aff00ff }\n theme_color:{ tags: selection , value: 0x99ccff0f }\n theme_color:{ tags: \"inactive background\" , value: 0x0000002f }\n theme_color:{ tags: drop_shadow , value: 0x0000007f }\n theme_color:{ tags: \"good_pop background\" , value: 0x2c5b36ff }\n theme_color:{ tags: \"good_pop border\" , value: 0x568761ff }\n theme_color:{ tags: \"good_pop hover\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"good_pop weak text\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"bad_pop background\" , value: 0x803425ff }\n theme_color:{ tags: \"bad_pop hover\" , value: 0xff825cff }\n theme_color:{ tags: code_default , value: 0xe0e0e0ff }\n theme_color:{ tags: code_symbol , value: 0xdcdcaaff }\n theme_color:{ tags: code_type , value: 0x4ec9b0ff }\n theme_color:{ tags: code_local , value: 0x9cdcfeff }\n theme_color:{ tags: code_register , value: 0xb7afd5ff }\n theme_color:{ tags: code_keyword , value: 0x569cd6ff }\n theme_color:{ tags: code_delimiter_or_operator , value: 0x767676ff }\n theme_color:{ tags: code_numeric , value: 0xb5cea8ff }\n theme_color:{ tags: code_numeric_alt_digit_group , value: 0x7c986dff }\n theme_color:{ tags: code_string , value: 0xd69d85ff }\n theme_color:{ tags: code_meta , value: 0x9b9b9bff }\n theme_color:{ tags: code_comment , value: 0x51a644ff }\n theme_color:{ tags: line_info_0 , value: 0x4f3022ff }\n theme_color:{ tags: line_info_1 , value: 0x4f3e15ff }\n theme_color:{ tags: line_info_2 , value: 0x434e2aff }\n theme_color:{ tags: line_info_3 , value: 0x36241fff }\n theme_color:{ tags: line_info_4 , value: 0x4f3022ff }\n theme_color:{ tags: line_info_5 , value: 0x4f3e15ff }\n theme_color:{ tags: line_info_6 , value: 0x434e2aff }\n theme_color:{ tags: line_info_7 , value: 0x36241fff }\n theme_color:{ tags: thread_0 , value: 0xffdc48ff }\n theme_color:{ tags: thread_1 , value: 0xb2ff65ff }\n theme_color:{ tags: thread_2 , value: 0xff99e5ff }\n theme_color:{ tags: thread_3 , value: 0x6598ffff }\n theme_color:{ tags: thread_4 , value: 0x65ffcbff }\n theme_color:{ tags: thread_5 , value: 0xff9819ff }\n theme_color:{ tags: thread_6 , value: 0x9932ffff }\n theme_color:{ tags: thread_7 , value: 0x65ff4cff }\n theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff }\n theme_color:{ tags: thread_error , value: 0xb23219ff }\n theme_color:{ tags: breakpoint , value: 0xa72911ff }\n theme_color:{ tags: \"floating background\" , value: 0x1b1b1baf }\n theme_color:{ tags: \"floating background alt\" , value: 0x0000005f }\n theme_color:{ tags: \"floating background fresh\" , value: 0x31393d5f }\n theme_color:{ tags: \"floating border\" , value: 0xbfbfbf1f }\n theme_color:{ tags: \"floating scroll_bar background\" , value: 0x3b3b3b5f }\n theme_color:{ tags: \"floating scroll_bar border\" , value: 0x5f5f5f5f }\n theme_color:{ tags: \"scroll_bar background\" , value: 0x2b2b2bff }\n theme_color:{ tags: \"scroll_bar border\" , value: 0x3f3f3fff }\n theme_color:{ tags: \"implicit background\" , value: 0x00000000 }\n theme_color:{ tags: \"implicit border\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow background\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow border\" , value: 0xffffff1f }\n theme_color:{ tags: \"tab background\" , value: 0x333333ff }\n theme_color:{ tags: \"tab border\" , value: 0x7160e8ff }\n theme_color:{ tags: \"tab inactive background\" , value: 0x171717ff }\n theme_color:{ tags: \"tab inactive border\" , value: 0x3e4c57ff }\n theme_color:{ tags: \"tab auto background\" , value: 0x3f386dff }\n theme_color:{ tags: \"tab auto border\" , value: 0x7160e8ff }\n theme_color:{ tags: \"tab auto inactive background\" , value: 0x2f2633ff }\n theme_color:{ tags: \"tab auto inactive border\" , value: 0x685073ff }\n theme_color:{ tags: \"drop_site background\" , value: 0xffffff05 }\n theme_color:{ tags: \"drop_site border\" , value: 0xffffff0f }\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0xffffffff}\n theme_color:{tags: \"alt background\", value: 0xefefefff}\n theme_color:{tags: \"pop background\", value: 0xe3eaf2ff}\n theme_color:{tags: \"fresh background\", value: 0xeccbbeff}\n theme_color:{tags: \"match background\", value: 0xedcbf9ff}\n theme_color:{tags: border, value: 0xe7e7e7ff}\n theme_color:{tags: text, value: 0xff}\n theme_color:{tags: \"weak text\", value: 0x353535ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: hover, value: 0xa7ffff}\n theme_color:{tags: \"focus overlay\", value: 0x8eff3f}\n theme_color:{tags: \"focus border\", value: 0x8effff}\n theme_color:{tags: cursor, value: 0xff}\n theme_color:{tags: selection, value: 0x56aaff77}\n theme_color:{tags: \"inactive background\", value: 0x17}\n theme_color:{tags: drop_shadow, value: 0xe7b27}\n theme_color:{tags: \"good_pop background\", value: 0x21a43dff}\n theme_color:{tags: \"good_pop border\", value: 0x21a43dff}\n theme_color:{tags: \"good_pop hover\", value: 0xe3f5d3ff}\n theme_color:{tags: \"good_pop weak text\", value: 0xe3f5d3ff}\n theme_color:{tags: \"good_pop text\", value: 0xe3f5d3ff}\n theme_color:{tags: \"bad_pop background\", value: 0xcb3f23ff}\n theme_color:{tags: \"bad_pop text\", value: 0xffcdc4ff}\n theme_color:{tags: \"bad_pop text weak\", value: 0xffcdc4ff}\n theme_color:{tags: \"bad_pop hover\", value: 0xff825cff}\n theme_color:{tags: code_default, value: 0x000000ff}\n theme_color:{tags: code_symbol, value: 0x74531fff}\n theme_color:{tags: code_type, value: 0x2b91afff}\n theme_color:{tags: code_local, value: 0x1f377fff}\n theme_color:{tags: code_register, value: 0x8a1bffff}\n theme_color:{tags: code_keyword, value: 0x0000ffff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x767676ff}\n theme_color:{tags: code_numeric, value: 0xff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x1d1d1dff}\n theme_color:{tags: code_string, value: 0xa61515ff}\n theme_color:{tags: code_meta, value: 0x808080ff}\n theme_color:{tags: code_comment, value: 0x008000ff}\n theme_color:{tags: line_info_0, value: 0xb5d9c8ff}\n theme_color:{tags: line_info_1, value: 0xa9c1d0ff}\n theme_color:{tags: line_info_2, value: 0x99abc5ff}\n theme_color:{tags: line_info_3, value: 0xc6bcd5ff}\n theme_color:{tags: thread_0, value: 0xffb141ff}\n theme_color:{tags: thread_1, value: 0x66c407ff}\n theme_color:{tags: thread_unwound, value: 0x67b3d7ff}\n theme_color:{tags: thread_error, value: 0xff2900ff}\n theme_color:{tags: breakpoint, value: 0xff2800ff}\n theme_color:{tags: \"floating background\", value: 0xffffffff}\n theme_color:{tags: \"floating background alt\", value: 0x11}\n theme_color:{tags: \"floating background fresh\", value: 0xa0c2d318}\n theme_color:{tags: \"floating border\", value: 0x50}\n theme_color:{tags: \"floating scroll_bar background\", value: 0x3b3b3b5f}\n theme_color:{tags: \"floating scroll_bar border\", value: 0x5f5f5f5f}\n theme_color:{tags: \"menu_bar background\", value: 0xccd5f0ff}\n theme_color:{tags: \"menu_bar border\", value: 0xbabdc3ff}\n theme_color:{tags: \"scroll_bar background\", value: 0xe4e4e4ff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0xf5cc84ff}\n theme_color:{tags: \"tab border\", value: 0xae7718ff}\n theme_color:{tags: \"tab inactive background\", value: 0x3b4f81ff}\n theme_color:{tags: \"tab inactive text\", value: 0xffffffff}\n theme_color:{tags: \"tab inactive border\", value: 0x3b4f81ff}\n theme_color:{tags: \"tab auto background\", value: 0xe99595ff}\n theme_color:{tags: \"tab auto border\", value: 0xff6262ff}\n theme_color:{tags: \"tab auto inactive background\", value: 0xac6060ff}\n theme_color:{tags: \"tab auto inactive border\", value: 0xff6262ff}\n theme_color:{tags: \"drop_site background\", value: 0xffffff05}\n theme_color:{tags: \"drop_site border\", value: 0xa7ffff}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0x002a35ff}\n theme_color:{tags: \"alt background\", value: 0x053542ff}\n theme_color:{tags: \"pop background\", value: 0x355b6eff}\n theme_color:{tags: \"fresh background\", value: 0x31393dff}\n theme_color:{tags: \"match background\", value: 0x31393dff}\n theme_color:{tags: border, value: 0x65166ff}\n theme_color:{tags: text, value: 0xeee8d5ff}\n theme_color:{tags: \"weak text\", value: 0x93a1a1ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: hover, value: 0xca4b16ff}\n theme_color:{tags: \"focus overlay\", value: 0xca4b151f}\n theme_color:{tags: \"focus border\", value: 0xca4b16ff}\n theme_color:{tags: cursor, value: 0xca4b16ff}\n theme_color:{tags: selection, value: 0x99ccff0f}\n theme_color:{tags: \"inactive background\", value: 0x0000002f}\n theme_color:{tags: drop_shadow, value: 0x0000007f}\n theme_color:{tags: \"good_pop background\", value: 0x5f8700ff}\n theme_color:{tags: \"good_pop border\", value: 0x5f8700ff}\n theme_color:{tags: \"bad_pop background\", value: 0x810000ff}\n theme_color:{tags: code_default, value: 0x839496ff}\n theme_color:{tags: code_symbol, value: 0xb3880eff}\n theme_color:{tags: code_type, value: 0xb3880eff}\n theme_color:{tags: code_local, value: 0xeee8d5ff}\n theme_color:{tags: code_register, value: 0xeee8d5ff}\n theme_color:{tags: code_keyword, value: 0x849804ff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x839496ff}\n theme_color:{tags: code_numeric, value: 0x2aa198ff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x19766bff}\n theme_color:{tags: code_string, value: 0x2aa198ff}\n theme_color:{tags: code_meta, value: 0xca4b16ff}\n theme_color:{tags: code_comment, value: 0x586e75ff}\n theme_color:{tags: line_info_0, value: 0x4f3022ff}\n theme_color:{tags: line_info_1, value: 0x4f3e15ff}\n theme_color:{tags: line_info_2, value: 0x434e2aff}\n theme_color:{tags: line_info_3, value: 0x36241fff}\n theme_color:{tags: thread_0, value: 0xffcb7fff}\n theme_color:{tags: thread_1, value: 0xb2ff65ff}\n theme_color:{tags: thread_unwound, value: 0xb2ccd8ff}\n theme_color:{tags: thread_error, value: 0xb23219ff}\n theme_color:{tags: breakpoint, value: 0xa72911ff}\n theme_color:{tags: \"floating background\", value: 0x2a3574}\n theme_color:{tags: \"floating background alt\", value: 0x4f}\n theme_color:{tags: \"floating background fresh\", value: 0x31393d5f}\n theme_color:{tags: \"floating scroll_bar background\", value: 0x53542ff}\n theme_color:{tags: \"scroll_bar background\", value: 0x53542ff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0x586e75ff}\n theme_color:{tags: \"tab border\", value: 0x90abb3ff}\n theme_color:{tags: \"tab inactive background\", value: 0x0}\n theme_color:{tags: \"tab inactive border\", value: 0x33494fff}\n theme_color:{tags: \"tab auto background\", value: 0x565ed2ff}\n theme_color:{tags: \"tab auto border\", value: 0xa2a6dfff}\n theme_color:{tags: \"tab auto inactive background\", value: 0}\n theme_color:{tags: \"tab auto inactive border\", value: 0x595fbcff}\n theme_color:{tags: \"drop_site background\", value: 0xffffff05}\n theme_color:{tags: \"drop_site border\", value: 0xffffff0f}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0xfdf6e3ff}\n theme_color:{tags: \"alt background\", value: 0xeee8d5ff}\n theme_color:{tags: \"pop background\", value: 0x29a19890}\n theme_color:{tags: \"fresh background\", value: 0xf7d38dff}\n theme_color:{tags: \"match background\", value: 0xdcddddff}\n theme_color:{tags: border, value: 0xd1ccbdff}\n theme_color:{tags: \"weak text\", value: 0x93a1a1ff}\n theme_color:{tags: text, value: 0x657b83ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: hover, value: 0xca4b16ff}\n theme_color:{tags: \"focus overlay\", value: 0xca4b1454}\n theme_color:{tags: \"focus border\", value: 0xca4b16ff}\n theme_color:{tags: cursor, value: 0xca4b16ff}\n theme_color:{tags: selection, value: 0x8594a264}\n theme_color:{tags: \"inactive background\", value: 0x14}\n theme_color:{tags: drop_shadow, value: 0x3a}\n theme_color:{tags: \"good_pop background\", value: 0xd1e99aff}\n theme_color:{tags: \"good_pop border\", value: 0xd1e99aff}\n theme_color:{tags: \"bad_pop background\", value: 0xd26c6cff}\n theme_color:{tags: \"bad_pop border\", value: 0xd26c6cff}\n theme_color:{tags: \"bad_pop weak text\", value: 0xffffffff}\n theme_color:{tags: \"bad_pop text\", value: 0xffffffff}\n theme_color:{tags: code_default, value: 0x839496ff}\n theme_color:{tags: code_symbol, value: 0xb3880eff}\n theme_color:{tags: code_type, value: 0xb3880eff}\n theme_color:{tags: code_local, value: 0x657b83ff}\n theme_color:{tags: code_register, value: 0x947298ff}\n theme_color:{tags: code_keyword, value: 0x849804ff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x839496ff}\n theme_color:{tags: code_numeric, value: 0x2aa198ff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x19766bff}\n theme_color:{tags: code_string, value: 0x2aa198ff}\n theme_color:{tags: code_meta, value: 0xca4b16ff}\n theme_color:{tags: code_comment, value: 0x586e75ff}\n theme_color:{tags: line_info_0, value: 0xeee1dbff}\n theme_color:{tags: line_info_1, value: 0xe5d5b1ff}\n theme_color:{tags: line_info_2, value: 0xd9e8b6ff}\n theme_color:{tags: line_info_3, value: 0xf5d5ccff}\n theme_color:{tags: thread_0, value: 0xffa100ff}\n theme_color:{tags: thread_1, value: 0x6edd00ff}\n theme_color:{tags: thread_unwound, value: 0x708f9eff}\n theme_color:{tags: thread_error, value: 0xff5231ff}\n theme_color:{tags: breakpoint, value: 0xff411dff}\n theme_color:{tags: \"floating background\", value: 0xfdf6e3b1}\n theme_color:{tags: \"floating background alt\", value: 0x22}\n theme_color:{tags: \"floating background fresh\", value: 0xf7d38dff}\n theme_color:{tags: \"scroll_bar background\", value: 0xeee6d0ff}\n theme_color:{tags: \"scroll_bar floating background\", value: 0xd5ccb5ff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0xfdf6e3ff}\n theme_color:{tags: \"tab inactive background\", value: 0xe0d6bbff}\n theme_color:{tags: \"tab auto background\", value: 0xf5cfe1ff}\n theme_color:{tags: \"tab auto border\", value: 0xa2a6dfff}\n theme_color:{tags: \"tab auto inactive background\", value: 0xc8a5b5ff}\n theme_color:{tags: \"tab auto inactive border\", value: 0x595fbcff}\n theme_color:{tags: \"drop_site background\", value: 0x29a19890}\n theme_color:{tags: \"drop_site border\", value: 0x81ddd690}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0x0c0c0cff}\n theme_color:{tags: \"alt background\", value: 0x161616ff}\n theme_color:{tags: \"pop background\", value: 0x355b6eff}\n theme_color:{tags: \"fresh background\", value: 0x31393dff}\n theme_color:{tags: \"match background\", value: 0x31393dff}\n theme_color:{tags: border, value: 0x404040ff}\n theme_color:{tags: text, value: 0xcac1b6ff}\n theme_color:{tags: \"weak text\", value: 0xa08563ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: hover, value: 0xffffffff}\n theme_color:{tags: \"focus overlay\", value: 0x7485971e}\n theme_color:{tags: \"focus border\", value: 0x5e6b79ff}\n theme_color:{tags: cursor, value: 0x00ee00ff}\n theme_color:{tags: selection, value: 0x99ccff0f}\n theme_color:{tags: \"inactive background\", value: 0x0000002f}\n theme_color:{tags: drop_shadow, value: 0x0000007f}\n theme_color:{tags: \"good_pop background\", value: 0x2c5b36ff}\n theme_color:{tags: \"good_pop border\", value: 0x568761ff}\n theme_color:{tags: \"good_pop hover\", value: 0xe3f5d3ff}\n theme_color:{tags: \"good_pop weak text\", value: 0xe3f5d3ff}\n theme_color:{tags: \"bad_pop background\", value: 0x803425ff}\n theme_color:{tags: \"bad_pop hover\", value: 0xff825cff}\n theme_color:{tags: code_default, value: 0xa08563ff}\n theme_color:{tags: code_symbol, value: 0xcc5735ff}\n theme_color:{tags: code_type, value: 0xd8a51cff}\n theme_color:{tags: code_local, value: 0xd6b995ff}\n theme_color:{tags: code_register, value: 0xc04047ff}\n theme_color:{tags: code_keyword, value: 0xac7b0aff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x907553ff}\n theme_color:{tags: code_numeric, value: 0x6b8e23ff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x4f681cff}\n theme_color:{tags: code_string, value: 0x6b8e23ff}\n theme_color:{tags: code_meta, value: 0xdab98fff}\n theme_color:{tags: code_comment, value: 0x686868ff}\n theme_color:{tags: line_info_0, value: 0x4f3022ff}\n theme_color:{tags: line_info_1, value: 0x4f3e15ff}\n theme_color:{tags: line_info_2, value: 0x434e2aff}\n theme_color:{tags: line_info_3, value: 0x36241fff}\n theme_color:{tags: thread_0, value: 0xffcb7fff}\n theme_color:{tags: thread_1, value: 0xb2ff65ff}\n theme_color:{tags: thread_unwound, value: 0xb2ccd8ff}\n theme_color:{tags: thread_error, value: 0xb23219ff}\n theme_color:{tags: breakpoint, value: 0xa72911ff}\n theme_color:{tags: \"floating background\", value: 0x18181980}\n theme_color:{tags: \"floating background alt\", value: 0x0000005f}\n theme_color:{tags: \"floating background fresh\", value: 0x31393d5f}\n theme_color:{tags: \"floating border\", value: 0xbfbfbf1f}\n theme_color:{tags: \"floating scroll_bar background\", value: 0x3b3b3b5f}\n theme_color:{tags: \"floating scroll_bar border\", value: 0x5f5f5f5f}\n theme_color:{tags: \"menu_bar background\", value: 0x1f1f27ff}\n theme_color:{tags: \"menu_bar border\", value: 0x3d3d47ff}\n theme_color:{tags: \"scroll_bar background\", value: 0x2b2b2bff}\n theme_color:{tags: \"scroll_bar border\", value: 0x3f3f3fff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0x1f1f27ff}\n theme_color:{tags: \"tab border\", value: 0x3d3d47ff}\n theme_color:{tags: \"tab text\", value: 0xca9301ff}\n theme_color:{tags: \"tab text weak\", value: 0x8c690eff}\n theme_color:{tags: \"tab inactive background\", value: 0x171718ff}\n theme_color:{tags: \"tab inactive border\", value: 0x1f1f27ff}\n theme_color:{tags: \"tab auto background\", value: 0x243b38ff}\n theme_color:{tags: \"tab auto border\", value: 0x478980ff}\n theme_color:{tags: \"tab auto inactive background\", value: 0x102623ff}\n theme_color:{tags: \"tab auto inactive border\", value: 0x1e5850ff}\n theme_color:{tags: \"drop_site background\", value: 0xffffff05}\n theme_color:{tags: \"drop_site border\", value: 0xffffff0f}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0x042327ff}\n theme_color:{tags: \"alt background\", value: 0x11b1fff}\n theme_color:{tags: \"pop background\", value: 0x355b6eff}\n theme_color:{tags: \"pop text\", value: 0xbad7e6ff}\n theme_color:{tags: \"fresh background\", value: 0x31393dff}\n theme_color:{tags: \"match background\", value: 0x31393dff}\n theme_color:{tags: border, value: 0x334d50ff}\n theme_color:{tags: text, value: 0xdad3beff}\n theme_color:{tags: \"weak text\", value: 0xb0a688ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: \"menu_bar good text\", value: 0x2a8242ff}\n theme_color:{tags: \"menu_bar neutral text\", value: 0x5681ff}\n theme_color:{tags: \"menu_bar bad text\", value: 0xa21200ff}\n theme_color:{tags: \"menu_bar weak text\", value: 0x313131ff}\n theme_color:{tags: \"menu_bar bad_pop text weak\", value: 0xffffffff}\n theme_color:{tags: hover, value: 0xffffffff}\n theme_color:{tags: \"focus overlay\", value: 0x86e08e20}\n theme_color:{tags: \"focus border\", value: 0x86e08fff}\n theme_color:{tags: cursor, value: 0x86e08fff}\n theme_color:{tags: selection, value: 0x99ccff0f}\n theme_color:{tags: \"inactive background\", value: 0x0000002f}\n theme_color:{tags: drop_shadow, value: 0x0000007f}\n theme_color:{tags: \"good_pop background\", value: 0x2c5b36ff}\n theme_color:{tags: \"good_pop border\", value: 0x568761ff}\n theme_color:{tags: \"good_pop hover\", value: 0xe3f5d3ff}\n theme_color:{tags: \"good_pop weak text\", value: 0xe3f5d3ff}\n theme_color:{tags: \"bad_pop background\", value: 0x803425ff}\n theme_color:{tags: \"bad_pop hover\", value: 0xff825cff}\n theme_color:{tags: code_default, value: 0xbdb395ff}\n theme_color:{tags: code_symbol, value: 0xcbe0f5ff}\n theme_color:{tags: code_type, value: 0xcbe0f5ff}\n theme_color:{tags: code_local, value: 0xd9cfb3ff}\n theme_color:{tags: code_register, value: 0xb7afd5ff}\n theme_color:{tags: code_keyword, value: 0x9de3c0ff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x767676ff}\n theme_color:{tags: code_numeric, value: 0x2ca198ff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x217770ff}\n theme_color:{tags: code_string, value: 0x2ca198ff}\n theme_color:{tags: code_meta, value: 0xB0FFB0ff}\n theme_color:{tags: code_comment, value: 0x31b72cff}\n theme_color:{tags: line_info_0, value: 0x4f3022ff}\n theme_color:{tags: line_info_1, value: 0x4f3e15ff}\n theme_color:{tags: line_info_2, value: 0x434e2aff}\n theme_color:{tags: line_info_3, value: 0x36241fff}\n theme_color:{tags: thread_0, value: 0xffcb7fff}\n theme_color:{tags: thread_1, value: 0xb2ff65ff}\n theme_color:{tags: thread_unwound, value: 0xb2ccd8ff}\n theme_color:{tags: thread_error, value: 0xb23219ff}\n theme_color:{tags: breakpoint, value: 0xa72911ff}\n theme_color:{tags: \"floating background\", value: 0x3232792}\n theme_color:{tags: \"floating background alt\", value: 0x0000005f}\n theme_color:{tags: \"floating background fresh\", value: 0x31393d5f}\n theme_color:{tags: \"floating scroll_bar background\", value: 0xe363bff}\n theme_color:{tags: \"menu_bar background\", value: 0xb59e7aff}\n theme_color:{tags: \"menu_bar text\", value: 0xff}\n theme_color:{tags: \"menu_bar border\", value: 0x947d5aff}\n theme_color:{tags: \"scroll_bar background\", value: 0xe363bff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0x13533aff}\n theme_color:{tags: \"tab border\", value: 0x6c9182ff}\n theme_color:{tags: \"tab inactive background\", value: 0x0}\n theme_color:{tags: \"tab inactive border\", value: 0x947d5a6c}\n theme_color:{tags: \"tab auto background\", value: 0x5b3939ff}\n theme_color:{tags: \"tab auto border\", value: 0x875c5cff}\n theme_color:{tags: \"tab auto inactive background\", value: 0x251b1bff}\n theme_color:{tags: \"tab auto inactive border\", value: 0x563d3dff}\n theme_color:{tags: \"drop_site background\", value: 0xffffff05}\n theme_color:{tags: \"drop_site border\", value: 0xffffff0f}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background,value: 0xc0c0cff}\n theme_color:{tags: \"alt background\", value: 0x131313ff}\n theme_color:{tags: \"pop background\", value: 0x4c00ff}\n theme_color:{tags: \"fresh background\", value: 0x4c00ff}\n theme_color:{tags: \"match background\", value: 0x4c00ff}\n theme_color:{tags: border, value: 0x272727ff}\n theme_color:{tags: text, value: 0x90b080ff}\n theme_color:{tags: \"weak text\", value: 0x6b845fff}\n theme_color:{tags: \"menu_bar background\", value: 0x888888ff}\n theme_color:{tags: \"menu_bar text\", value: 0x20202ff}\n theme_color:{tags: \"menu_bar text weak\", value: 0x525252ff}\n theme_color:{tags: \"good text\", value: 0x32a852ff}\n theme_color:{tags: \"neutral text\", value: 0x3a90bbff}\n theme_color:{tags: \"bad text\", value: 0xcf5242ff}\n theme_color:{tags: hover, value: 0xee00ff}\n theme_color:{tags: \"focus overlay\", value: 0xee0012}\n theme_color:{tags: \"focus border\", value: 0x00ee00ff}\n theme_color:{tags: cursor, value: 0x00ee00ff}\n theme_color:{tags: selection, value: 0x99ccff0f}\n theme_color:{tags: \"inactive background\", value: 0x0000002f}\n theme_color:{tags: drop_shadow, value: 0x0000007f}\n theme_color:{tags: \"good_pop background\", value: 0x4900ff}\n theme_color:{tags: \"good_pop border\", value: 0x4900ff}\n theme_color:{tags: \"bad_pop background\", value: 0x430b00ff}\n theme_color:{tags: code_default, value: 0x90b080ff}\n theme_color:{tags: code_symbol, value: 0xbfd9b2ff}\n theme_color:{tags: code_type, value: 0xbfd9b2ff}\n theme_color:{tags: code_local, value: 0xbfd9b2ff}\n theme_color:{tags: code_register, value: 0xb84cffff}\n theme_color:{tags: code_keyword, value: 0xd08f1fff}\n theme_color:{tags: code_delimiter_or_operator, value: 0x90b080ff}\n theme_color:{tags: code_numeric, value: 0x50ff2fff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0x30af18ff}\n theme_color:{tags: code_string, value: 0x50ff2fff}\n theme_color:{tags: code_meta, value: 0x90b080ff}\n theme_color:{tags: code_comment, value: 0x1f90f0ff}\n theme_color:{tags: line_info_0, value: 0xa253dff}\n theme_color:{tags: line_info_1, value: 0x9103dff}\n theme_color:{tags: line_info_2, value: 0x1e083dff}\n theme_color:{tags: line_info_3, value: 0x1e083dff}\n theme_color:{tags: thread_0, value: 0xd08f1fff}\n theme_color:{tags: thread_1, value: 0x1ea5d0ff}\n theme_color:{tags: thread_unwound, value: 0xb2ccd8ff}\n theme_color:{tags: thread_error, value: 0xb23219ff}\n theme_color:{tags: breakpoint, value: 0xa72911ff}\n theme_color:{tags: \"scroll_bar background\", value: 0x1d1d1dff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0x15490cff}\n theme_color:{tags: \"tab border\", value: 0x15490cff}\n theme_color:{tags: \"tab text\", value: 0x90b080ff}\n theme_color:{tags: \"tab text weak\", value: 0x90b080ff}\n theme_color:{tags: \"tab inactive background\", value: 0x21321eff}\n theme_color:{tags: \"tab inactive border\", value: 0x21321eff}\n theme_color:{tags: \"tab auto background\", value: 0x674f3eff}\n theme_color:{tags: \"tab auto border\", value: 0x674f3eff}\n theme_color:{tags: \"tab auto inactive background\", value: 0x47382eff}\n theme_color:{tags: \"tab auto inactive border\", value: 0x47382eff}\n theme_color:{tags: \"drop_site background\", value: 0xffffff05}\n theme_color:{tags: \"drop_site border\", value: 0xffffff0f}\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{ tags: background , value: 0x1b1f22ff }\n theme_color:{ tags: \"alt background\" , value: 0x232929ff }\n theme_color:{ tags: \"pop background\" , value: 0x2f4838ff }\n theme_color:{ tags: \"fresh background\" , value: 0x31393dff }\n theme_color:{ tags: \"match background\" , value: 0x31393dff }\n theme_color:{ tags: border , value: 0x485347ff }\n theme_color:{ tags: text , value: 0xffffffff }\n theme_color:{ tags: \"weak text\" , value: 0xa2a2a2ff }\n theme_color:{ tags: \"good text\" , value: 0x32a852ff }\n theme_color:{ tags: \"neutral text\" , value: 0x3a90bbff }\n theme_color:{ tags: \"bad text\" , value: 0xcf5242ff }\n theme_color:{ tags: hover , value: 0xffffffff }\n theme_color:{ tags: \"focus overlay\" , value: 0xfda20012 }\n theme_color:{ tags: \"focus border\" , value: 0xfda200ff }\n theme_color:{ tags: cursor , value: 0x8aff00ff }\n theme_color:{ tags: selection , value: 0x99ccff0f }\n theme_color:{ tags: \"inactive background\" , value: 0x0 }\n theme_color:{ tags: drop_shadow , value: 0x0000007f }\n theme_color:{ tags: \"good_pop background\" , value: 0x2c5b36ff }\n theme_color:{ tags: \"good_pop border\" , value: 0x568761ff }\n theme_color:{ tags: \"good_pop hover\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"good_pop weak text\" , value: 0xe3f5d3ff }\n theme_color:{ tags: \"bad_pop background\" , value: 0x803425ff }\n theme_color:{ tags: \"bad_pop hover\" , value: 0xff825cff }\n theme_color:{ tags: code_default , value: 0xad8b69ff }\n theme_color:{ tags: code_symbol , value: 0x87ad6aff }\n theme_color:{ tags: code_type , value: 0xb67474ff }\n theme_color:{ tags: code_local , value: 0xe9bf95ff }\n theme_color:{ tags: code_register , value: 0xa688b2ff }\n theme_color:{ tags: code_keyword , value: 0xe49e17ff }\n theme_color:{ tags: code_delimiter_or_operator , value: 0x795e43ff }\n theme_color:{ tags: code_numeric , value: 0x98b19eff }\n theme_color:{ tags: code_numeric_alt_digit_group , value: 0x688b71ff }\n theme_color:{ tags: code_string , value: 0x98b19eff }\n theme_color:{ tags: code_meta , value: 0xad5979ff }\n theme_color:{ tags: code_comment , value: 0x52675dff }\n theme_color:{ tags: line_info_0 , value: 0x4f3022ff }\n theme_color:{ tags: line_info_1 , value: 0x4f3e15ff }\n theme_color:{ tags: line_info_2 , value: 0x434e2aff }\n theme_color:{ tags: line_info_3 , value: 0x36241fff }\n theme_color:{ tags: line_info_4 , value: 0x4f3022ff }\n theme_color:{ tags: line_info_5 , value: 0x4f3e15ff }\n theme_color:{ tags: line_info_6 , value: 0x434e2aff }\n theme_color:{ tags: line_info_7 , value: 0x36241fff }\n theme_color:{ tags: thread_0 , value: 0xffc258ff }\n theme_color:{ tags: thread_1 , value: 0x82d331ff }\n theme_color:{ tags: thread_2 , value: 0xff99e5ff }\n theme_color:{ tags: thread_3 , value: 0x6598ffff }\n theme_color:{ tags: thread_4 , value: 0x65ffcbff }\n theme_color:{ tags: thread_5 , value: 0xff9819ff }\n theme_color:{ tags: thread_6 , value: 0x9932ffff }\n theme_color:{ tags: thread_7 , value: 0x65ff4cff }\n theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff }\n theme_color:{ tags: thread_error , value: 0xb23219ff }\n theme_color:{ tags: breakpoint , value: 0xa72911ff }\n theme_color:{ tags: \"floating background\" , value: 0x1b1f2276 }\n theme_color:{ tags: \"floating background alt\" , value: 0x0000005f }\n theme_color:{ tags: \"floating background fresh\" , value: 0x31393d5f }\n theme_color:{ tags: \"floating border\" , value: 0xbfbfbf1f }\n theme_color:{ tags: \"floating scroll_bar background\" , value: 0x3b3b3b5f }\n theme_color:{ tags: \"floating scroll_bar border\" , value: 0x5f5f5f5f }\n theme_color:{ tags: \"menu_bar background\" , value: 0x243d32ff }\n theme_color:{ tags: \"menu_bar border\" , value: 0x597b63ff }\n theme_color:{ tags: \"scroll_bar background\" , value: 0x232929ff }\n theme_color:{ tags: \"scroll_bar border\" , value: 0x3c4a3fff }\n theme_color:{ tags: \"implicit background\" , value: 0x00000000 }\n theme_color:{ tags: \"implicit border\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow background\" , value: 0x00000000 }\n theme_color:{ tags: \"hollow border\" , value: 0xffffff1f }\n theme_color:{ tags: \"tab background\" , value: 0x243d32ff }\n theme_color:{ tags: \"tab border\" , value: 0x597b63ff }\n theme_color:{ tags: \"tab inactive background\" , value: 0x30383eff }\n theme_color:{ tags: \"tab inactive border\" , value: 0x6b7680ff }\n theme_color:{ tags: \"tab auto background\" , value: 0x30636dff }\n theme_color:{ tags: \"tab auto border\" , value: 0x768f94ff }\n theme_color:{ tags: \"tab auto inactive background\" , value: 0x2f2633ff }\n theme_color:{ tags: \"tab auto inactive border\" , value: 0x685073ff }\n theme_color:{ tags: \"drop_site background\" , value: 0xffffff05 }\n theme_color:{ tags: \"drop_site border\" , value: 0xffffff0f }\n}\n"), +str8_lit_comp("theme:\n{\n theme_color:{tags: background, value: 0x000080ff}\n theme_color:{tags: \"pop background\", value: 0x8080ff}\n theme_color:{tags: \"fresh background\", value: 0x31393dff}\n theme_color:{tags: \"match background\", value: 0x31393dff}\n theme_color:{tags: border, value: 0x8080ff}\n theme_color:{tags: text, value: 0xffffffff}\n theme_color:{tags: \"weak text\", value: 0xffffffff}\n theme_color:{tags: \"good text\", value: 0x00ff00ff}\n theme_color:{tags: \"neutral text\", value: 0x00ffffff}\n theme_color:{tags: \"bad text\", value: 0xff0000ff}\n theme_color:{tags: hover, value: 0xffffffff}\n theme_color:{tags: \"focus overlay\", value: 0xffff0012}\n theme_color:{tags: \"focus border\", value: 0xffff00ff}\n theme_color:{tags: cursor, value: 0xffff00ff}\n theme_color:{tags: selection, value: 0xffff0018}\n theme_color:{tags: \"inactive background\", value: 0x0000002f}\n theme_color:{tags: drop_shadow, value: 0x0000007f}\n theme_color:{tags: \"good_pop background\", value: 0x6c17ff}\n theme_color:{tags: \"good_pop border\", value: 0x6c17ff}\n theme_color:{tags: \"bad_pop background\", value: 0xff0000ff}\n theme_color:{tags: code_default, value: 0xffffffff}\n theme_color:{tags: code_symbol, value: 0xffffff}\n theme_color:{tags: code_type, value: 0x00ff00ff}\n theme_color:{tags: code_local, value: 0x00ffffff}\n theme_color:{tags: code_register, value: 0xff00ffff}\n theme_color:{tags: code_keyword, value: 0xffffffff}\n theme_color:{tags: code_delimiter_or_operator, value: 0xffffffff}\n theme_color:{tags: code_numeric, value: 0xffff00ff}\n theme_color:{tags: code_numeric_alt_digit_group, value: 0xffff00ff}\n theme_color:{tags: code_string, value: 0xffff00ff}\n theme_color:{tags: code_meta, value: 0xff0000ff}\n theme_color:{tags: code_comment, value: 0x008080ff}\n theme_color:{tags: line_info_0, value: 0x8080ff}\n theme_color:{tags: line_info_1, value: 0x800080ff}\n theme_color:{tags: line_info_2, value: 0x800000ff}\n theme_color:{tags: line_info_3, value: 0x08000ff}\n theme_color:{tags: thread_0, value: 0xffff00ff}\n theme_color:{tags: thread_1, value: 0x00ff00ff}\n theme_color:{tags: thread_unwound, value: 0x00ffffff}\n theme_color:{tags: thread_error, value: 0xff0000ff}\n theme_color:{tags: breakpoint, value: 0xff0000ff}\n theme_color:{tags: \"menu_bar background\", value: 0x008080ff}\n theme_color:{tags: \"menu_bar border\", value: 0x8080ff}\n theme_color:{tags: \"scroll_bar background\", value: 0x008080ff}\n theme_color:{tags: \"implicit background\", value: 0x00000000}\n theme_color:{tags: \"implicit border\", value: 0x00000000}\n theme_color:{tags: \"hollow background\", value: 0x00000000}\n theme_color:{tags: \"hollow border\", value: 0xffffff1f}\n theme_color:{tags: \"tab background\", value: 0x8080ff}\n theme_color:{tags: \"tab border\", value: 0x8080ff}\n theme_color:{tags: \"tab inactive background\", value:0}\n theme_color:{tags: \"tab auto background\", value: 0x800000ff}\n theme_color:{tags: \"tab auto border\", value: 0x8080ff}\n theme_color:{tags: \"tab auto inactive background\", value: 0x300000ff}\n theme_color:{tags: \"tab auto inactive border\", value: 0x8080ff}\n theme_color:{tags: \"drop_site background\", value: 0x80ff}\n theme_color:{tags: \"drop_site border\", value: 0xffffff}\n}\n"), }; C_LINKAGE_END diff --git a/src/raddbg/generated/raddbg.meta.h b/src/raddbg/generated/raddbg.meta.h index e466ec24..8d48807c 100644 --- a/src/raddbg/generated/raddbg.meta.h +++ b/src/raddbg/generated/raddbg.meta.h @@ -6,47 +6,6 @@ #ifndef RADDBG_META_H #define RADDBG_META_H -typedef enum RD_CfgSrc -{ -RD_CfgSrc_User, -RD_CfgSrc_Project, -RD_CfgSrc_CommandLine, -RD_CfgSrc_Transient, -RD_CfgSrc_COUNT, -} RD_CfgSrc; - -typedef enum RD_EntityKind -{ -RD_EntityKind_Nil, -RD_EntityKind_Root, -RD_EntityKind_AutoViewRule, -RD_EntityKind_FilePathMap, -RD_EntityKind_WatchPin, -RD_EntityKind_Watch, -RD_EntityKind_ViewRule, -RD_EntityKind_Breakpoint, -RD_EntityKind_Condition, -RD_EntityKind_Location, -RD_EntityKind_Target, -RD_EntityKind_Executable, -RD_EntityKind_Arguments, -RD_EntityKind_WorkingDirectory, -RD_EntityKind_EntryPoint, -RD_EntityKind_StdoutPath, -RD_EntityKind_StderrPath, -RD_EntityKind_StdinPath, -RD_EntityKind_Window, -RD_EntityKind_Panel, -RD_EntityKind_View, -RD_EntityKind_RecentProject, -RD_EntityKind_RecentFile, -RD_EntityKind_Source, -RD_EntityKind_Dest, -RD_EntityKind_ConversionTask, -RD_EntityKind_ConversionFail, -RD_EntityKind_COUNT, -} RD_EntityKind; - typedef enum RD_RegSlot { RD_RegSlot_Null, @@ -57,11 +16,12 @@ RD_RegSlot_Thread, RD_RegSlot_CtrlEntity, RD_RegSlot_Window, RD_RegSlot_Panel, +RD_RegSlot_Tab, RD_RegSlot_View, -RD_RegSlot_PrevView, +RD_RegSlot_PrevTab, RD_RegSlot_DstPanel, -RD_RegSlot_Entity, -RD_RegSlot_EntityList, +RD_RegSlot_Cfg, +RD_RegSlot_CfgList, RD_RegSlot_UnwindCount, RD_RegSlot_InlineDepth, RD_RegSlot_FilePath, @@ -75,9 +35,18 @@ RD_RegSlot_Vaddr, RD_RegSlot_Voff, RD_RegSlot_VaddrRange, RD_RegSlot_VoffRange, +RD_RegSlot_Expr, +RD_RegSlot_UIKey, +RD_RegSlot_OffPx, +RD_RegSlot_RegSlot, RD_RegSlot_PID, RD_RegSlot_ForceConfirm, +RD_RegSlot_ForceFocus, RD_RegSlot_PreferDisasm, +RD_RegSlot_NoRichTooltip, +RD_RegSlot_DoImplicitRoot, +RD_RegSlot_DoLister, +RD_RegSlot_DoBigRows, RD_RegSlot_Dir2, RD_RegSlot_String, RD_RegSlot_CmdName, @@ -90,7 +59,7 @@ typedef enum RD_CmdKind { RD_CmdKind_Null, RD_CmdKind_LaunchAndRun, -RD_CmdKind_LaunchAndInit, +RD_CmdKind_LaunchAndStepInto, RD_CmdKind_Kill, RD_CmdKind_KillAll, RD_CmdKind_Detach, @@ -104,7 +73,6 @@ RD_CmdKind_Halt, RD_CmdKind_SoftHaltRefresh, RD_CmdKind_SetThreadIP, RD_CmdKind_RunToLine, -RD_CmdKind_RunToAddress, RD_CmdKind_Run, RD_CmdKind_Restart, RD_CmdKind_StepInto, @@ -123,24 +91,30 @@ RD_CmdKind_SetEntityColor, RD_CmdKind_SetEntityName, RD_CmdKind_Attach, RD_CmdKind_Exit, +RD_CmdKind_OpenPalette, RD_CmdKind_RunCommand, RD_CmdKind_OSEvent, RD_CmdKind_SelectThread, RD_CmdKind_SelectUnwind, RD_CmdKind_UpOneFrame, RD_CmdKind_DownOneFrame, -RD_CmdKind_IncUIFontScale, -RD_CmdKind_DecUIFontScale, -RD_CmdKind_IncCodeFontScale, -RD_CmdKind_DecCodeFontScale, +RD_CmdKind_SelectEntity, +RD_CmdKind_DeselectEntity, +RD_CmdKind_IncWindowFontSize, +RD_CmdKind_DecWindowFontSize, +RD_CmdKind_IncViewFontSize, +RD_CmdKind_DecViewFontSize, RD_CmdKind_OpenWindow, +RD_CmdKind_WindowSettings, RD_CmdKind_CloseWindow, RD_CmdKind_ToggleFullscreen, RD_CmdKind_BringToFront, RD_CmdKind_PopupAccept, RD_CmdKind_PopupCancel, +RD_CmdKind_ResetToDefaultBindings, RD_CmdKind_ResetToDefaultPanels, RD_CmdKind_ResetToCompactPanels, +RD_CmdKind_ResetToSimplePanels, RD_CmdKind_NewPanelLeft, RD_CmdKind_NewPanelUp, RD_CmdKind_NewPanelRight, @@ -159,30 +133,40 @@ RD_CmdKind_Redo, RD_CmdKind_GoBack, RD_CmdKind_GoForward, RD_CmdKind_ClosePanel, +RD_CmdKind_FocusTab, RD_CmdKind_NextTab, RD_CmdKind_PrevTab, RD_CmdKind_MoveTabRight, RD_CmdKind_MoveTabLeft, RD_CmdKind_OpenTab, +RD_CmdKind_BuildTab, +RD_CmdKind_DuplicateTab, +RD_CmdKind_CopyTabFullPath, RD_CmdKind_CloseTab, -RD_CmdKind_MoveTab, +RD_CmdKind_MoveView, RD_CmdKind_TabBarTop, RD_CmdKind_TabBarBottom, +RD_CmdKind_TabSettings, RD_CmdKind_SetCurrentPath, RD_CmdKind_Open, RD_CmdKind_Switch, RD_CmdKind_SwitchToPartnerFile, RD_CmdKind_RecordFileInProject, +RD_CmdKind_ShowFileInExplorer, RD_CmdKind_GoToDisassembly, RD_CmdKind_GoToSource, RD_CmdKind_SetFileReplacementPath, +RD_CmdKind_NewUser, +RD_CmdKind_NewProject, RD_CmdKind_OpenUser, RD_CmdKind_OpenProject, RD_CmdKind_OpenRecentProject, -RD_CmdKind_ApplyUserData, -RD_CmdKind_ApplyProjectData, +RD_CmdKind_SaveUser, +RD_CmdKind_SaveProject, RD_CmdKind_WriteUserData, RD_CmdKind_WriteProjectData, +RD_CmdKind_UserSettings, +RD_CmdKind_ProjectSettings, RD_CmdKind_Edit, RD_CmdKind_Accept, RD_CmdKind_Cancel, @@ -225,12 +209,12 @@ RD_CmdKind_Copy, RD_CmdKind_Cut, RD_CmdKind_Paste, RD_CmdKind_InsertText, +RD_CmdKind_MoveNext, +RD_CmdKind_MovePrev, RD_CmdKind_GoToLine, RD_CmdKind_GoToAddress, RD_CmdKind_CenterCursor, RD_CmdKind_ContainCursor, -RD_CmdKind_FindTextForward, -RD_CmdKind_FindTextBackward, RD_CmdKind_FindNext, RD_CmdKind_FindPrev, RD_CmdKind_FindThread, @@ -240,26 +224,33 @@ RD_CmdKind_GoToNameAtCursor, RD_CmdKind_ToggleWatchExpression, RD_CmdKind_ToggleWatchExpressionAtCursor, RD_CmdKind_ToggleWatchExpressionAtMouse, -RD_CmdKind_SetColumns, -RD_CmdKind_ToggleAddressVisibility, -RD_CmdKind_ToggleCodeBytesVisibility, -RD_CmdKind_EnableEntity, -RD_CmdKind_DisableEntity, -RD_CmdKind_SelectEntity, -RD_CmdKind_RemoveEntity, -RD_CmdKind_NameEntity, -RD_CmdKind_ConditionEntity, -RD_CmdKind_DuplicateEntity, -RD_CmdKind_RelocateEntity, +RD_CmdKind_EnableCfg, +RD_CmdKind_DisableCfg, +RD_CmdKind_SelectCfg, +RD_CmdKind_DeselectCfg, +RD_CmdKind_RemoveCfg, +RD_CmdKind_NameCfg, +RD_CmdKind_ConditionCfg, +RD_CmdKind_DuplicateCfg, +RD_CmdKind_RelocateCfg, +RD_CmdKind_SaveToProject, RD_CmdKind_AddBreakpoint, RD_CmdKind_AddAddressBreakpoint, RD_CmdKind_AddFunctionBreakpoint, RD_CmdKind_ToggleBreakpoint, RD_CmdKind_EnableBreakpoint, RD_CmdKind_DisableBreakpoint, +RD_CmdKind_ClearBreakpoints, RD_CmdKind_AddWatchPin, RD_CmdKind_ToggleWatchPin, -RD_CmdKind_RunToCursor, +RD_CmdKind_AddTypeView, +RD_CmdKind_AddFilePathMap, +RD_CmdKind_EditUserTheme, +RD_CmdKind_EditProjectTheme, +RD_CmdKind_AddThemeColor, +RD_CmdKind_ForkTheme, +RD_CmdKind_SaveTheme, +RD_CmdKind_SaveAndSetTheme, RD_CmdKind_SetNextStatement, RD_CmdKind_AddTarget, RD_CmdKind_SelectTarget, @@ -267,41 +258,43 @@ RD_CmdKind_EnableTarget, RD_CmdKind_DisableTarget, RD_CmdKind_RegisterAsJITDebugger, RD_CmdKind_FindCodeLocation, -RD_CmdKind_Filter, -RD_CmdKind_ApplyFilter, -RD_CmdKind_ClearFilter, -RD_CmdKind_GettingStarted, -RD_CmdKind_Commands, -RD_CmdKind_Target, -RD_CmdKind_Targets, -RD_CmdKind_FilePathMap, -RD_CmdKind_AutoViewRules, -RD_CmdKind_Breakpoints, -RD_CmdKind_WatchPins, -RD_CmdKind_Scheduler, -RD_CmdKind_CallStack, -RD_CmdKind_Modules, -RD_CmdKind_Watch, -RD_CmdKind_Locals, -RD_CmdKind_Registers, -RD_CmdKind_Globals, -RD_CmdKind_ThreadLocals, -RD_CmdKind_Types, -RD_CmdKind_Procedures, -RD_CmdKind_PendingFile, -RD_CmdKind_Disassembly, -RD_CmdKind_Output, -RD_CmdKind_Memory, -RD_CmdKind_ExceptionFilters, -RD_CmdKind_Settings, +RD_CmdKind_Search, +RD_CmdKind_SearchBackwards, RD_CmdKind_PickFile, RD_CmdKind_PickFolder, RD_CmdKind_PickFileOrFolder, +RD_CmdKind_PushQuery, RD_CmdKind_CompleteQuery, RD_CmdKind_CancelQuery, +RD_CmdKind_UpdateQuery, RD_CmdKind_ToggleDevMenu, RD_CmdKind_LogMarker, +RD_CmdKind_OpenWatch, +RD_CmdKind_OpenLocals, +RD_CmdKind_OpenRegisters, +RD_CmdKind_OpenGlobals, +RD_CmdKind_OpenThreadLocals, +RD_CmdKind_OpenTypes, +RD_CmdKind_OpenProcedures, +RD_CmdKind_OpenCallStack, +RD_CmdKind_OpenTargets, +RD_CmdKind_OpenBreakpoints, +RD_CmdKind_OpenWatchPins, +RD_CmdKind_OpenThreads, +RD_CmdKind_OpenProcesses, +RD_CmdKind_OpenMachines, +RD_CmdKind_OpenModules, +RD_CmdKind_OpenFilePathMaps, +RD_CmdKind_OpenTypeViews, +RD_CmdKind_OpenOutput, +RD_CmdKind_OpenText, +RD_CmdKind_OpenDisasm, +RD_CmdKind_OpenMemory, +RD_CmdKind_OpenBitmap, +RD_CmdKind_OpenColor, +RD_CmdKind_OpenGeo3D, RD_CmdKind_COUNT, +RD_CmdKind_FirstTabFastPathCmd = RD_CmdKind_OpenWatch, } RD_CmdKind; typedef enum RD_IconKind @@ -334,6 +327,7 @@ RD_IconKind_RadioHollow, RD_IconKind_RadioFilled, RD_IconKind_CheckHollow, RD_IconKind_CheckFilled, +RD_IconKind_Check, RD_IconKind_LeftCaret, RD_IconKind_RightCaret, RD_IconKind_UpCaret, @@ -375,129 +369,32 @@ RD_IconKind_QuestionMark, RD_IconKind_Person, RD_IconKind_Briefcase, RD_IconKind_Dot, +RD_IconKind_Bitmap, +RD_IconKind_Cube, +RD_IconKind_WindowRestore, +RD_IconKind_WindowMinimize, +RD_IconKind_Duplicate, RD_IconKind_COUNT, } RD_IconKind; -typedef enum RD_ViewRuleKind +typedef enum RD_CodeColorSlot { -RD_ViewRuleKind_Null, -RD_ViewRuleKind_Empty, -RD_ViewRuleKind_GettingStarted, -RD_ViewRuleKind_ExceptionFilters, -RD_ViewRuleKind_Settings, -RD_ViewRuleKind_PendingFile, -RD_ViewRuleKind_Commands, -RD_ViewRuleKind_FileSystem, -RD_ViewRuleKind_SystemProcesses, -RD_ViewRuleKind_EntityLister, -RD_ViewRuleKind_CtrlEntityLister, -RD_ViewRuleKind_SymbolLister, -RD_ViewRuleKind_Watch, -RD_ViewRuleKind_Locals, -RD_ViewRuleKind_Registers, -RD_ViewRuleKind_Globals, -RD_ViewRuleKind_ThreadLocals, -RD_ViewRuleKind_Types, -RD_ViewRuleKind_Procedures, -RD_ViewRuleKind_Targets, -RD_ViewRuleKind_FilePathMap, -RD_ViewRuleKind_AutoViewRules, -RD_ViewRuleKind_Breakpoints, -RD_ViewRuleKind_WatchPins, -RD_ViewRuleKind_Scheduler, -RD_ViewRuleKind_CallStack, -RD_ViewRuleKind_Modules, -RD_ViewRuleKind_Text, -RD_ViewRuleKind_Disasm, -RD_ViewRuleKind_Output, -RD_ViewRuleKind_Memory, -RD_ViewRuleKind_Bitmap, -RD_ViewRuleKind_Checkbox, -RD_ViewRuleKind_ColorRGBA, -RD_ViewRuleKind_Geo3D, -RD_ViewRuleKind_COUNT, -} RD_ViewRuleKind; - -typedef enum RD_ThemeColor -{ -RD_ThemeColor_Null, -RD_ThemeColor_Text, -RD_ThemeColor_TextPositive, -RD_ThemeColor_TextNegative, -RD_ThemeColor_TextNeutral, -RD_ThemeColor_TextWeak, -RD_ThemeColor_Cursor, -RD_ThemeColor_CursorInactive, -RD_ThemeColor_Focus, -RD_ThemeColor_Hover, -RD_ThemeColor_DropShadow, -RD_ThemeColor_DisabledOverlay, -RD_ThemeColor_DropSiteOverlay, -RD_ThemeColor_InactivePanelOverlay, -RD_ThemeColor_SelectionOverlay, -RD_ThemeColor_HighlightOverlay, -RD_ThemeColor_HighlightOverlayError, -RD_ThemeColor_BaseBackground, -RD_ThemeColor_BaseBackgroundAlt, -RD_ThemeColor_BaseBorder, -RD_ThemeColor_MenuBarBackground, -RD_ThemeColor_MenuBarBackgroundAlt, -RD_ThemeColor_MenuBarBorder, -RD_ThemeColor_FloatingBackground, -RD_ThemeColor_FloatingBackgroundAlt, -RD_ThemeColor_FloatingBorder, -RD_ThemeColor_ImplicitButtonBackground, -RD_ThemeColor_ImplicitButtonBorder, -RD_ThemeColor_PlainButtonBackground, -RD_ThemeColor_PlainButtonBorder, -RD_ThemeColor_PositivePopButtonBackground, -RD_ThemeColor_PositivePopButtonBorder, -RD_ThemeColor_NegativePopButtonBackground, -RD_ThemeColor_NegativePopButtonBorder, -RD_ThemeColor_NeutralPopButtonBackground, -RD_ThemeColor_NeutralPopButtonBorder, -RD_ThemeColor_ScrollBarButtonBackground, -RD_ThemeColor_ScrollBarButtonBorder, -RD_ThemeColor_TabBackground, -RD_ThemeColor_TabBorder, -RD_ThemeColor_TabBackgroundInactive, -RD_ThemeColor_TabBorderInactive, -RD_ThemeColor_CodeDefault, -RD_ThemeColor_CodeSymbol, -RD_ThemeColor_CodeType, -RD_ThemeColor_CodeLocal, -RD_ThemeColor_CodeRegister, -RD_ThemeColor_CodeKeyword, -RD_ThemeColor_CodeDelimiterOperator, -RD_ThemeColor_CodeNumeric, -RD_ThemeColor_CodeNumericAltDigitGroup, -RD_ThemeColor_CodeString, -RD_ThemeColor_CodeMeta, -RD_ThemeColor_CodeComment, -RD_ThemeColor_CodeLineNumbers, -RD_ThemeColor_CodeLineNumbersSelected, -RD_ThemeColor_LineInfoBackground0, -RD_ThemeColor_LineInfoBackground1, -RD_ThemeColor_LineInfoBackground2, -RD_ThemeColor_LineInfoBackground3, -RD_ThemeColor_LineInfoBackground4, -RD_ThemeColor_LineInfoBackground5, -RD_ThemeColor_LineInfoBackground6, -RD_ThemeColor_LineInfoBackground7, -RD_ThemeColor_Thread0, -RD_ThemeColor_Thread1, -RD_ThemeColor_Thread2, -RD_ThemeColor_Thread3, -RD_ThemeColor_Thread4, -RD_ThemeColor_Thread5, -RD_ThemeColor_Thread6, -RD_ThemeColor_Thread7, -RD_ThemeColor_ThreadUnwound, -RD_ThemeColor_ThreadError, -RD_ThemeColor_Breakpoint, -RD_ThemeColor_CacheLineBoundary, -RD_ThemeColor_COUNT, -} RD_ThemeColor; +RD_CodeColorSlot_CodeDefault, +RD_CodeColorSlot_CodeSymbol, +RD_CodeColorSlot_CodeType, +RD_CodeColorSlot_CodeLocal, +RD_CodeColorSlot_CodeRegister, +RD_CodeColorSlot_CodeKeyword, +RD_CodeColorSlot_CodeDelimiterOperator, +RD_CodeColorSlot_CodeNumeric, +RD_CodeColorSlot_CodeNumericAltDigitGroup, +RD_CodeColorSlot_CodeString, +RD_CodeColorSlot_CodeMeta, +RD_CodeColorSlot_CodeComment, +RD_CodeColorSlot_CodeLineNumbers, +RD_CodeColorSlot_CodeLineNumbersSelected, +RD_CodeColorSlot_COUNT, +} RD_CodeColorSlot; typedef enum RD_ThemePreset { @@ -508,34 +405,29 @@ RD_ThemePreset_VSLight, RD_ThemePreset_SolarizedDark, RD_ThemePreset_SolarizedLight, RD_ThemePreset_HandmadeHero, +RD_ThemePreset_Naysayer, RD_ThemePreset_FourCoder, +RD_ThemePreset_Grove, RD_ThemePreset_FarManager, RD_ThemePreset_COUNT, } RD_ThemePreset; -typedef enum RD_SettingCode +typedef struct RD_VocabInfo RD_VocabInfo; +struct RD_VocabInfo { -RD_SettingCode_HoverAnimations, -RD_SettingCode_PressAnimations, -RD_SettingCode_FocusAnimations, -RD_SettingCode_TooltipAnimations, -RD_SettingCode_MenuAnimations, -RD_SettingCode_ScrollingAnimations, -RD_SettingCode_BackgroundBlur, -RD_SettingCode_ThreadLines, -RD_SettingCode_BreakpointLines, -RD_SettingCode_ThreadGlow, -RD_SettingCode_BreakpointGlow, -RD_SettingCode_OpaqueBackgrounds, -RD_SettingCode_TabWidth, -RD_SettingCode_MainFontSize, -RD_SettingCode_CodeFontSize, -RD_SettingCode_SmoothUIText, -RD_SettingCode_SmoothCodeText, -RD_SettingCode_HintUIText, -RD_SettingCode_HintCodeText, -RD_SettingCode_COUNT, -} RD_SettingCode; +String8 code_name; +String8 code_name_plural; +String8 display_name; +String8 display_name_plural; +RD_IconKind icon_kind; +}; + +typedef struct RD_NameSchemaInfo RD_NameSchemaInfo; +struct RD_NameSchemaInfo +{ +String8 name; +String8 schema; +}; typedef struct RD_Regs RD_Regs; struct RD_Regs @@ -545,19 +437,20 @@ CTRL_Handle module; CTRL_Handle process; CTRL_Handle thread; CTRL_Handle ctrl_entity; -RD_Handle window; -RD_Handle panel; -RD_Handle view; -RD_Handle prev_view; -RD_Handle dst_panel; -RD_Handle entity; -RD_HandleList entity_list; +RD_CfgID window; +RD_CfgID panel; +RD_CfgID tab; +RD_CfgID view; +RD_CfgID prev_tab; +RD_CfgID dst_panel; +RD_CfgID cfg; +RD_CfgIDList cfg_list; U64 unwind_count; U64 inline_depth; String8 file_path; TxtPt cursor; TxtPt mark; -U128 text_key; +HS_Key text_key; TXT_LangKind lang_kind; D_LineList lines; DI_Key dbgi_key; @@ -565,9 +458,18 @@ U64 vaddr; U64 voff; Rng1U64 vaddr_range; Rng1U64 voff_range; +String8 expr; +UI_Key ui_key; +Vec2F32 off_px; +RD_RegSlot reg_slot; U32 pid; B32 force_confirm; +B32 force_focus; B32 prefer_disasm; +B32 no_rich_tooltip; +B32 do_implicit_root; +B32 do_lister; +B32 do_big_rows; Dir2 dir2; String8 string; String8 cmd_name; @@ -580,8 +482,8 @@ struct RD_Query { RD_QueryFlags flags; RD_RegSlot slot; +String8 expr; String8 view_name; -RD_EntityKind entity_kind; CTRL_EntityKind ctrl_entity_kind; }; @@ -591,24 +493,37 @@ struct RD_CmdKindInfo String8 string; String8 description; String8 search_tags; -String8 display_name; -RD_IconKind icon_kind; +String8 ctx_filter; RD_CmdKindFlags flags; RD_Query query; }; -typedef struct RD_ViewRuleInfo RD_ViewRuleInfo; -struct RD_ViewRuleInfo -{ -String8 string; -String8 description; -String8 display_name; -String8 params_schema; -RD_IconKind icon_kind; -RD_ViewRuleInfoFlags flags; -EV_ViewRuleExprExpandInfoHookFunctionType *expr_expand_info; -RD_ViewRuleUIFunctionType *ui; -}; +#define RD_FixedTabXList \ +Y(watches, watch, "")\ +X(locals) \ +X(registers) \ +X(globals) \ +X(thread_locals) \ +X(types) \ +X(procedures) \ +X(call_stack) \ +X(targets) \ +X(breakpoints) \ +X(watch_pins) \ +X(threads) \ +X(processes) \ +X(machines) \ +X(modules) \ +X(file_path_maps) \ +X(type_views) \ +Y(output, text, "query:output")\ +Y(text, text, "")\ +Y(disasm, disasm, "")\ +Y(memory, memory, "")\ +Y(bitmap, bitmap, "")\ +Y(color, color, "")\ +Y(geo3d, geo3d, "")\ +Z(getting_started)\ #define rd_regs_lit_init_top \ .machine = rd_regs()->machine,\ @@ -618,11 +533,12 @@ RD_ViewRuleUIFunctionType *ui; .ctrl_entity = rd_regs()->ctrl_entity,\ .window = rd_regs()->window,\ .panel = rd_regs()->panel,\ +.tab = rd_regs()->tab,\ .view = rd_regs()->view,\ -.prev_view = rd_regs()->prev_view,\ +.prev_tab = rd_regs()->prev_tab,\ .dst_panel = rd_regs()->dst_panel,\ -.entity = rd_regs()->entity,\ -.entity_list = rd_regs()->entity_list,\ +.cfg = rd_regs()->cfg,\ +.cfg_list = rd_regs()->cfg_list,\ .unwind_count = rd_regs()->unwind_count,\ .inline_depth = rd_regs()->inline_depth,\ .file_path = rd_regs()->file_path,\ @@ -636,566 +552,424 @@ RD_ViewRuleUIFunctionType *ui; .voff = rd_regs()->voff,\ .vaddr_range = rd_regs()->vaddr_range,\ .voff_range = rd_regs()->voff_range,\ +.expr = rd_regs()->expr,\ +.ui_key = rd_regs()->ui_key,\ +.off_px = rd_regs()->off_px,\ +.reg_slot = rd_regs()->reg_slot,\ .pid = rd_regs()->pid,\ .force_confirm = rd_regs()->force_confirm,\ +.force_focus = rd_regs()->force_focus,\ .prefer_disasm = rd_regs()->prefer_disasm,\ +.no_rich_tooltip = rd_regs()->no_rich_tooltip,\ +.do_implicit_root = rd_regs()->do_implicit_root,\ +.do_lister = rd_regs()->do_lister,\ +.do_big_rows = rd_regs()->do_big_rows,\ .dir2 = rd_regs()->dir2,\ .string = rd_regs()->string,\ .cmd_name = rd_regs()->cmd_name,\ .params_tree = rd_regs()->params_tree,\ .os_event = rd_regs()->os_event,\ -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(watches); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(targets); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(breakpoints); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(watch_pins); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(file_path_maps); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(auto_view_rules); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(machines); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(processes); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(threads); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(modules); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(scheduler_machine); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(scheduler_process); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(locals); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(registers); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(globals); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(thread_locals); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(types); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(procedures); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(watches); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(targets); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(breakpoints); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(watch_pins); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(file_path_maps); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(auto_view_rules); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(machines); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(processes); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(threads); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(modules); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(scheduler_machine); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(scheduler_process); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(locals); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(registers); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(globals); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(thread_locals); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(types); -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(procedures); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(targets); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(breakpoints); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watch_pins); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(file_path_maps); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(auto_view_rules); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(machines); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(processes); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(threads); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(modules); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(scheduler_machine); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(scheduler_process); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(globals); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(thread_locals); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(types); -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(procedures); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(targets); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(breakpoints); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watch_pins); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(file_path_maps); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(auto_view_rules); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(machines); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(processes); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(threads); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(modules); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(scheduler_machine); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(scheduler_process); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(globals); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(thread_locals); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(types); -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(procedures); -RD_VIEW_RULE_UI_FUNCTION_DEF(null); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(text); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(disasm); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(memory); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(bitmap); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(color_rgba); -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(geo3d); -RD_VIEW_RULE_UI_FUNCTION_DEF(empty); -RD_VIEW_RULE_UI_FUNCTION_DEF(getting_started); -RD_VIEW_RULE_UI_FUNCTION_DEF(exception_filters); -RD_VIEW_RULE_UI_FUNCTION_DEF(settings); -RD_VIEW_RULE_UI_FUNCTION_DEF(pending_file); -RD_VIEW_RULE_UI_FUNCTION_DEF(commands); -RD_VIEW_RULE_UI_FUNCTION_DEF(file_system); -RD_VIEW_RULE_UI_FUNCTION_DEF(system_processes); -RD_VIEW_RULE_UI_FUNCTION_DEF(entity_lister); -RD_VIEW_RULE_UI_FUNCTION_DEF(ctrl_entity_lister); -RD_VIEW_RULE_UI_FUNCTION_DEF(symbol_lister); -RD_VIEW_RULE_UI_FUNCTION_DEF(watch); -RD_VIEW_RULE_UI_FUNCTION_DEF(locals); -RD_VIEW_RULE_UI_FUNCTION_DEF(registers); -RD_VIEW_RULE_UI_FUNCTION_DEF(globals); -RD_VIEW_RULE_UI_FUNCTION_DEF(thread_locals); -RD_VIEW_RULE_UI_FUNCTION_DEF(types); -RD_VIEW_RULE_UI_FUNCTION_DEF(procedures); -RD_VIEW_RULE_UI_FUNCTION_DEF(targets); -RD_VIEW_RULE_UI_FUNCTION_DEF(file_path_map); -RD_VIEW_RULE_UI_FUNCTION_DEF(auto_view_rules); -RD_VIEW_RULE_UI_FUNCTION_DEF(breakpoints); -RD_VIEW_RULE_UI_FUNCTION_DEF(watch_pins); -RD_VIEW_RULE_UI_FUNCTION_DEF(scheduler); -RD_VIEW_RULE_UI_FUNCTION_DEF(call_stack); -RD_VIEW_RULE_UI_FUNCTION_DEF(modules); -RD_VIEW_RULE_UI_FUNCTION_DEF(text); -RD_VIEW_RULE_UI_FUNCTION_DEF(disasm); -RD_VIEW_RULE_UI_FUNCTION_DEF(output); -RD_VIEW_RULE_UI_FUNCTION_DEF(memory); -RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap); -RD_VIEW_RULE_UI_FUNCTION_DEF(checkbox); -RD_VIEW_RULE_UI_FUNCTION_DEF(color_rgba); -RD_VIEW_RULE_UI_FUNCTION_DEF(geo3d); C_LINKAGE_BEGIN -extern String8 rd_cfg_src_string_table[4]; -extern RD_CmdKind rd_cfg_src_load_cmd_kind_table[4]; -extern RD_CmdKind rd_cfg_src_write_cmd_kind_table[4]; -extern RD_CmdKind rd_cfg_src_apply_cmd_kind_table[4]; -extern String8 d_entity_kind_display_string_table[27]; -extern String8 d_entity_kind_name_lower_table[27]; -extern String8 d_entity_kind_name_lower_plural_table[27]; -extern String8 d_entity_kind_name_label_table[27]; -extern RD_EntityKindFlags rd_entity_kind_flags_table[27]; -extern Rng1U64 rd_reg_slot_range_table[34]; -extern RD_StringBindingPair rd_default_binding_table[110]; +extern String8 rd_tab_fast_path_view_name_table[24]; +extern String8 rd_tab_fast_path_query_name_table[24]; +extern RD_VocabInfo rd_vocab_info_table[343]; +extern RD_NameSchemaInfo rd_name_schema_info_table[24]; +extern Rng1U64 rd_reg_slot_range_table[44]; extern String8 rd_binding_version_remap_old_name_table[8]; extern String8 rd_binding_version_remap_new_name_table[8]; -extern String8 rd_icon_kind_text_table[69]; -extern String8 rd_collection_name_table[18]; -extern RD_EntityKind rd_collection_entity_kind_table[18]; -extern CTRL_EntityKind rd_collection_ctrl_entity_kind_table[18]; -extern EV_ViewRuleExprExpandInfoHookFunctionType * rd_collection_expr_expand_info_hook_function_table[18]; -extern EV_ViewRuleExprExpandRangeInfoHookFunctionType * rd_collection_expr_expand_range_info_hook_function_table[18]; -extern EV_ViewRuleExprExpandIDFromNumHookFunctionType * rd_collection_expr_expand_id_from_num_hook_function_table[18]; -extern EV_ViewRuleExprExpandIDFromNumHookFunctionType * rd_collection_expr_expand_num_from_id_hook_function_table[18]; -extern RD_ViewRuleInfo rd_view_rule_kind_info_table[35]; -extern RD_IconKind rd_entity_kind_icon_kind_table[27]; -extern String8 rd_theme_preset_display_string_table[9]; -extern String8 rd_theme_preset_code_string_table[9]; -extern String8 rd_theme_color_version_remap_old_name_table[22]; -extern String8 rd_theme_color_version_remap_new_name_table[22]; -extern Vec4F32 rd_theme_preset_colors__default_dark[76]; -extern Vec4F32 rd_theme_preset_colors__default_light[76]; -extern Vec4F32 rd_theme_preset_colors__vs_dark[76]; -extern Vec4F32 rd_theme_preset_colors__vs_light[76]; -extern Vec4F32 rd_theme_preset_colors__solarized_dark[76]; -extern Vec4F32 rd_theme_preset_colors__solarized_light[76]; -extern Vec4F32 rd_theme_preset_colors__handmade_hero[76]; -extern Vec4F32 rd_theme_preset_colors__four_coder[76]; -extern Vec4F32 rd_theme_preset_colors__far_manager[76]; -extern Vec4F32* rd_theme_preset_colors_table[9]; -extern String8 rd_theme_color_display_string_table[76]; -extern String8 rd_theme_color_cfg_string_table[76]; -extern String8 rd_setting_code_display_string_table[19]; -extern String8 rd_setting_code_lower_string_table[19]; -extern B8 rd_setting_code_default_is_per_window_table[19]; -extern RD_SettingVal rd_setting_code_default_val_table[19]; -extern Rng1S32 rd_setting_code_s32_range_table[19]; +extern String8 rd_icon_kind_text_table[75]; +extern String8 rd_code_color_slot_name_table[14]; +extern String8 rd_theme_preset_display_string_table[11]; +extern String8 rd_theme_preset_code_string_table[11]; +extern String8 rd_theme_preset_cfg_string_table[11]; read_only global U8 rd_icon_font_bytes__data[] = { -0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x80,0x00,0x03,0x00,0x70,0x47,0x53,0x55,0x42,0x20,0x8b,0x25,0x7a,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x54,0x4f,0x53,0x2f,0x32,0x56,0x44,0x49,0xa0,0x00,0x00,0x01,0x50,0x00,0x00,0x00,0x60,0x63,0x6d,0x61,0x70,0x2a,0x09,0xe2,0xc2,0x00,0x00,0x01,0xb0,0x00,0x00,0x05,0xec,0x63,0x76,0x74,0x20, -0x0e,0x5d,0x06,0x6d,0x00,0x00,0x53,0xc0,0x00,0x00,0x00,0x38,0x66,0x70,0x67,0x6d,0x62,0x31,0xfb,0x7b,0x00,0x00,0x53,0xf8,0x00,0x00,0x0e,0x0c,0x67,0x61,0x73,0x70,0x00,0x00,0x00,0x10,0x00,0x00,0x53,0xb8,0x00,0x00,0x00,0x08,0x67,0x6c,0x79,0x66,0x3f,0x82,0x6a,0x1b,0x00,0x00,0x07,0x9c,0x00,0x00,0x43,0x86,0x68,0x65,0x61,0x64, -0x26,0x89,0x5f,0x83,0x00,0x00,0x4b,0x24,0x00,0x00,0x00,0x36,0x68,0x68,0x65,0x61,0x07,0x79,0x03,0xdb,0x00,0x00,0x4b,0x5c,0x00,0x00,0x00,0x24,0x68,0x6d,0x74,0x78,0xf3,0xce,0xff,0xc8,0x00,0x00,0x4b,0x80,0x00,0x00,0x01,0x30,0x6c,0x6f,0x63,0x61,0x8c,0xcb,0x7c,0x1e,0x00,0x00,0x4c,0xb0,0x00,0x00,0x00,0x9a,0x6d,0x61,0x78,0x70, -0x01,0xe3,0x0f,0x19,0x00,0x00,0x4d,0x4c,0x00,0x00,0x00,0x20,0x6e,0x61,0x6d,0x65,0xcd,0x9d,0x1a,0x1b,0x00,0x00,0x4d,0x6c,0x00,0x00,0x02,0xcd,0x70,0x6f,0x73,0x74,0x95,0xf6,0x72,0x8f,0x00,0x00,0x50,0x3c,0x00,0x00,0x03,0x79,0x70,0x72,0x65,0x70,0xeb,0x48,0xca,0x9d,0x00,0x00,0x62,0x04,0x00,0x00,0x00,0xa7,0x00,0x01,0x00,0x00, +0x00,0x01,0x00,0x00,0x00,0x0f,0x00,0x80,0x00,0x03,0x00,0x70,0x47,0x53,0x55,0x42,0x20,0x8b,0x25,0x7a,0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x54,0x4f,0x53,0x2f,0x32,0x56,0x43,0x62,0x25,0x00,0x00,0x01,0x50,0x00,0x00,0x00,0x60,0x63,0x6d,0x61,0x70,0xa3,0x60,0xa4,0x23,0x00,0x00,0x01,0xb0,0x00,0x00,0x06,0x12,0x63,0x76,0x74,0x20, +0x0e,0x1f,0x06,0xf3,0x00,0x00,0x51,0x34,0x00,0x00,0x00,0x38,0x66,0x70,0x67,0x6d,0x62,0x31,0xfb,0x7b,0x00,0x00,0x51,0x6c,0x00,0x00,0x0e,0x0c,0x67,0x61,0x73,0x70,0x00,0x00,0x00,0x10,0x00,0x00,0x51,0x2c,0x00,0x00,0x00,0x08,0x67,0x6c,0x79,0x66,0x71,0xda,0x4c,0xc8,0x00,0x00,0x07,0xc4,0x00,0x00,0x40,0x90,0x68,0x65,0x61,0x64, +0x2b,0xeb,0xd3,0xaf,0x00,0x00,0x48,0x54,0x00,0x00,0x00,0x36,0x68,0x68,0x65,0x61,0x07,0xc2,0x04,0x27,0x00,0x00,0x48,0x8c,0x00,0x00,0x00,0x24,0x68,0x6d,0x74,0x78,0x06,0x4b,0xff,0xca,0x00,0x00,0x48,0xb0,0x00,0x00,0x01,0x44,0x6c,0x6f,0x63,0x61,0x71,0xa6,0x82,0xac,0x00,0x00,0x49,0xf4,0x00,0x00,0x00,0xa4,0x6d,0x61,0x78,0x70, +0x01,0xe8,0x0f,0x19,0x00,0x00,0x4a,0x98,0x00,0x00,0x00,0x20,0x6e,0x61,0x6d,0x65,0xcd,0x9d,0x1c,0x1d,0x00,0x00,0x4a,0xb8,0x00,0x00,0x02,0xcd,0x70,0x6f,0x73,0x74,0x77,0x9e,0x36,0x3b,0x00,0x00,0x4d,0x88,0x00,0x00,0x03,0xa2,0x70,0x72,0x65,0x70,0xeb,0x48,0xca,0x9d,0x00,0x00,0x5f,0x78,0x00,0x00,0x00,0xa7,0x00,0x01,0x00,0x00, 0x00,0x0a,0x00,0x30,0x00,0x3e,0x00,0x02,0x44,0x46,0x4c,0x54,0x00,0x0e,0x6c,0x61,0x74,0x6e,0x00,0x1a,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x6c,0x69,0x67,0x61,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x04, -0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x03,0x35,0x01,0x90,0x00,0x05,0x00,0x00,0x02,0x7a,0x02,0xbc,0x00,0x00,0x00,0x8c,0x02,0x7a,0x02,0xbc,0x00,0x00,0x01,0xe0,0x00,0x31,0x01,0x02,0x00,0x00,0x02,0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x66,0x45,0x64,0x00,0xc0,0x00,0x21,0xe8,0x00,0x03,0x52,0xff,0x6a,0x00,0x5a,0x03,0xac,0x00,0x96,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x04, -0x00,0x00,0x02,0x58,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x52,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x2c,0x00,0x03,0x00,0x0a,0x00,0x00,0x02,0x58,0x00,0x04,0x01,0x26,0x00,0x00,0x00,0x20,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2e,0x00,0x31,0x00,0x35,0x00,0x39,0x00,0x3c,0x00,0x50,0x00,0x5b,0x00,0x5e, -0x00,0x73,0x00,0x7b,0x00,0x7d,0xe8,0x00,0xff,0xff,0x00,0x00,0x00,0x21,0x00,0x27,0x00,0x2b,0x00,0x2d,0x00,0x30,0x00,0x33,0x00,0x37,0x00,0x3c,0x00,0x3e,0x00,0x52,0x00,0x5d,0x00,0x61,0x00,0x75,0x00,0x7d,0xe8,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x20,0x00,0x24,0x00,0x24,0x00,0x24,0x00,0x26,0x00,0x28,0x00,0x2c,0x00,0x30,0x00,0x30,0x00,0x54,0x00,0x66,0x00,0x68,0x00,0x8c,0x00,0x98,0x00,0x98,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a, -0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a,0x00,0x1b,0x00,0x1c,0x00,0x1d,0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a, -0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a,0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a, -0x00,0x4b,0x00,0x00,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x06,0x07,0x00,0x08,0x09,0x00,0x0a,0x0b,0x0c,0x00,0x0d, -0x0e,0x0f,0x00,0x00,0x10,0x00,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x00,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x00,0x2e,0x2f,0x00,0x00,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x00,0x43,0x44,0x45, -0x46,0x47,0x48,0x49,0x00,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x03,0x3d,0x01,0x90,0x00,0x05,0x00,0x00,0x02,0x7a,0x02,0xbc,0x00,0x00,0x00,0x8c,0x02,0x7a,0x02,0xbc,0x00,0x00,0x01,0xe0,0x00,0x31,0x01,0x02,0x00,0x00,0x02,0x00,0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x66,0x45,0x64,0x00,0xc0,0x00,0x21,0x00,0x7d,0x03,0x52,0xff,0x6a,0x00,0x5a,0x03,0xac,0x00,0x96,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x04, +0x00,0x00,0x02,0x42,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x3c,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x2c,0x00,0x03,0x00,0x0a,0x00,0x00,0x02,0x42,0x00,0x04,0x01,0x10,0x00,0x00,0x00,0x18,0x00,0x10,0x00,0x03,0x00,0x08,0x00,0x23,0x00,0x2b,0x00,0x2e,0x00,0x31,0x00,0x39,0x00,0x3c,0x00,0x5b,0x00,0x5e,0x00,0x73,0x00,0x7b,0x00,0x7d, +0xff,0xff,0x00,0x00,0x00,0x21,0x00,0x26,0x00,0x2d,0x00,0x30,0x00,0x33,0x00,0x3c,0x00,0x3e,0x00,0x5d,0x00,0x61,0x00,0x75,0x00,0x7d,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x1c,0x00,0x26,0x00,0x28,0x00,0x2a,0x00,0x36, +0x00,0x36,0x00,0x70,0x00,0x72,0x00,0x96,0x00,0xa2,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,0x00,0x09,0x00,0x0a,0x00,0x0b,0x00,0x0c,0x00,0x0d,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x18,0x00,0x19,0x00,0x1a, +0x00,0x1b,0x00,0x1c,0x00,0x1d,0x00,0x1e,0x00,0x1f,0x00,0x20,0x00,0x21,0x00,0x22,0x00,0x23,0x00,0x24,0x00,0x25,0x00,0x26,0x00,0x27,0x00,0x28,0x00,0x29,0x00,0x2a,0x00,0x2b,0x00,0x2c,0x00,0x2d,0x00,0x2e,0x00,0x2f,0x00,0x30,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00,0x36,0x00,0x37,0x00,0x38,0x00,0x39,0x00,0x3a, +0x00,0x3b,0x00,0x3c,0x00,0x3d,0x00,0x3e,0x00,0x3f,0x00,0x40,0x00,0x41,0x00,0x42,0x00,0x43,0x00,0x44,0x00,0x45,0x00,0x46,0x00,0x47,0x00,0x48,0x00,0x49,0x00,0x4a,0x00,0x4b,0x00,0x4c,0x00,0x4d,0x00,0x4e,0x00,0x4f,0x00,0x50,0x00,0x00,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x00,0x00,0x04,0x05,0x06,0x07,0x08,0x09,0x00,0x0a,0x0b,0x00,0x0c,0x0d,0x00,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x00,0x00,0x15,0x00,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25, +0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x00,0x34,0x35,0x00,0x00,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x00,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x00,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x03,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x27, -0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x31, -0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x0e, -0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x41, -0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x46, -0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x1e, -0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x52, -0x00,0x00,0x00,0x52,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x53,0x00,0x00,0x00,0x25,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x57, -0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x2e, -0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x65, -0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,0x6a, -0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x6b,0x00,0x00,0x00,0x6b,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x3b,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x3e, -0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x76, -0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7b,0x00,0x00,0x00,0x7b, -0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x7d,0x00,0x00,0x00,0x7d,0x00,0x00,0x00,0x4a,0x00,0x00,0xe8,0x00,0x00,0x00,0xe8,0x00,0x00,0x00,0x00,0x4b,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x49,0x4b,0xb0,0x24,0x50,0x58,0x40,0x13,0x00,0x01,0x00,0x02,0x01,0x02,0x63,0x04,0x01,0x00,0x00,0x03,0x5f, -0x00,0x03,0x03,0x10,0x00,0x4e,0x1b,0x40,0x19,0x00,0x03,0x04,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x02,0x02,0x01,0x57,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x01,0x02,0x4f,0x59,0x40,0x0f,0x02,0x00,0x1e,0x1b,0x16,0x13,0x0a,0x07,0x00,0x0f,0x02,0x0f,0x05,0x07,0x16,0x2b,0x01,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32, -0x36,0x35,0x11,0x34,0x26,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x71,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x34,0x7c,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x02,0xc3,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x59, -0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x06,0x00,0x00,0xff,0xba,0x02,0x80,0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x39,0x00,0x42,0x00,0x4b,0x00,0x84,0x40,0x0d,0x39,0x30,0x2f,0x26,0x0d,0x0c,0x03,0x02,0x08,0x02,0x04,0x01,0x4c,0x4b,0xb0,0x16,0x50,0x58,0x40,0x25,0x08,0x0c,0x02,0x04,0x0b,0x01, -0x02,0x03,0x04,0x02,0x69,0x09,0x01,0x05,0x05,0x01,0x61,0x07,0x01,0x01,0x01,0x10,0x4d,0x0d,0x0a,0x02,0x03,0x03,0x00,0x61,0x06,0x01,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x23,0x07,0x01,0x01,0x09,0x01,0x05,0x04,0x01,0x05,0x69,0x08,0x0c,0x02,0x04,0x0b,0x01,0x02,0x03,0x04,0x02,0x69,0x0d,0x0a,0x02,0x03,0x03,0x00,0x61,0x06,0x01, -0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x1f,0x44,0x43,0x1e,0x1d,0x48,0x47,0x43,0x4b,0x44,0x4b,0x41,0x40,0x3d,0x3c,0x35,0x34,0x2b,0x2a,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x14,0x19,0x17,0x0e,0x07,0x1a,0x2b,0x13,0x14,0x07,0x11,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x03,0x34,0x26,0x22, -0x06,0x14,0x16,0x32,0x36,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xf0,0x48,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x32, -0x2a,0x38,0x28,0x28,0x38,0x2a,0x46,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x01,0xdc,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x02,0x8a,0x4c,0x22,0xfe,0x86,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0xfd,0x76,0x1e,0x28, -0x28,0x3a,0x28,0x28,0x02,0x30,0x28,0x3a,0x28,0x28,0x3a,0x28,0xfe,0x5c,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x6e,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x05,0x00,0x00,0xff,0xb1,0x03,0x12,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f, -0x00,0x37,0x00,0x5b,0x00,0x88,0x40,0x10,0x4b,0x39,0x02,0x08,0x06,0x29,0x21,0x19,0x11,0x09,0x01,0x06,0x01,0x00,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x2a,0x0a,0x01,0x08,0x00,0x06,0x08,0x59,0x0d,0x0b,0x02,0x06,0x04,0x02,0x02,0x00,0x01,0x06,0x00,0x69,0x00,0x07,0x07,0x0c,0x5f,0x00,0x0c,0x0c,0x10,0x4d,0x05,0x03,0x02,0x01, -0x01,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x28,0x00,0x0c,0x00,0x07,0x06,0x0c,0x07,0x67,0x0a,0x01,0x08,0x00,0x06,0x08,0x59,0x0d,0x0b,0x02,0x06,0x04,0x02,0x02,0x00,0x01,0x06,0x00,0x69,0x05,0x03,0x02,0x01,0x01,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x40,0x16,0x59,0x58,0x55,0x52,0x4f,0x4d,0x47,0x46,0x43, -0x40,0x26,0x22,0x13,0x26,0x26,0x26,0x26,0x26,0x23,0x0e,0x07,0x1f,0x2b,0x25,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x37,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x37,0x11,0x34,0x26,0x2b,0x01,0x22,0x06,0x15,0x11,0x14,0x16,0x3b,0x01,0x32,0x36,0x01,0x33, -0x27,0x26,0x27,0x23,0x06,0x07,0x05,0x15,0x14,0x06,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x37,0x3e,0x01,0x37,0x33,0x32,0x16,0x1f,0x01,0x33,0x32,0x16,0x01,0x1e,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8f,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08, -0x0a,0x8e,0x0a,0x07,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0xfe,0xd1,0xfa,0x1b,0x04,0x05,0xb1,0x06,0x04,0x01,0xeb,0x0a,0x08,0x36,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x35,0x08,0x0a,0x0a,0x08,0xac,0x27,0x09,0x2c,0x16,0xb2,0x17,0x2a,0x09,0x27,0xad,0x08,0x0a,0x52,0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x08, -0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x08,0x01,0x89,0x08,0x0a,0x0a,0x08,0xfe,0x77,0x08,0x0a,0x0a,0x02,0x32,0x41,0x05,0x01,0x01,0x05,0x53,0x24,0x08,0x0a,0xfd,0xef,0x2e,0x44,0x42,0x2e,0x02,0x13,0x0a,0x08,0x24,0x08,0x0a,0x5d,0x15,0x1c,0x01,0x1e,0x14,0x5d,0x0a,0x00,0x00,0x03,0x00,0x00,0xff,0xba,0x00,0xf0, -0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x62,0x40,0x09,0x13,0x0a,0x09,0x00,0x04,0x05,0x02,0x01,0x4c,0x4b,0xb0,0x16,0x50,0x58,0x40,0x1e,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x69,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x10,0x4d,0x06,0x01,0x04,0x04,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x1c,0x00,0x01,0x00, -0x03,0x02,0x01,0x03,0x69,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x69,0x06,0x01,0x04,0x04,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x0f,0x1e,0x1d,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x17,0x19,0x14,0x07,0x07,0x1a,0x2b,0x37,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07, -0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xa8,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0xa2,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x6e,0x1c, -0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x00,0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x23,0x00,0x30,0x00,0x6f,0x40,0x0a,0x0d,0x01,0x00,0x01,0x1f,0x01,0x04,0x03,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x26,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04, -0x01,0x03,0x04,0x7e,0x00,0x01,0x01,0x07,0x61,0x00,0x07,0x07,0x10,0x4d,0x00,0x04,0x04,0x06,0x62,0x00,0x06,0x06,0x11,0x06,0x4e,0x1b,0x40,0x24,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04,0x7e,0x00,0x07,0x00,0x01,0x00,0x07,0x01,0x67,0x00,0x04,0x04,0x06,0x62,0x00,0x06,0x06,0x11,0x06,0x4e, -0x59,0x40,0x0b,0x15,0x15,0x23,0x24,0x25,0x23,0x24,0x14,0x08,0x07,0x1e,0x2b,0x01,0x35,0x34,0x26,0x07,0x23,0x35,0x34,0x26,0x27,0x23,0x22,0x06,0x07,0x15,0x23,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x33,0x15,0x14,0x16,0x17,0x33,0x32,0x36,0x37,0x35,0x33,0x32,0x36,0x37,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02, -0xa7,0x16,0x0e,0x8f,0x16,0x0e,0x47,0x0f,0x14,0x01,0x8f,0x0e,0x16,0x01,0x14,0x0f,0x8f,0x16,0x0e,0x47,0x0f,0x14,0x01,0x8f,0x0e,0x16,0xb2,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x8f,0x0f,0x14,0x01,0x16,0x0e,0x8f,0x14,0x0f,0x48,0x0e,0x16,0x01,0x8f,0x0f,0x14,0x01,0x16,0x0e,0x8f, -0x14,0x33,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0f,0x00,0x1c,0x00,0x3c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x15,0x00,0x00,0x00,0x03,0x61,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x00,0x01, -0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x15,0x15,0x35,0x24,0x04,0x07,0x1a,0x2b,0x01,0x35,0x34,0x26,0x07,0x21,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x21,0x32,0x36,0x37,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02,0xa7,0x16,0x0e,0xfe,0x53,0x0e,0x16,0x01,0x14,0x0f,0x01, -0xad,0x0e,0x16,0xb2,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x33,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x01,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x28,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x01,0x01, -0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0xb4,0x15,0x13,0x02,0x07,0x18,0x2b,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x03,0x59,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x5e,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4, -0x74,0x74,0xc4,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x3c,0x01,0xed,0x00,0x0e,0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x35,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x36,0x33,0x21,0x32,0x16,0x02, -0x3b,0x0a,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x01,0xc9,0x0e,0x0b,0xfa,0x0b,0x0b,0xfa,0x0b,0x1c,0x16,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa0,0x03,0x0b,0x00,0x2d,0x00,0x42,0x00,0x8b,0x40,0x0a,0x3b,0x01,0x04,0x06,0x25,0x01,0x05,0x04,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x30,0x00, -0x07,0x01,0x02,0x01,0x07,0x02,0x80,0x00,0x06,0x02,0x04,0x02,0x06,0x04,0x80,0x00,0x04,0x05,0x02,0x04,0x05,0x7e,0x00,0x05,0x03,0x02,0x05,0x03,0x7e,0x00,0x03,0x00,0x00,0x03,0x00,0x64,0x00,0x02,0x02,0x01,0x5f,0x00,0x01,0x01,0x10,0x02,0x4e,0x1b,0x40,0x36,0x00,0x07,0x01,0x02,0x01,0x07,0x02,0x80,0x00,0x06,0x02,0x04,0x02,0x06, -0x04,0x80,0x00,0x04,0x05,0x02,0x04,0x05,0x7e,0x00,0x05,0x03,0x02,0x05,0x03,0x7e,0x00,0x01,0x00,0x02,0x06,0x01,0x02,0x67,0x00,0x03,0x00,0x00,0x03,0x57,0x00,0x03,0x03,0x00,0x60,0x00,0x00,0x03,0x00,0x50,0x59,0x40,0x0b,0x14,0x17,0x15,0x27,0x35,0x39,0x35,0x33,0x08,0x07,0x1e,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x35, -0x11,0x34,0x36,0x37,0x21,0x32,0x17,0x1e,0x01,0x0f,0x01,0x06,0x23,0x27,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x3d,0x01,0x34,0x3f,0x01,0x36,0x33,0x32,0x17,0x16,0x13,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x14,0x03,0x12,0x5e,0x43,0xfe,0x30, -0x43,0x5e,0x5e,0x43,0x01,0xd0,0x23,0x1e,0x09,0x03,0x07,0x1b,0x06,0x07,0x05,0x0d,0x0c,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x05,0x24,0x06,0x07,0x03,0x04,0x0b,0x81,0xfe,0x39,0x0d,0x24,0x0e,0xf0,0x0e,0x0e,0x3d,0x0e,0x24,0x0e,0x93,0x01,0x69,0x0d,0x24,0x0e,0x3e,0x0d,0x01,0x4b,0xb1,0x43,0x5e,0x5e,0x43,0x01, -0xd0,0x42,0x5e,0x01,0x0e,0x04,0x13,0x06,0x1c,0x05,0x01,0x03,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x8d,0x08,0x05,0x23,0x06,0x02,0x04,0x01,0x05,0xfe,0x3a,0x0e,0x0e,0xf0,0x0d,0x24,0x0e,0x3e,0x0d,0x0d,0x93,0x01,0x69,0x0d,0x0d,0x3d,0x0e,0x24,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0xb1,0x03,0x12,0x03,0x0b,0x00,0x0f, -0x00,0x1f,0x00,0x2f,0x00,0x3b,0x00,0x43,0x00,0x67,0x00,0xcf,0x40,0x10,0x57,0x45,0x02,0x06,0x08,0x29,0x21,0x19,0x11,0x09,0x01,0x06,0x00,0x01,0x02,0x4c,0x4b,0xb0,0x09,0x50,0x58,0x40,0x2f,0x00,0x09,0x0e,0x08,0x06,0x09,0x72,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00, -0x07,0x01,0x00,0x69,0x00,0x0e,0x0e,0x10,0x4d,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x1b,0x4b,0xb0,0x24,0x50,0x58,0x40,0x30,0x00,0x09,0x0e,0x08,0x0e,0x09,0x08,0x80,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00,0x07,0x01,0x00,0x69,0x00,0x0e,0x0e,0x10, -0x4d,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x1b,0x40,0x2d,0x00,0x0e,0x09,0x0e,0x85,0x00,0x09,0x08,0x09,0x85,0x0f,0x0d,0x02,0x08,0x0c,0x0a,0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00,0x07,0x01,0x00,0x69,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x59,0x59,0x40,0x1a, -0x65,0x64,0x61,0x5e,0x5b,0x59,0x53,0x52,0x4f,0x4c,0x49,0x47,0x41,0x3f,0x14,0x24,0x14,0x26,0x26,0x26,0x26,0x26,0x23,0x10,0x07,0x1f,0x2b,0x01,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b, -0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x13,0x11,0x21,0x11,0x14,0x1e,0x01,0x33,0x21,0x32,0x3e,0x01,0x01,0x33,0x27,0x26,0x27,0x23,0x06,0x07,0x05,0x15,0x14,0x06,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x37,0x3e,0x01,0x37,0x33,0x32,0x16,0x1f,0x01, -0x33,0x32,0x16,0x01,0x1e,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8f,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8e,0x0a,0x07,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x48,0xfe,0x0c,0x08,0x08,0x02,0x01,0xd0,0x02,0x08,0x08,0xfe,0x89,0xfa,0x1b,0x04,0x05,0xb1,0x06,0x04,0x01,0xeb,0x0a,0x08,0x36,0x34,0x25, -0xfe,0x30,0x25,0x34,0x01,0x35,0x08,0x0a,0x0a,0x08,0xac,0x27,0x09,0x2c,0x16,0xb2,0x17,0x2a,0x09,0x27,0xad,0x08,0x0a,0x01,0xb7,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0xfe,0x64,0x02,0x11, -0xfd,0xef,0x0c,0x14,0x0a,0x0a,0x14,0x02,0x65,0x41,0x05,0x01,0x01,0x05,0x53,0x24,0x08,0x0a,0xfd,0xef,0x2e,0x44,0x42,0x2e,0x02,0x13,0x0a,0x08,0x24,0x08,0x0a,0x5d,0x15,0x1c,0x01,0x1e,0x14,0x5d,0x0a,0x00,0x00,0x01,0x00,0x00,0xff,0x9c,0x03,0xac,0x03,0x20,0x00,0x2a,0x00,0x34,0x40,0x09,0x20,0x1e,0x16,0x12,0x04,0x00,0x01,0x01, -0x4c,0x4b,0xb0,0x17,0x50,0x58,0x40,0x0b,0x00,0x01,0x01,0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x00,0x00,0x01,0x61,0x00,0x01,0x01,0x10,0x00,0x4e,0x59,0xb5,0x1b,0x1a,0x13,0x02,0x07,0x17,0x2b,0x25,0x16,0x1d,0x01,0x21,0x35,0x34,0x37,0x3e,0x01,0x35,0x34,0x26,0x27,0x2e,0x03,0x27,0x34,0x36,0x3f,0x01,0x26, -0x27,0x26,0x36,0x32,0x16,0x0f,0x01,0x16,0x15,0x0e,0x03,0x07,0x0e,0x01,0x15,0x14,0x16,0x02,0xe0,0xcc,0xfc,0x54,0xcc,0x5e,0x44,0x2c,0x0a,0x02,0x0e,0x0e,0x0e,0x02,0x0a,0x04,0x04,0x08,0x04,0x04,0x5a,0xe0,0x5c,0x06,0x0c,0x12,0x02,0x0e,0x0e,0x0e,0x02,0x08,0x2e,0x46,0x80,0x48,0x32,0x6a,0x6a,0x32,0x48,0x22,0x46,0x3c,0x16,0x36, -0x2e,0x0c,0x0c,0x04,0x1e,0x1c,0x10,0x14,0x02,0x04,0x32,0x26,0x36,0x74,0x74,0x36,0x58,0x08,0x22,0x1c,0x1e,0x04,0x0c,0x0c,0x30,0x34,0x16,0x3c,0x46,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xb6,0x03,0xe8,0x03,0x08,0x00,0x18,0x00,0x20,0x00,0x2d,0x00,0xcc,0xb5,0x25,0x01,0x09,0x0b,0x01,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x30, -0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x72,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07,0x07,0x02,0x5f,0x00,0x02,0x02,0x10,0x4d,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x4b,0xb0,0x1f,0x50,0x58,0x40,0x31,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x09, -0x80,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07,0x07,0x02,0x5f,0x00,0x02,0x02,0x10,0x4d,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x2f,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x09,0x80,0x00,0x02,0x00,0x07,0x01,0x02,0x07,0x67,0x0c,0x01,0x05, -0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x59,0x40,0x1e,0x21,0x21,0x00,0x00,0x21,0x2d,0x21,0x2d,0x2c,0x2b,0x29,0x26,0x23,0x22,0x20,0x1d,0x1b,0x1a,0x00,0x18,0x00,0x18,0x12,0x24,0x35,0x22,0x11,0x0e,0x07,0x1b,0x2b,0x01,0x15, -0x21,0x13,0x36,0x3b,0x01,0x36,0x3f,0x01,0x3e,0x01,0x3b,0x01,0x32,0x16,0x17,0x16,0x17,0x33,0x32,0x17,0x13,0x21,0x35,0x03,0x07,0x21,0x27,0x26,0x2b,0x01,0x22,0x13,0x35,0x21,0x06,0x07,0x06,0x23,0x21,0x22,0x35,0x27,0x21,0x15,0x01,0xc8,0xfe,0x38,0x0a,0x04,0x60,0xa0,0x10,0x15,0x17,0x0e,0x12,0x1c,0xde,0x1a,0x14,0x0c,0x12,0x2a, -0xa0,0x60,0x04,0x0a,0xfe,0x3a,0xa4,0x1c,0x01,0x24,0x1c,0x0e,0x1c,0x98,0x1c,0x96,0x01,0xae,0x06,0x04,0x06,0x54,0xfd,0x12,0x5a,0x0a,0x01,0xae,0x01,0x46,0x64,0x01,0x24,0x6c,0x1a,0x29,0x2d,0x1a,0x0c,0x0e,0x18,0x20,0x50,0x6c,0xfe,0xdc,0x64,0x01,0x62,0x36,0x36,0x1a,0xfd,0x8a,0x64,0x58,0x4e,0x54,0x54,0xa6,0x64,0x00,0x00,0x00, -0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x67,0x02,0x7c,0x00,0x0d,0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x13,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x16,0x01,0x65,0x14,0x20,0x09,0xfa, -0x0a,0x0a,0xfa,0x0b,0x1c,0x18,0x02,0x58,0xfe,0x0c,0x0e,0x16,0x0b,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x41,0x02,0x7d,0x00,0x0e,0x00,0x0a,0xb7,0x00,0x00,0x00,0x76,0x14,0x01,0x07,0x17,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x26,0x35,0x11,0x34,0x3e,0x01,0x1f,0x01,0x16,0x01,0x41,0x0a,0xfa,0x0b, -0x1c,0x16,0x16,0x1c,0x0b,0xfa,0x0a,0x01,0x5e,0x0e,0x0b,0xfa,0x0b,0x16,0x0e,0x01,0xf4,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x00,0x00,0x01,0xff,0xff,0x00,0x00,0x02,0x3b,0x01,0xc9,0x00,0x0e,0x00,0x18,0x40,0x15,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x15,0x32,0x02,0x07,0x18,0x2b,0x25,0x14, -0x06,0x27,0x21,0x22,0x2e,0x01,0x3f,0x01,0x36,0x32,0x1f,0x01,0x16,0x02,0x3b,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x1e,0x0a,0xfa,0x0a,0xab,0x0e,0x16,0x01,0x14,0x1e,0x0b,0xfa,0x0a,0x0a,0xfa,0x0b,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x5e,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x03,0x01,0x00,0x01, -0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x19,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x17,0x16,0x14,0x0f,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x37,0x01,0x36,0x32,0x1f,0x01,0x16,0x01,0x5e,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0xfe,0xfc,0x06,0x06,0x01,0x04,0x05, -0x10,0x04,0x1c,0x06,0x02,0x22,0x07,0x05,0xdc,0xdb,0x06,0x0e,0x06,0x1c,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0x1c,0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x4c,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x0b,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01, -0x00,0x51,0x1c,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x17,0x01,0x16,0x01,0x4c,0x05,0xfe,0xfb,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x10,0x04,0x01,0x05,0x05,0x01,0x3a,0x07,0x05,0xfe,0xfb,0x05,0x05,0x1c,0x06,0x0e,0x06, -0xdb,0xdc,0x05,0x0e,0x06,0x1c,0x06,0x06,0xfe,0xfc,0x05,0x00,0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x16,0x00,0x3f,0x00,0x83,0x40,0x0b,0x38,0x36,0x02,0x03,0x05,0x13,0x01,0x02,0x03,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x00,0x06,0x00,0x03,0x02,0x06, -0x03,0x69,0x08,0x01,0x02,0x00,0x01,0x02,0x01,0x66,0x00,0x04,0x04,0x00,0x61,0x07,0x01,0x00,0x00,0x12,0x04,0x4e,0x1b,0x40,0x2b,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x07,0x01,0x00,0x00,0x04,0x06,0x00,0x04,0x69,0x00,0x06,0x00,0x03,0x02,0x06,0x03,0x69,0x08,0x01,0x02,0x01,0x01,0x02,0x59,0x08,0x01,0x02,0x02,0x01,0x62,0x00, -0x01,0x02,0x01,0x52,0x59,0x40,0x19,0x0a,0x09,0x01,0x00,0x27,0x26,0x22,0x20,0x1d,0x1b,0x11,0x0e,0x09,0x16,0x0a,0x16,0x05,0x04,0x00,0x08,0x01,0x08,0x09,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x13,0x32,0x36,0x35,0x36,0x26,0x2b,0x01,0x22,0x06,0x07,0x14,0x16,0x17,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x07, -0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x32,0x17,0x16,0x15,0x14,0x07,0x06,0x0f,0x01,0x06,0x0f,0x01,0x06,0x07,0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x3f,0x01,0x36,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xbc,0x1e,0x26,0x02,0x26,0x1e,0x02,0x1c,0x26,0x02,0x26,0x1c,0xa8,0x1a,0x6a,0x52, -0x40,0x28,0x44,0x04,0x6e,0x10,0x10,0x4e,0x0c,0x10,0x10,0x08,0x0c,0x16,0x0a,0x0a,0x15,0x0b,0x06,0x0e,0x04,0x6c,0x04,0x06,0x16,0x1c,0x2e,0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0xfd,0x1e,0x26,0x1c,0x1e,0x26,0x24,0x1c,0x1e,0x26,0x02,0x01,0x48,0x22,0x2c,0x4e,0x4c,0x1a,0x2a,0x68,0x04, -0x04,0x1a,0x1c,0x18,0x14,0x14,0x18,0x12,0x16,0x0c,0x08,0x0f,0x07,0x08,0x11,0x09,0x08,0x14,0x3a,0x08,0x04,0x0c,0x10,0x14,0x10,0x12,0x22,0x00,0x00,0x02,0x00,0x00,0xff,0xbd,0x03,0x4d,0x03,0x0b,0x00,0x08,0x00,0x1d,0x00,0x56,0xb5,0x00,0x01,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x10,0x00,0x00,0x00,0x02,0x5f,0x00, -0x02,0x02,0x10,0x4d,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x4b,0xb0,0x2a,0x50,0x58,0x40,0x0e,0x00,0x02,0x00,0x00,0x01,0x02,0x00,0x69,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x15,0x00,0x01,0x00,0x01,0x86,0x00,0x02,0x00,0x00,0x02,0x57,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x02,0x00,0x51,0x59,0x59,0xb5,0x38,0x1a,0x12,0x03,0x07, -0x19,0x2b,0x13,0x34,0x26,0x0e,0x01,0x1e,0x02,0x36,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x2e,0x01,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x17,0x01,0x16,0xfa,0x2a,0x3a,0x2c,0x02,0x28,0x3e,0x26,0x02,0x55,0x14,0xfe,0xee,0x16,0x3b,0x14,0xfe,0x71,0x15,0x1e,0x2a,0x1d,0xe9,0x1d,0x48,0x15,0x01,0x8f,0x14,0x02,0x58,0x1e,0x2a, -0x02,0x26,0x40,0x24,0x06,0x30,0xfe,0xd9,0x1e,0x15,0xfe,0xee,0x15,0x15,0x01,0x8f,0x15,0x48,0x1d,0xe8,0x1d,0x2a,0x01,0x1e,0x15,0xfe,0x71,0x15,0x00,0x0d,0x00,0x00,0xff,0xea,0x03,0xca,0x02,0xd2,0x00,0x03,0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x13,0x00,0x17,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2f,0x00,0x33, -0x00,0xfd,0x4b,0xb0,0x32,0x50,0x58,0x40,0x49,0x18,0x12,0x0c,0x03,0x06,0x00,0x07,0x00,0x06,0x07,0x80,0x20,0x19,0x13,0x1d,0x0d,0x05,0x07,0x03,0x00,0x07,0x03,0x7e,0x17,0x11,0x0b,0x03,0x05,0x02,0x04,0x02,0x05,0x04,0x80,0x16,0x10,0x0a,0x03,0x04,0x01,0x02,0x04,0x01,0x7e,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x1a,0x01,0x01,0x02, -0x01,0x63,0x14,0x1e,0x0f,0x08,0x1b,0x05,0x03,0x03,0x00,0x60,0x00,0x00,0x00,0x13,0x03,0x4e,0x1b,0x40,0x54,0x18,0x12,0x0c,0x03,0x06,0x00,0x07,0x00,0x06,0x07,0x80,0x20,0x19,0x13,0x1d,0x0d,0x05,0x07,0x03,0x00,0x07,0x03,0x7e,0x17,0x11,0x0b,0x03,0x05,0x02,0x04,0x02,0x05,0x04,0x80,0x16,0x10,0x0a,0x03,0x04,0x01,0x02,0x04,0x01, -0x7e,0x00,0x00,0x14,0x1e,0x0f,0x08,0x1b,0x05,0x03,0x02,0x00,0x03,0x67,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x05,0x01,0x02,0x58,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x02,0x01,0x5f,0x1a,0x01,0x01,0x02,0x01,0x4f,0x59,0x40,0x52,0x30,0x30,0x28,0x28,0x1c,0x1c,0x18,0x18,0x10,0x10,0x04,0x04,0x00,0x00,0x30,0x33,0x30,0x33,0x32,0x31, -0x2f,0x2e,0x2d,0x2c,0x28,0x2b,0x28,0x2b,0x2a,0x29,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1c,0x1f,0x1c,0x1f,0x1e,0x1d,0x18,0x1b,0x18,0x1b,0x1a,0x19,0x17,0x16,0x15,0x14,0x10,0x13,0x10,0x13,0x12,0x11,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x04,0x07,0x04,0x07,0x06,0x05,0x00,0x03,0x00,0x03,0x11,0x21,0x07,0x17,0x2b,0x15, -0x11,0x21,0x11,0x01,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x05,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x03,0xca,0xfe,0x3d,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xe1,0x9e, -0x9e,0x9e,0x9e,0x9e,0xfd,0x5b,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0xe1,0x9d,0x9d,0x9d,0x9d,0x9d,0x16,0x02,0xe8,0xfd,0x18,0x01,0xc4,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e,0x9e,0x43,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e,0x9e,0x00,0x00,0x00, -0x00,0x02,0xff,0xff,0xff,0xf9,0x04,0x19,0x03,0x0b,0x00,0x12,0x00,0x29,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x15,0x00,0x04,0x00,0x02,0x01,0x04,0x02,0x68,0x00,0x01,0x00,0x00,0x01,0x00,0x63,0x00,0x03,0x03,0x10,0x03,0x4e,0x1b,0x40,0x1d,0x00,0x03,0x04,0x03,0x85,0x00,0x04,0x00,0x02,0x01,0x04,0x02,0x68,0x00,0x01,0x00,0x00, -0x01,0x57,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x59,0xb7,0x23,0x3a,0x23,0x36,0x35,0x05,0x07,0x1b,0x2b,0x01,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x2e,0x01,0x3f,0x01,0x3e,0x01,0x33,0x21,0x32,0x16,0x27,0x15,0x21,0x22,0x06,0x0f,0x02,0x27,0x26,0x37,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16, -0x04,0x19,0x12,0xbb,0x18,0x56,0x26,0xfd,0xa1,0x13,0x1c,0x01,0x11,0xbc,0x18,0x56,0x25,0x02,0x5f,0x13,0x1e,0xc0,0xfe,0x30,0x35,0x72,0x23,0xbc,0x02,0x01,0x01,0x01,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x3f,0x11,0x14,0xdd,0x1c,0x28,0x0e,0x22,0x14,0xdd,0x1c,0x28,0x0e,0xaf,0x5a,0x34,0x29,0xdd,0x03,0x07,0x05,0x02, -0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x00,0x01,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x14,0x00,0x35,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0d,0x00,0x02,0x00,0x00,0x02,0x00,0x64,0x00,0x01,0x01,0x10,0x01,0x4e,0x1b,0x40,0x15,0x00,0x01,0x02,0x01,0x85,0x00,0x02,0x00,0x00,0x02,0x57,0x00,0x02,0x02,0x00,0x60,0x00,0x00,0x02, -0x00,0x50,0x59,0xb5,0x23,0x35,0x33,0x03,0x07,0x19,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0xa1,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x01,0xff,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12, -0x4a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x1f,0x40,0x1c,0x01,0x01,0x00,0x49,0x03,0x02,0x02,0x00,0x01,0x00,0x86,0x00,0x01,0x01,0x13,0x01,0x4e,0x00,0x00,0x00,0x06,0x00,0x06,0x11,0x12,0x04,0x07,0x18,0x2b,0x09,0x02,0x33,0x11,0x21,0x11,0x02,0xf8,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x78, -0x01,0x6e,0xfe,0x84,0x01,0x7c,0x01,0x5e,0xfe,0xa2,0x00,0x00,0x00,0x02,0xff,0xf7,0xff,0xe2,0x03,0xdb,0x03,0x12,0x00,0x17,0x00,0x20,0x00,0x42,0x4b,0xb0,0x1c,0x50,0x58,0x40,0x11,0x00,0x02,0x01,0x02,0x85,0x03,0x01,0x01,0x01,0x00,0x61,0x00,0x00,0x00,0x14,0x00,0x4e,0x1b,0x40,0x17,0x00,0x02,0x01,0x02,0x85,0x03,0x01,0x01,0x00, -0x00,0x01,0x59,0x03,0x01,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x59,0x40,0x0c,0x19,0x18,0x1d,0x1c,0x18,0x20,0x19,0x20,0x2f,0x04,0x07,0x17,0x2b,0x01,0x1e,0x01,0x06,0x07,0x06,0x26,0x06,0x07,0x06,0x1e,0x01,0x07,0x0e,0x02,0x23,0x22,0x26,0x37,0x3e,0x01,0x37,0x24,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x59, -0x48,0x3a,0x12,0x1a,0x10,0x4c,0x54,0x26,0x1e,0x12,0x32,0x02,0x02,0x44,0xb8,0x7c,0xba,0xd2,0x0a,0x08,0xc0,0x78,0x01,0x22,0x48,0x1e,0x2c,0x2c,0x3e,0x2c,0x2c,0x02,0x6e,0x30,0x7c,0x54,0x06,0x04,0x1c,0x08,0x2a,0x2e,0x3a,0x48,0x0e,0x1a,0x4a,0x4a,0xca,0x90,0x76,0xea,0x22,0x54,0xfd,0x8a,0x2c,0x40,0x2a,0x2a,0x40,0x2c,0x00,0x00, -0x00,0x02,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x06,0x00,0x18,0x00,0x33,0x40,0x30,0x01,0x01,0x00,0x03,0x01,0x4c,0x00,0x03,0x00,0x03,0x85,0x04,0x01,0x00,0x01,0x00,0x85,0x00,0x01,0x02,0x02,0x01,0x57,0x00,0x01,0x01,0x02,0x60,0x00,0x02,0x01,0x02,0x50,0x00,0x00,0x18,0x16,0x11,0x0e,0x0b,0x09,0x00,0x06,0x00,0x06,0x05, -0x07,0x16,0x2b,0x01,0x11,0x16,0x1f,0x01,0x16,0x17,0x05,0x14,0x16,0x17,0x21,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21,0x02,0x3b,0x0d,0x08,0xe3,0x08,0x08,0xfe,0xb1,0x20,0x16,0x01,0x2f,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xbe,0x02,0x34,0x01,0x08,0x08,0x08,0xe4,0x07,0x0d,0x12,0x16,0x1e, -0x01,0xfd,0xb3,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c,0x17,0x1e,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x08,0x00,0x6a,0x00,0x72,0x40,0x15,0x65,0x59,0x4c,0x41,0x04,0x00,0x04,0x3b,0x0a,0x02,0x01,0x00,0x34,0x28,0x1b,0x10,0x04,0x03,0x01,0x03,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x20,0x00,0x00, -0x00,0x05,0x5f,0x00,0x05,0x05,0x10,0x4d,0x00,0x03,0x03,0x04,0x61,0x06,0x01,0x04,0x04,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x1e,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x69,0x00,0x03,0x03,0x04,0x61,0x06,0x01,0x04,0x04,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59, -0x40,0x0f,0x5c,0x5b,0x53,0x51,0x49,0x48,0x2b,0x2a,0x22,0x20,0x13,0x12,0x07,0x07,0x18,0x2b,0x01,0x34,0x26,0x22,0x0e,0x01,0x16,0x32,0x36,0x25,0x15,0x14,0x06,0x0f,0x01,0x06,0x07,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x27,0x22,0x2f,0x01,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x35,0x27,0x26,0x27,0x07,0x06,0x22,0x27,0x26, -0x27,0x26,0x34,0x37,0x3e,0x01,0x37,0x26,0x2f,0x01,0x2e,0x01,0x27,0x35,0x34,0x36,0x3f,0x01,0x36,0x37,0x26,0x27,0x26,0x34,0x37,0x3e,0x01,0x33,0x32,0x1f,0x01,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x1f,0x01,0x16,0x17,0x37,0x36,0x32,0x17,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x07,0x16,0x1f,0x01,0x1e,0x01,0x02,0x3b,0x52, -0x78,0x52,0x02,0x56,0x74,0x56,0x01,0x1c,0x08,0x07,0x68,0x0a,0x0b,0x13,0x28,0x06,0x05,0x0f,0x50,0x0d,0x07,0x07,0x4d,0x19,0x1a,0x09,0x07,0x04,0x10,0x7c,0x08,0x0c,0x10,0x1b,0x17,0x4f,0x06,0x10,0x06,0x46,0x16,0x04,0x05,0x08,0x28,0x0a,0x0f,0x08,0x66,0x07,0x08,0x01,0x0a,0x05,0x68,0x08,0x0e,0x17,0x25,0x06,0x05,0x0f,0x50,0x0d, -0x07,0x08,0x4d,0x18,0x1a,0x09,0x08,0x03,0x11,0x7c,0x07,0x0c,0x01,0x0f,0x1c,0x17,0x4f,0x05,0x0f,0x07,0x48,0x14,0x04,0x04,0x09,0x28,0x0a,0x0f,0x08,0x66,0x07,0x0a,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0x78,0x7c,0x07,0x0c,0x01,0x10,0x1e,0x15,0x1b,0x32,0x06,0x0e,0x06,0x15,0x50,0x01,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a, -0x07,0x67,0x09,0x0c,0x3c,0x05,0x06,0x40,0x1e,0x05,0x0e,0x06,0x0c,0x32,0x0f,0x1c,0x1b,0x0f,0x01,0x0c,0x07,0x7c,0x07,0x0c,0x01,0x10,0x19,0x1a,0x20,0x2d,0x07,0x0c,0x07,0x14,0x50,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a,0x07,0x67,0x09,0x0b,0x3b,0x05,0x05,0x43,0x1c,0x05,0x0e,0x06,0x0c,0x32,0x0f,0x1c,0x1a,0x10,0x01,0x0c,0x00, -0x00,0x09,0x00,0x00,0xff,0xf9,0x03,0xe8,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0x8f,0x00,0x80,0x4b,0xb0,0x26,0x50,0x58,0x40,0x26,0x0f,0x09,0x02,0x03,0x0e,0x08,0x02,0x02,0x01,0x03,0x02,0x67,0x0b,0x05,0x02,0x01,0x0a,0x04,0x02,0x00,0x01,0x00,0x63,0x10,0x0c,0x02,0x06, -0x06,0x07,0x5f,0x11,0x0d,0x02,0x07,0x07,0x10,0x06,0x4e,0x1b,0x40,0x2e,0x11,0x0d,0x02,0x07,0x10,0x0c,0x02,0x06,0x03,0x07,0x06,0x67,0x0f,0x09,0x02,0x03,0x0e,0x08,0x02,0x02,0x01,0x03,0x02,0x67,0x0b,0x05,0x02,0x01,0x00,0x00,0x01,0x57,0x0b,0x05,0x02,0x01,0x01,0x00,0x5f,0x0a,0x04,0x02,0x00,0x01,0x00,0x4f,0x59,0x40,0x1e,0x8e, -0x8b,0x86,0x83,0x7e,0x7b,0x76,0x73,0x6e,0x6b,0x66,0x63,0x5e,0x5b,0x56,0x53,0x4e,0x4b,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x12,0x07,0x1f,0x2b,0x25,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15, -0x14,0x06,0x07,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15, -0x14,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x1e,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17, -0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17, -0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x9a,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x01,0x06,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c, -0x16,0x20,0x01,0x1e,0x02,0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x02,0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01, -0x20,0x01,0x08,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0x00,0x05,0x00,0x00,0xff,0x6a,0x03,0xe8,0x03,0x52,0x00,0x10,0x00,0x14,0x00,0x25,0x00,0x2f,0x00,0x39,0x00,0x65,0x40,0x62,0x33,0x29,0x02,0x07,0x08,0x21,0x01,0x05,0x02,0x1d,0x15,0x0d,0x0c,0x04,0x00,0x05,0x03,0x4c,0x04,0x01,0x05,0x01,0x4b,0x0a,0x01,0x08,0x09,0x01, -0x07,0x01,0x08,0x07,0x67,0x00,0x02,0x05,0x01,0x02,0x57,0x06,0x0c,0x03,0x0b,0x04,0x01,0x00,0x05,0x00,0x01,0x05,0x69,0x06,0x0c,0x03,0x0b,0x04,0x01,0x01,0x00,0x5f,0x04,0x01,0x00,0x01,0x00,0x4f,0x11,0x11,0x00,0x00,0x37,0x35,0x32,0x31,0x2d,0x2b,0x28,0x27,0x24,0x22,0x1f,0x1e,0x1b,0x19,0x11,0x14,0x11,0x14,0x13,0x12,0x00,0x10, -0x00,0x0f,0x37,0x0d,0x07,0x17,0x2b,0x01,0x11,0x14,0x06,0x07,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x13,0x36,0x33,0x21,0x11,0x23,0x11,0x01,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x22,0x26,0x27,0x11,0x33,0x32,0x17,0x25,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x05,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32, -0x16,0x01,0x89,0x16,0x0e,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x8b,0x04,0x0d,0x01,0x9f,0x8e,0x02,0x3b,0x16,0x0e,0xfe,0xe3,0x0f,0x14,0x01,0x0f,0x14,0x01,0xed,0x0d,0x04,0xfe,0x3e,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x01,0x77,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x02,0x9f,0xfe,0x54,0x0f,0x14,0x01,0xfe,0xbf,0x0f,0x14,0x01,0x16,0x0e,0x01, -0x1d,0x01,0xe8,0x0c,0xfe,0x78,0x01,0x88,0xfe,0x0c,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x41,0x16,0x0e,0x01,0xac,0x0c,0xad,0x7d,0x7d,0x08,0x0a,0x0a,0x08,0x7d,0x7d,0x08,0x0a,0x0a,0x00,0x08,0xff,0xff,0xff,0xf8,0x03,0xe9,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0xad, -0x40,0x28,0x79,0x78,0x71,0x49,0x48,0x41,0x06,0x08,0x09,0x69,0x61,0x60,0x29,0x21,0x20,0x06,0x04,0x05,0x59,0x58,0x51,0x50,0x19,0x18,0x11,0x10,0x08,0x02,0x03,0x39,0x38,0x31,0x09,0x08,0x01,0x06,0x00,0x01,0x04,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2a,0x0d,0x01,0x05,0x0c,0x01,0x04,0x03,0x05,0x04,0x67,0x0b,0x01,0x03,0x0a,0x01, -0x02,0x01,0x03,0x02,0x67,0x07,0x01,0x01,0x06,0x01,0x00,0x01,0x00,0x63,0x0e,0x01,0x08,0x08,0x09,0x5f,0x0f,0x01,0x09,0x09,0x10,0x08,0x4e,0x1b,0x40,0x31,0x0f,0x01,0x09,0x0e,0x01,0x08,0x05,0x09,0x08,0x67,0x0d,0x01,0x05,0x0c,0x01,0x04,0x03,0x05,0x04,0x67,0x0b,0x01,0x03,0x0a,0x01,0x02,0x01,0x03,0x02,0x67,0x07,0x01,0x01,0x00, -0x00,0x01,0x57,0x07,0x01,0x01,0x01,0x00,0x5f,0x06,0x01,0x00,0x01,0x00,0x4f,0x59,0x40,0x1a,0x7d,0x7b,0x75,0x73,0x6d,0x6b,0x65,0x64,0x5d,0x5b,0x55,0x54,0x4d,0x4c,0x26,0x26,0x17,0x26,0x17,0x17,0x17,0x17,0x14,0x10,0x07,0x1f,0x2b,0x37,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x27,0x15,0x14, -0x06,0x27,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14, -0x06,0x27,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x8f,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01, -0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0xfc,0xa6,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd, -0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x76,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xd0,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xfe,0x4c,0x6b,0x07,0x0c, -0x01,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0x02,0x7d,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xfe,0x4d,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xcf,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x02,0x83, -0x03,0x0b,0x00,0x07,0x00,0x1f,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x14,0x05,0x03,0x02,0x00,0x00,0x02,0x00,0x02,0x63,0x00,0x01,0x01,0x04,0x61,0x00,0x04,0x04,0x10,0x01,0x4e,0x1b,0x40,0x1c,0x00,0x04,0x00,0x01,0x00,0x04,0x01,0x69,0x05,0x03,0x02,0x00,0x02,0x02,0x00,0x59,0x05,0x03,0x02,0x00,0x00,0x02,0x5f,0x00,0x02,0x00, -0x02,0x4f,0x59,0x40,0x09,0x23,0x13,0x25,0x36,0x13,0x10,0x06,0x07,0x1c,0x2b,0x13,0x21,0x35,0x34,0x26,0x0e,0x01,0x17,0x05,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17,0x33,0x35,0x34,0x36,0x32,0x16,0x07,0x15,0x33,0x32,0x16,0xb3,0x01,0x1d,0x54,0x76,0x54,0x01,0x01,0xd0,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20, -0x16,0x11,0x94,0xcc,0x96,0x02,0x12,0x17,0x1e,0x01,0xa5,0x6c,0x3b,0x54,0x02,0x50,0x3d,0xa1,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01,0x6c,0x66,0x94,0x94,0x66,0x6c,0x1e,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x06,0x01,0x01,0x00,0x01,0x4c,0x00,0x01, -0x00,0x4a,0x05,0x01,0x01,0x49,0x00,0x00,0x01,0x01,0x00,0x57,0x00,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x11,0x11,0x02,0x07,0x18,0x2b,0x01,0x15,0x21,0x11,0x21,0x15,0x01,0x01,0x7a,0x01,0x60,0xfe,0xa0,0xfe,0x86,0x02,0xda,0xbe,0xfe,0x86,0xc0,0x01,0x7c,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x04,0x2f,0x03,0x52,0x00,0x0f, -0x00,0x2f,0x00,0x2e,0x40,0x2b,0x09,0x01,0x02,0x01,0x00,0x20,0x01,0x03,0x02,0x02,0x4c,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x67,0x00,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x00,0x03,0x03,0x11,0x03,0x4e,0x35,0x26,0x36,0x26,0x26,0x14,0x06,0x07,0x1c,0x2b,0x01,0x11,0x34,0x26,0x27,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x33,0x21, -0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x14,0x1e,0x01,0x17,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x34,0x3e,0x01,0x35,0x21,0x22,0x26,0x37,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0xe8,0x0a,0x08,0xfc,0x83,0x07,0x0a,0x01,0x0c,0x06,0x03,0x7d,0x07,0x0c,0x46,0x34,0x25,0xfe,0xd1,0x12,0x10,0x01,0x14,0x0f,0xfe,0xe2,0x0f,0x14,0x01, -0x12,0x12,0xfe,0xd0,0x24,0x36,0x01,0x34,0x25,0x03,0x7d,0x25,0x34,0x01,0x28,0x01,0xd1,0x07,0x0a,0x01,0x0c,0x06,0xfe,0x2f,0x07,0x0a,0x0a,0x01,0xd8,0xfd,0xa1,0x25,0x34,0x01,0x14,0x2e,0x22,0x07,0x0e,0x16,0x16,0x0e,0x08,0x22,0x2c,0x15,0x36,0x24,0x02,0x5f,0x25,0x34,0x34,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xe1,0x02,0xf8, -0x02,0xdb,0x00,0x21,0x00,0x31,0x00,0x71,0xb6,0x11,0x06,0x02,0x00,0x03,0x01,0x4c,0x4b,0xb0,0x1a,0x50,0x58,0x40,0x18,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x69,0x00,0x04,0x04,0x02,0x61,0x00,0x02,0x02,0x13,0x4d,0x00,0x01,0x01,0x14,0x01,0x4e,0x1b,0x4b,0xb0,0x1d,0x50,0x58,0x40,0x16,0x00,0x02,0x00,0x04,0x03,0x02,0x04,0x69,0x00, -0x03,0x00,0x00,0x01,0x03,0x00,0x69,0x00,0x01,0x01,0x14,0x01,0x4e,0x1b,0x40,0x1d,0x00,0x01,0x00,0x01,0x86,0x00,0x02,0x00,0x04,0x03,0x02,0x04,0x69,0x00,0x03,0x00,0x00,0x03,0x59,0x00,0x03,0x03,0x00,0x61,0x00,0x00,0x03,0x00,0x51,0x59,0x59,0xb7,0x15,0x2b,0x1d,0x25,0x22,0x05,0x07,0x1b,0x2b,0x01,0x0e,0x01,0x23,0x22,0x26,0x27, -0x0f,0x01,0x06,0x23,0x22,0x26,0x35,0x34,0x3f,0x02,0x2e,0x01,0x35,0x34,0x37,0x3e,0x01,0x32,0x17,0x16,0x17,0x16,0x15,0x14,0x07,0x06,0x25,0x1e,0x01,0x33,0x32,0x3e,0x01,0x34,0x2e,0x01,0x22,0x0e,0x01,0x15,0x14,0x16,0x02,0xa8,0x29,0x66,0x36,0x31,0x5d,0x28,0x33,0x82,0x15,0x18,0x1e,0x2d,0x0f,0x81,0x7e,0x20,0x22,0x27,0x25,0x80, -0x95,0x40,0x3f,0x26,0x26,0x14,0x14,0xfe,0x99,0x19,0x40,0x21,0x2d,0x4f,0x2e,0x2f,0x4e,0x5b,0x4f,0x2f,0x1a,0x01,0x00,0x29,0x2a,0x22,0x20,0x7d,0x82,0x0f,0x2f,0x1e,0x1a,0x13,0x82,0x33,0x26,0x5e,0x32,0x4b,0x40,0x3f,0x4b,0x27,0x25,0x3f,0x41,0x4a,0x38,0x32,0x34,0x24,0x18,0x1a,0x2e,0x4f,0x5d,0x4e,0x2e,0x2f,0x4e,0x2d,0x22,0x40, -0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x19,0x00,0x47,0x4b,0xb0,0x26,0x50,0x58,0x40,0x16,0x04,0x01,0x00,0x00,0x03,0x61,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x14,0x00,0x03,0x04,0x01,0x00,0x01,0x03,0x00,0x69,0x00,0x01,0x01,0x02,0x61,0x00,0x02, -0x02,0x11,0x02,0x4e,0x59,0x40,0x0f,0x01,0x00,0x17,0x16,0x11,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x05,0x07,0x16,0x2b,0x01,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x01,0xad,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6, -0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x02,0x8e,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x4d,0x02,0xff,0x00,0x06,0x00,0x14,0x00,0x19,0x00,0x24,0x00,0xaa,0x40,0x17,0x1e,0x01,0x02,0x05,0x1d,0x16, -0x0e,0x07,0x04,0x03,0x02,0x19,0x03,0x02,0x03,0x00,0x03,0x01,0x01,0x01,0x00,0x04,0x4c,0x4b,0xb0,0x09,0x50,0x58,0x40,0x23,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x00,0x03,0x70,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x4b,0xb0,0x12,0x50, -0x58,0x40,0x22,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x03,0x85,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x23,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x03,0x85,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x04,0x80, -0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x59,0x59,0x40,0x12,0x00,0x00,0x21,0x20,0x18,0x17,0x10,0x0f,0x09,0x08,0x00,0x06,0x00,0x06,0x14,0x07,0x07,0x17,0x2b,0x17,0x37,0x27,0x07,0x15,0x33,0x15,0x01,0x34,0x23,0x22,0x07,0x01,0x06,0x15,0x14,0x33,0x32,0x37,0x01,0x36,0x27,0x17,0x01,0x23,0x35,0x01,0x14,0x0f,0x01, -0x27,0x37,0x36,0x32,0x1f,0x01,0x16,0xcb,0x32,0x83,0x33,0x48,0x01,0x5f,0x0c,0x05,0x04,0xfe,0xd1,0x04,0x0d,0x05,0x04,0x01,0x2f,0x03,0x1e,0xe8,0xfe,0x30,0xe8,0x03,0x4d,0x14,0x5d,0xe8,0x5d,0x14,0x3b,0x16,0x83,0x14,0x07,0x33,0x83,0x33,0x3c,0x47,0x02,0x06,0x0c,0x04,0xfe,0xd2,0x04,0x06,0x0c,0x04,0x01,0x2e,0x04,0x71,0xe8,0xfe, -0x2f,0xe9,0x01,0x9a,0x1d,0x15,0x5d,0xe9,0x5c,0x15,0x15,0x83,0x16,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x01,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x01,0x4a,0x02,0x01,0x00,0x49,0x00,0x01,0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x11,0x13, -0x02,0x07,0x18,0x2b,0x09,0x02,0x35,0x21,0x11,0x21,0x01,0x5e,0x01,0x7c,0xfe,0x84,0xfe,0xa2,0x01,0x5e,0x02,0xda,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x7a,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xab,0x03,0x6b,0x03,0x20,0x00,0x0f,0x00,0x13,0x00,0x1f,0x00,0x38,0x40,0x35,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x0b, -0x03,0x02,0x01,0x4c,0x00,0x02,0x02,0x00,0x5f,0x04,0x01,0x00,0x00,0x10,0x4d,0x00,0x03,0x03,0x01,0x5f,0x00,0x01,0x01,0x11,0x01,0x4e,0x01,0x00,0x13,0x12,0x11,0x10,0x09,0x06,0x00,0x0f,0x01,0x0e,0x05,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x07, -0x17,0x07,0x17,0x37,0x17,0x37,0x27,0x37,0x27,0x07,0x87,0x0c,0x11,0x11,0x0c,0x02,0xc6,0x0c,0x11,0x11,0x0c,0xfd,0x58,0x02,0x8b,0xfd,0x75,0x01,0x87,0x2d,0x52,0x52,0x2d,0x53,0x52,0x2e,0x53,0x53,0x2e,0x52,0x03,0x1f,0x12,0x0c,0xfc,0xc8,0x0c,0x11,0x11,0x0c,0x03,0x38,0x0c,0x12,0x3b,0xfd,0x02,0x02,0xcb,0x2e,0x52,0x53,0x2d,0x52, -0x52,0x2d,0x53,0x52,0x2e,0x52,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x84,0x03,0x8f,0x03,0x33,0x00,0x02,0x00,0x10,0x00,0x3c,0x00,0x68,0x00,0xf2,0x40,0x0b,0x01,0x01,0x0a,0x02,0x62,0x36,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x32,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x03,0x00,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02, -0x0f,0x01,0x0a,0x06,0x02,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x04,0x11,0x02,0x00,0x00,0x13,0x00,0x4e,0x1b,0x4b,0xb0,0x16,0x50,0x58,0x40,0x36,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x03,0x04,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02,0x0f,0x01,0x0a,0x06,0x02,0x0a, -0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x00,0x04,0x04,0x13,0x4d,0x11,0x01,0x00,0x00,0x13,0x00,0x4e,0x1b,0x40,0x39,0x12,0x01,0x01,0x03,0x01,0x85,0x11,0x01,0x00,0x04,0x02,0x04,0x00,0x02,0x80,0x00,0x03,0x04,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02,0x0f,0x01,0x0a,0x06, -0x02,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x00,0x04,0x04,0x13,0x04,0x4e,0x59,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x68,0x66,0x5e,0x5c,0x5b,0x59,0x4d,0x4b,0x4a,0x48,0x3f,0x3d,0x3c,0x3a,0x32,0x30,0x2f,0x2d,0x21,0x1f,0x1e,0x1c,0x13,0x11,0x0c,0x0b,0x0a,0x09, -0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d,0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x13,0x33,0x32,0x16,0x1d,0x01,0x14,0x16,0x17,0x16,0x17,0x16,0x3b,0x01,0x15,0x23,0x22,0x07,0x06,0x07,0x06,0x07,0x06,0x1d,0x01,0x14,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32, -0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x36,0x37,0x36,0x37,0x36,0x3d,0x01,0x34,0x37,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0x90,0x63,0x64,0xfe,0xcd,0x0d,0x13,0x3f,0x01,0x58, -0x3f,0x12,0x0d,0x55,0x1b,0x47,0x45,0x07,0x0b,0x09,0x12,0x0e,0x1c,0x0f,0x0f,0x1a,0x12,0x0f,0x0c,0x08,0x05,0x03,0x0f,0x22,0x34,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x20,0x0a,0x08,0x05,0x04,0x07,0x07,0x23,0x33,0x27,0x1b,0x15,0x55,0x4e,0x4e,0x55,0x15,0x02, -0xb1,0xac,0xac,0x82,0x12,0x0d,0xe7,0xc7,0x2e,0x4e,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x09,0x0a,0x05,0x05,0x33,0x05,0x03,0x0a,0x08,0x0f,0x0d,0x14,0x80,0x1d,0x33,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09,0x0b,0x33,0x08,0x09,0x08,0x0f,0x14,0x0d,0x57, -0x21,0x16,0x19,0x24,0x12,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x17,0x40,0x14,0x06,0x01,0x00,0x4a,0x02,0x01,0x00,0x01,0x00,0x85,0x00,0x01,0x01,0x76,0x11,0x11,0x10,0x03,0x07,0x19,0x2b,0x01,0x23,0x11,0x21,0x11,0x23,0x01,0x02,0xf8,0xc0,0xfe, -0x88,0xc0,0x01,0x7c,0x01,0x50,0xfe,0xa2,0x01,0x5e,0x01,0x7c,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0xa5,0x02,0x98,0x00,0x15,0x00,0x1d,0x40,0x1a,0x0f,0x01,0x00,0x01,0x01,0x4c,0x00,0x02,0x01,0x02,0x85,0x00,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26, -0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x03,0xa5,0x10,0xfe,0x20,0x10,0x2c,0x10,0xfe,0xea,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0x01,0x6e,0x10,0x2c,0x10,0x4c,0x10,0x02,0x16,0x16,0x10,0xfe,0x20,0x0f,0x0f,0x01,0x16,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa5,0x01,0x6f,0x10,0x10,0x4c,0x0f,0x00,0x03,0xff,0xf5, -0xff,0xb1,0x03,0xf3,0x03,0x52,0x00,0x0f,0x00,0x21,0x00,0x33,0x00,0x33,0x40,0x30,0x1b,0x11,0x02,0x03,0x02,0x09,0x01,0x02,0x01,0x00,0x02,0x4c,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x04,0x5f,0x00,0x04,0x04,0x11,0x04,0x4e,0x17,0x38,0x27,0x27,0x26,0x23,0x06,0x07,0x1c, -0x2b,0x25,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34,0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x17,0x14,0x16,0x37,0x33,0x32,0x36,0x03,0x01,0x16,0x07,0x0e,0x01,0x07,0x21,0x22,0x26,0x27,0x26,0x37,0x01,0x3e,0x01,0x32,0x16,0x02,0x3b,0x0a,0x07,0x6c,0x07,0x0a,0x0a,0x07,0x6c,0x07, -0x0a,0x01,0x0a,0x05,0x07,0x07,0x7a,0x06,0x08,0x05,0x09,0x0c,0x07,0x67,0x08,0x0c,0x08,0x01,0xac,0x14,0x15,0x09,0x22,0x12,0xfc,0xa6,0x12,0x22,0x09,0x15,0x14,0x01,0xad,0x09,0x22,0x26,0x22,0x53,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xd7,0x01,0x01,0x06,0x04,0x06,0x06,0x04,0x08,0xff,0x05,0x08,0x01,0x06,0x02,0x10, -0xfc,0xee,0x23,0x23,0x11,0x12,0x01,0x14,0x10,0x23,0x23,0x03,0x12,0x11,0x14,0x14,0x00,0x04,0x00,0x00,0xff,0x79,0x03,0xd1,0x03,0x3c,0x00,0x0f,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x36,0x40,0x33,0x07,0x01,0x05,0x03,0x01,0x01,0x05,0x01,0x63,0x06,0x01,0x04,0x04,0x00,0x5f,0x09,0x02,0x08,0x03,0x00,0x00,0x12,0x04,0x4e,0x11,0x10, -0x01,0x00,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x19,0x16,0x10,0x1f,0x11,0x1e,0x09,0x06,0x00,0x0f,0x01,0x0e,0x0a,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x33,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x21, -0x11,0x21,0x38,0x0d,0x13,0x13,0x0d,0x01,0x7c,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0x01,0x7d,0x0d,0x12,0x12,0x0d,0xfc,0xa6,0x01,0x3e,0xfe,0xc2,0x01,0xfc,0x01,0x3e,0xfe,0xc2,0x03,0x3b,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x3e,0xfc, -0xbb,0x03,0x45,0xfc,0xbb,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x7e,0x03,0xd6,0x03,0x37,0x00,0x0f,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x3d,0x40,0x3a,0x00,0x04,0x00,0x01,0x02,0x04,0x01,0x67,0x00,0x02,0x09,0x01,0x07,0x06,0x02,0x07,0x67,0x00,0x06,0x00,0x03,0x06,0x03,0x63,0x08,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x00,0x12, -0x05,0x4e,0x24,0x24,0x20,0x20,0x24,0x27,0x24,0x27,0x26,0x25,0x20,0x23,0x20,0x23,0x14,0x35,0x35,0x35,0x32,0x0a,0x07,0x1b,0x2b,0x01,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x15,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x03,0x11,0x21,0x11,0x01,0x11,0x21, -0x11,0x03,0xd5,0x12,0x0d,0xfc,0x7d,0x0d,0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d,0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x3f,0xfc,0xbc,0x03,0x44,0xfc,0xbc,0x03,0x17,0x0d,0x12,0x12,0x0d,0xfe,0x84,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0xfe,0x83,0x0d,0x12,0x12,0x0d,0x03,0x5a,0xfe,0xc2,0x01,0x3e,0xfe, -0x04,0xfe,0xc1,0x01,0x3f,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x89,0x03,0xdc,0x03,0x38,0x00,0x02,0x00,0x10,0x00,0x39,0x00,0x62,0x00,0xcc,0x40,0x0b,0x01,0x01,0x06,0x0a,0x5c,0x33,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x21,0x50,0x58,0x40,0x3f,0x12,0x01,0x01,0x03,0x01,0x85,0x04,0x11,0x02,0x00,0x03,0x02,0x03,0x00,0x02,0x80, -0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f,0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x1b,0x40,0x45,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80, -0x11,0x01,0x00,0x02,0x03,0x00,0x02,0x7e,0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f,0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x62,0x60, -0x58,0x56,0x55,0x53,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x1f,0x1d,0x1c,0x1a,0x13,0x11,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d,0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x01,0x33,0x32,0x16,0x1d,0x01,0x14, -0x1e,0x02,0x3b,0x01,0x15,0x23,0x22,0x07,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x02,0x3d,0x01,0x34,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07, -0x16,0x1d,0x01,0x14,0x3b,0x01,0x03,0xdc,0x63,0x64,0xfd,0x31,0x0d,0x13,0x3f,0x02,0xf4,0x3f,0x12,0x0d,0xfe,0xb9,0x1b,0x47,0x45,0x07,0x16,0x22,0x18,0x10,0x10,0x16,0x16,0x10,0x14,0x07,0x08,0x06,0x21,0x38,0x25,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x1f,0x15,0x07, -0x0f,0x21,0x34,0x27,0x1b,0x15,0x55,0x4d,0x4e,0x54,0x15,0x02,0x85,0xad,0xad,0xb3,0x12,0x0d,0xe7,0xc7,0x6d,0x8d,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x13,0x0a,0x33,0x04,0x04,0x12,0x1c,0x14,0x80,0x1d,0x1a,0x19,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09, -0x0b,0x33,0x08,0x13,0x1a,0x14,0x57,0x20,0x30,0x23,0x13,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x43,0x00,0x7b,0x40,0x0f,0x18,0x01,0x03,0x04,0x13,0x01,0x02,0x00,0x03,0x06,0x01,0x01,0x00,0x03,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x05,0x01, -0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x69,0x00,0x07,0x00,0x08,0x07,0x08,0x63,0x00,0x06,0x06,0x09,0x5f,0x00,0x09,0x09,0x10,0x06,0x4e,0x1b,0x40,0x2a,0x00,0x09,0x00,0x06,0x04,0x09,0x06,0x67,0x05,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x69,0x00, -0x07,0x08,0x08,0x07,0x57,0x00,0x07,0x07,0x08,0x5f,0x00,0x08,0x07,0x08,0x4f,0x59,0x40,0x0e,0x42,0x3f,0x35,0x35,0x36,0x14,0x23,0x26,0x14,0x23,0x23,0x0a,0x07,0x1f,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x35,0x34,0x36,0x3b,0x01,0x32,0x16, -0x1d,0x01,0x33,0x32,0x16,0x13,0x11,0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x47,0x34,0x25, -0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x07,0x0a,0xc5,0x08,0x0a,0x0a,0x08,0xc5,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe, -0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x59,0xb6,0x09,0x01,0x02,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x1a,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x67,0x00,0x03,0x00,0x04,0x03,0x04,0x63,0x00,0x02,0x02,0x05, -0x5f,0x00,0x05,0x05,0x10,0x02,0x4e,0x1b,0x40,0x20,0x00,0x05,0x00,0x02,0x01,0x05,0x02,0x67,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x67,0x00,0x03,0x04,0x04,0x03,0x57,0x00,0x03,0x03,0x04,0x5f,0x00,0x04,0x03,0x04,0x4f,0x59,0x40,0x09,0x35,0x35,0x35,0x36,0x26,0x23,0x06,0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x3d, -0x01,0x34,0x36,0x33,0x21,0x32,0x16,0x13,0x11,0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xfe,0x30,0x08,0x0a,0x0a,0x08,0x01,0xd0,0x08,0x0a,0x47,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01, -0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58, -0x01,0xd4,0x00,0x15,0x00,0x21,0xb1,0x06,0x64,0x44,0x40,0x16,0x07,0x01,0x00,0x02,0x01,0x4c,0x00,0x02,0x00,0x02,0x85,0x01,0x01,0x00,0x00,0x76,0x17,0x14,0x14,0x03,0x07,0x19,0x2b,0xb1,0x06,0x00,0x44,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01,0x26,0x34,0x37,0x01,0x36,0x32,0x17,0x01,0x16,0x02,0x58,0x06, -0x1c,0x05,0x0e,0x06,0xdc,0xdb,0x05,0x10,0x04,0x1c,0x06,0x06,0x01,0x04,0x05,0x0e,0x06,0x01,0x04,0x06,0xbd,0x07,0x05,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0xfe,0xfc,0x05,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0x89,0x03,0x42,0x03,0x33,0x00,0x0f,0x00,0x19,0x00,0x33,0x00,0x3f,0x00,0x4b, -0x00,0x57,0x00,0x8c,0x40,0x89,0x56,0x01,0x0c,0x0d,0x44,0x01,0x0a,0x0b,0x3e,0x01,0x08,0x09,0x03,0x4c,0x00,0x02,0x03,0x05,0x03,0x02,0x05,0x80,0x00,0x05,0x0d,0x03,0x05,0x0d,0x7e,0x00,0x0b,0x0c,0x0a,0x0c,0x0b,0x0a,0x80,0x00,0x0a,0x09,0x0c,0x0a,0x09,0x7e,0x00,0x09,0x08,0x0c,0x09,0x08,0x7e,0x10,0x01,0x08,0x07,0x0c,0x08,0x07, -0x7e,0x00,0x0d,0x11,0x01,0x0c,0x0b,0x0d,0x0c,0x67,0x00,0x07,0x00,0x01,0x07,0x01,0x64,0x06,0x04,0x0f,0x03,0x03,0x03,0x00,0x5f,0x0e,0x01,0x00,0x00,0x12,0x03,0x4e,0x4e,0x4c,0x36,0x34,0x10,0x10,0x01,0x00,0x54,0x52,0x4c,0x57,0x4e,0x57,0x48,0x45,0x42,0x40,0x3c,0x3a,0x34,0x3f,0x36,0x3f,0x32,0x2f,0x2a,0x28,0x25,0x22,0x1f,0x1d, -0x10,0x19,0x10,0x19,0x16,0x13,0x09,0x06,0x00,0x0f,0x01,0x0e,0x12,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x17,0x15,0x14,0x16,0x3b,0x01,0x32,0x36,0x3d,0x01,0x13,0x11,0x34,0x26,0x07,0x23,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x37,0x35,0x23,0x22,0x06,0x17,0x11,0x14,0x16, -0x33,0x21,0x32,0x36,0x27,0x21,0x22,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x07,0x14,0x27,0x21,0x22,0x26,0x37,0x34,0x33,0x21,0x32,0x15,0x14,0x06,0x27,0x21,0x22,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x07,0x14,0x02,0xa6,0x41,0x5a,0x01,0x5c,0x40,0xfd,0xf6,0x41,0x5a,0x01,0x5c,0x40,0x68,0x20,0x15,0xd0,0x16,0x1e,0x9c,0x1e,0x15,0x35, -0x3c,0x2c,0xd0,0x2b,0x3e,0x01,0x35,0x15,0x20,0x01,0x1e,0x16,0x02,0x0a,0x15,0x1e,0x68,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x1a,0xfe,0x60,0x0b,0x10,0x01,0x1a,0x01,0xa0,0x1a,0x0e,0x0c,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x03,0x33,0x5c,0x40,0xfd,0x8f,0x41,0x5c,0x5c,0x41,0x02,0x71,0x41,0x5a,0x01, -0x68,0x34,0x15,0x20,0x20,0x15,0x34,0xfd,0x5b,0x02,0x71,0x15,0x20,0x01,0x34,0x2b,0x3c,0x01,0x3e,0x2a,0x34,0x1e,0x16,0xfd,0x8f,0x15,0x20,0x20,0x49,0x19,0x0c,0x0e,0x01,0x10,0x0b,0x19,0x9d,0x0e,0x0c,0x19,0x19,0x0b,0x10,0x9d,0x19,0x0b,0x10,0x01,0x0e,0x0c,0x19,0x00,0x00,0x03,0x00,0x00,0xff,0xf9,0x04,0x29,0x03,0x0b,0x00,0x11, -0x00,0x27,0x00,0x45,0x00,0x88,0xb5,0x24,0x01,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2b,0x00,0x07,0x04,0x03,0x04,0x07,0x03,0x80,0x00,0x03,0x02,0x04,0x03,0x02,0x7e,0x08,0x09,0x02,0x02,0x00,0x00,0x01,0x02,0x00,0x68,0x00,0x01,0x00,0x05,0x01,0x05,0x63,0x00,0x04,0x04,0x06,0x5f,0x00,0x06,0x06,0x10,0x04,0x4e,0x1b, -0x40,0x31,0x00,0x07,0x04,0x03,0x04,0x07,0x03,0x80,0x00,0x03,0x02,0x04,0x03,0x02,0x7e,0x00,0x06,0x00,0x04,0x07,0x06,0x04,0x67,0x08,0x09,0x02,0x02,0x00,0x00,0x01,0x02,0x00,0x68,0x00,0x01,0x05,0x05,0x01,0x57,0x00,0x01,0x01,0x05,0x5f,0x00,0x05,0x01,0x05,0x4f,0x59,0x40,0x17,0x13,0x12,0x42,0x40,0x3d,0x3b,0x38,0x35,0x30,0x2d, -0x21,0x1e,0x19,0x16,0x12,0x27,0x13,0x27,0x36,0x31,0x0a,0x07,0x18,0x2b,0x01,0x34,0x23,0x21,0x22,0x06,0x0f,0x01,0x06,0x15,0x14,0x33,0x21,0x32,0x36,0x3f,0x01,0x36,0x25,0x21,0x35,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06,0x15,0x11,0x37,0x3e,0x01,0x05,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x26, -0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x17,0x15,0x33,0x32,0x16,0x17,0x16,0x03,0xe2,0x1e,0xfd,0xa1,0x16,0x34,0x0d,0xa4,0x0b,0x1e,0x02,0x5f,0x17,0x32,0x0f,0xa4,0x0a,0xfd,0x83,0x01,0xad,0x20,0x16,0xfe,0xbf,0x17,0x1e,0x01,0x1e,0x17,0xb3,0x16,0x20,0x8f,0x19,0x50,0x02,0xea,0x19,0xa5,0x18,0x52,0x25, -0xfd,0xa1,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x6b,0x1e,0x34,0x0b,0x08,0x01,0x4b,0x13,0x18,0x11,0xcb,0x0d,0x09,0x14,0x1a,0x10,0xcb,0x0c,0x64,0x5a,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfe,0x24,0xaf,0x1e,0x26,0x5a,0x23,0x20,0xcb,0x1e,0x26,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33, -0x12,0x4a,0x33,0x5a,0x1a,0x1b,0x11,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xdc,0x01,0xcc,0x00,0x08,0x00,0x20,0x40,0x1d,0x02,0x01,0x00,0x01,0x01,0x00,0x59,0x02,0x01,0x00,0x00,0x01,0x61,0x00,0x01,0x00,0x01,0x51,0x01,0x00,0x05,0x04,0x00,0x08,0x01,0x08,0x03,0x07,0x16,0x2b,0x13,0x32,0x16,0x14,0x06,0x22,0x26,0x34,0x36,0x6e, -0x2e,0x40,0x40,0x5c,0x40,0x40,0x01,0xcc,0x40,0x5a,0x42,0x42,0x5a,0x40,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb8,0x03,0x94,0x03,0x1f,0x00,0x02,0x00,0x10,0x00,0x39,0x00,0x66,0x01,0x0d,0x40,0x0b,0x60,0x33,0x02,0x07,0x06,0x01,0x01,0x02,0x07,0x02,0x4c,0x4b,0xb0,0x13,0x50,0x58,0x40,0x38,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80, -0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x08,0x12,0x04,0x11,0x05,0x00,0x01,0x09,0x00,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x4b,0xb0,0x1a,0x50,0x58,0x40,0x3f,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80, -0x12,0x04,0x11,0x03,0x00,0x08,0x01,0x08,0x00,0x01,0x80,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x40,0x45,0x00,0x02,0x07,0x09,0x07,0x02, -0x09,0x80,0x11,0x01,0x00,0x08,0x04,0x08,0x00,0x04,0x80,0x12,0x01,0x04,0x01,0x08,0x04,0x01,0x7e,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x59, -0x59,0x40,0x2d,0x03,0x03,0x00,0x00,0x66,0x64,0x5c,0x5a,0x59,0x57,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x20,0x1e,0x1d,0x1b,0x13,0x11,0x03,0x10,0x03,0x10,0x0d,0x0a,0x07,0x06,0x05,0x04,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x25,0x37,0x17,0x07,0x15,0x21,0x35,0x23,0x15,0x14,0x16,0x33,0x21,0x32,0x36, -0x3d,0x01,0x01,0x33,0x32,0x16,0x1d,0x01,0x14,0x17,0x1e,0x02,0x3b,0x01,0x15,0x23,0x22,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x01,0x37,0x36,0x3d,0x01,0x34, -0x37,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0xcd,0x64,0x63,0x82,0xfe,0xa7,0x3e,0x12,0x0d,0x01,0x97,0x0d,0x13,0xfe,0xa0,0x1c,0x47,0x44,0x04,0x05,0x11,0x25,0x18,0x10,0x10,0x1c,0x20,0x14,0x07,0x07,0x07,0x22,0x35,0x26,0x1c,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa7, -0x1b,0x48,0x44,0x04,0x05,0x09,0x0a,0x23,0x18,0x0f,0x0f,0x1d,0x20,0x13,0x03,0x04,0x07,0x08,0x10,0x10,0x1b,0x1b,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0x6a,0xac,0xac,0x09,0x6a,0xb3,0xd3,0x0d,0x12,0x12,0x0d,0x8a,0x02,0xbe,0x42,0x44,0x54,0x14,0x0c,0x10,0x10,0x0c,0x33,0x08,0x14,0x19,0x15,0x80,0x21,0x16,0x19,0x23,0x12,0x33, -0x52,0x7f,0x59,0x0b,0x09,0x5c,0x54,0x54,0xfd,0x8b,0x42,0x43,0x7e,0x14,0x0c,0x10,0x08,0x0b,0x09,0x33,0x09,0x12,0x0e,0x0c,0x15,0x56,0x1a,0x1e,0x18,0x12,0x10,0x0b,0x09,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x03,0xff,0xfe,0x00,0x00,0x03,0xe8,0x02,0x60,0x00,0x20,0x00,0x24,0x00,0x28,0x00,0x36,0x40,0x33, -0x00,0x00,0x08,0x06,0x07,0x03,0x04,0x03,0x00,0x04,0x67,0x05,0x01,0x03,0x01,0x01,0x03,0x57,0x05,0x01,0x03,0x03,0x01,0x5f,0x02,0x01,0x01,0x03,0x01,0x4f,0x25,0x25,0x21,0x21,0x25,0x28,0x25,0x28,0x27,0x26,0x21,0x24,0x21,0x24,0x14,0x27,0x2a,0x18,0x09,0x07,0x1a,0x2b,0x11,0x26,0x37,0x25,0x36,0x17,0x16,0x0f,0x01,0x21,0x27,0x26, -0x37,0x36,0x17,0x05,0x16,0x07,0x03,0x06,0x23,0x21,0x26,0x2f,0x01,0x26,0x0f,0x01,0x06,0x23,0x21,0x26,0x27,0x37,0x17,0x21,0x37,0x33,0x17,0x21,0x37,0x02,0x0a,0x01,0x68,0x1d,0x0c,0x0b,0x19,0xe3,0x02,0x92,0xe4,0x19,0x0b,0x0e,0x1d,0x01,0x6a,0x0b,0x02,0x1b,0x08,0x19,0xfe,0xc7,0x19,0x06,0x31,0x27,0x35,0x32,0x06,0x1a,0xfe,0xc8, -0x1b,0x04,0x27,0x13,0x01,0x04,0x2b,0xdd,0x29,0x01,0x03,0x14,0x01,0x82,0x0d,0x0c,0xba,0x0b,0x1b,0x21,0x0c,0x68,0x68,0x10,0x1d,0x1b,0x0b,0xba,0x0c,0x0d,0xff,0x00,0x1e,0x02,0x18,0xdf,0x19,0x18,0xe0,0x1a,0x02,0x1c,0xe2,0xbd,0xbd,0xbd,0xbd,0x00,0x00,0x03,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x13,0x00,0x1a,0x00,0x23, -0x00,0x39,0x40,0x36,0x14,0x01,0x02,0x04,0x01,0x4c,0x00,0x01,0x00,0x04,0x02,0x01,0x04,0x67,0x00,0x02,0x00,0x03,0x05,0x02,0x03,0x67,0x06,0x01,0x05,0x00,0x00,0x05,0x57,0x06,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x05,0x00,0x4f,0x1b,0x1b,0x1b,0x23,0x1b,0x23,0x13,0x26,0x14,0x35,0x36,0x07,0x07,0x1b,0x2b,0x01,0x1e,0x01,0x15,0x11, -0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x17,0x07,0x15,0x33,0x26,0x2f,0x01,0x26,0x13,0x11,0x23,0x22,0x26,0x27,0x35,0x21,0x11,0x03,0x33,0x10,0x16,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xf4,0x16,0x36,0x0f,0x4a,0xd2,0x05,0x07,0xaf,0x06,0xc6,0xe8,0x17,0x1e,0x01,0xfe,0x53,0x02,0x7e, -0x10,0x34,0x18,0xfd,0x7e,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c,0x17,0x1e,0x01,0x16,0x10,0x26,0xd2,0x11,0x06,0xaf,0x07,0xfc,0xb0,0x02,0x3c,0x20,0x15,0xe9,0xfc,0xa6,0x00,0x01,0x00,0x00,0xff,0xaa,0x03,0x11,0x03,0x13,0x00,0x0b,0x00,0x06,0xb3,0x07,0x02,0x01,0x32,0x2b,0x09,0x01,0x06,0x26,0x35,0x11,0x34,0x36,0x17,0x01,0x16,0x14, -0x03,0x04,0xfd,0x1b,0x0d,0x12,0x12,0x0d,0x02,0xe5,0x0d,0x01,0x4d,0xfe,0x64,0x07,0x0a,0x0f,0x03,0x36,0x0e,0x0c,0x08,0xfe,0x64,0x07,0x14,0x00,0x00,0x01,0xff,0xff,0xff,0xae,0x02,0x3c,0x03,0x0f,0x00,0x1d,0x00,0x31,0xb7,0x1b,0x1a,0x12,0x03,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x00,0x00,0x10,0x4d,0x00, -0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x0b,0x00,0x00,0x00,0x01,0x5f,0x00,0x01,0x01,0x11,0x01,0x4e,0x59,0xb4,0x35,0x3d,0x02,0x07,0x18,0x2b,0x17,0x06,0x26,0x37,0x11,0x34,0x36,0x17,0x01,0x16,0x17,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x07,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x11,0x06,0x07,0x19,0x0a,0x10,0x01,0x0e,0x0b,0x01, -0x8c,0x05,0x03,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x03,0x05,0x47,0x0b,0x06,0x0f,0x03,0x36,0x0e,0x08,0x0c,0xfe,0x74,0x05,0x05,0x01,0x7a,0x0e,0x16,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x01,0x7b,0x06,0x05,0x00,0x00,0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x13,0x00,0x29, -0x00,0xa7,0x40,0x0d,0x0c,0x01,0x03,0x02,0x23,0x22,0x18,0x17,0x04,0x05,0x07,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x32,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02,0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00,0x05,0x04,0x02,0x05,0x04,0x7e,0x0a,0x01,0x04,0x00,0x01,0x04,0x01,0x66,0x09,0x01,0x02, -0x02,0x00,0x61,0x08,0x01,0x00,0x00,0x12,0x02,0x4e,0x1b,0x40,0x39,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02,0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00,0x05,0x04,0x02,0x05,0x04,0x7e,0x08,0x01,0x00,0x09,0x01,0x02,0x03,0x00,0x02,0x69,0x0a,0x01,0x04,0x01,0x01,0x04,0x59,0x0a,0x01,0x04,0x04,0x01, -0x62,0x00,0x01,0x04,0x01,0x52,0x59,0x40,0x1f,0x15,0x14,0x0a,0x09,0x01,0x00,0x26,0x24,0x20,0x1e,0x1b,0x19,0x14,0x29,0x15,0x29,0x10,0x0e,0x09,0x13,0x0a,0x13,0x05,0x04,0x00,0x08,0x01,0x08,0x0b,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x17,0x22,0x06,0x15,0x06,0x16,0x33,0x32,0x36,0x35,0x34,0x03,0x32,0x36, -0x37,0x27,0x06,0x23,0x22,0x3f,0x01,0x36,0x23,0x22,0x06,0x07,0x17,0x36,0x33,0x32,0x0f,0x01,0x06,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xf2,0x2a,0x2e,0x02,0x22,0x20,0x26,0x2e,0xb4,0x1e,0x6c,0x34,0x12,0x30,0x18,0x0e,0x0a,0x2a,0x1a,0x30,0x1e,0x76,0x38,0x10,0x34,0x16,0x0c,0x0c,0x24,0x1a, -0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0x96,0x30,0x1a,0x1c,0x20,0x2c,0x20,0x3a,0xfd,0xae,0x34,0x34,0x18,0x24,0x26,0xa0,0x60,0x3a,0x2e,0x1a,0x22,0x22,0x98,0x68,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x31,0x00,0x6a,0x40,0x0b,0x2a,0x01,0x03,0x05,0x25,0x1d,0x02,0x04, -0x03,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x24,0x00,0x04,0x03,0x01,0x03,0x04,0x01,0x80,0x00,0x01,0x02,0x03,0x01,0x02,0x7e,0x00,0x03,0x03,0x05,0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x22,0x00,0x04,0x03,0x01,0x03,0x04,0x01,0x80,0x00,0x01,0x02,0x03,0x01,0x02,0x7e, -0x00,0x05,0x00,0x03,0x04,0x05,0x03,0x69,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x09,0x29,0x35,0x17,0x23,0x17,0x24,0x06,0x07,0x1c,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x26,0x34,0x3f,0x01,0x36,0x16,0x17,0x1e,0x01,0x33,0x32,0x3e,0x03,0x2e,0x02,0x22,0x06,0x07,0x17,0x16,0x06,0x2b,0x01,0x22, -0x26,0x27,0x35,0x34,0x36,0x1f,0x01,0x3e,0x01,0x33,0x32,0x1e,0x02,0x03,0x59,0x44,0x72,0xa0,0x56,0x60,0xae,0x3c,0x04,0x05,0x4c,0x06,0x11,0x04,0x29,0x76,0x43,0x3a,0x68,0x50,0x2a,0x02,0x2e,0x4c,0x6c,0x6f,0x64,0x28,0x4d,0x11,0x13,0x17,0xfa,0x0f,0x14,0x01,0x2c,0x11,0x48,0x3c,0x9a,0x52,0x57,0x9e,0x74,0x42,0x01,0x5e,0x57,0x9e, -0x74,0x44,0x52,0x49,0x06,0x0e,0x04,0x4d,0x05,0x01,0x06,0x35,0x3a,0x2e,0x4c,0x6a,0x74,0x6a,0x4c,0x2e,0x28,0x25,0x4d,0x10,0x2d,0x16,0x0e,0xfa,0x18,0x13,0x12,0x48,0x39,0x3e,0x44,0x74,0x9e,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf9,0x02,0x83,0x03,0x53,0x00,0x23,0x00,0x3a,0x40,0x37,0x00,0x04,0x05,0x00,0x05,0x04,0x00,0x80, -0x00,0x03,0x00,0x05,0x04,0x03,0x05,0x69,0x02,0x06,0x02,0x00,0x01,0x01,0x00,0x59,0x02,0x06,0x02,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x01,0x00,0x20,0x1f,0x1b,0x18,0x14,0x13,0x10,0x0e,0x09,0x06,0x00,0x23,0x01,0x23,0x07,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17, -0x33,0x35,0x34,0x36,0x1e,0x01,0x07,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x34,0x26,0x22,0x06,0x17,0x15,0x02,0x4d,0x17,0x1e,0x01,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20,0x16,0x11,0x94,0xcc,0x96,0x02,0x14,0x0f,0x24,0x0e,0x16,0x54,0x76,0x54,0x01,0x01,0xa5,0x1e,0x17,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01, -0xb3,0x67,0x94,0x02,0x90,0x69,0x0e,0x16,0x16,0x0e,0x3b,0x54,0x54,0x3b,0xb3,0x00,0x00,0x08,0x00,0x00,0xff,0x9f,0x03,0x8f,0x03,0x1d,0x00,0x04,0x00,0x09,0x00,0x0e,0x00,0x13,0x00,0x1b,0x00,0x23,0x00,0x2b,0x00,0x33,0x00,0x41,0x40,0x3e,0x21,0x20,0x15,0x14,0x0e,0x01,0x06,0x00,0x4a,0x31,0x30,0x25,0x24,0x10,0x09,0x06,0x01,0x49, -0x05,0x04,0x02,0x08,0x04,0x00,0x01,0x00,0x85,0x07,0x06,0x09,0x03,0x04,0x01,0x01,0x76,0x0f,0x0f,0x00,0x00,0x2d,0x2c,0x29,0x28,0x1d,0x1c,0x19,0x18,0x0f,0x13,0x0f,0x13,0x0b,0x0a,0x06,0x05,0x00,0x04,0x00,0x04,0x0a,0x07,0x16,0x2b,0x01,0x35,0x1e,0x01,0x17,0x07,0x33,0x0e,0x01,0x07,0x03,0x23,0x3e,0x01,0x37,0x11,0x15,0x2e,0x01, -0x27,0x01,0x35,0x1e,0x01,0x17,0x23,0x2e,0x01,0x01,0x23,0x3e,0x01,0x37,0x15,0x0e,0x01,0x01,0x15,0x2e,0x01,0x27,0x33,0x1e,0x01,0x01,0x33,0x0e,0x01,0x07,0x35,0x3e,0x01,0x02,0x09,0x3c,0x56,0x10,0xa2,0xa2,0x10,0x56,0x3c,0x71,0xa2,0x10,0x56,0x3c,0x3c,0x56,0x10,0x01,0x13,0x98,0xda,0x14,0x71,0x12,0x9a,0xfe,0x11,0x71,0x13,0xda, -0x99,0x6a,0x98,0x01,0x02,0x9a,0xd8,0x14,0x71,0x12,0x9a,0x01,0xef,0x71,0x15,0xd8,0x99,0x69,0x9a,0x01,0x97,0xa2,0x10,0x58,0x3a,0x71,0x3b,0x58,0x0f,0x01,0x13,0x3b,0x56,0x11,0xfe,0xed,0xa2,0x10,0x56,0x3c,0x01,0x86,0x71,0x13,0xda,0x99,0x6b,0x98,0xfe,0xfd,0x98,0xda,0x14,0x71,0x12,0x98,0xfe,0x0f,0x72,0x13,0xdc,0x98,0x6b,0x98, -0x01,0x03,0x99,0xda,0x14,0x72,0x12,0x98,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x03,0x00,0x21,0x00,0x31,0x00,0x45,0x00,0x8d,0x40,0x11,0x2b,0x2a,0x23,0x22,0x04,0x08,0x04,0x01,0x4c,0x0d,0x01,0x04,0x06,0x01,0x08,0x02,0x4b,0x4b,0xb0,0x26,0x50,0x58,0x40,0x2f,0x00,0x08,0x04,0x03,0x04,0x08,0x03,0x80,0x00,0x03, -0x06,0x04,0x03,0x06,0x7e,0x00,0x06,0x00,0x01,0x00,0x06,0x01,0x68,0x07,0x01,0x04,0x04,0x0a,0x5f,0x00,0x0a,0x0a,0x10,0x4d,0x05,0x02,0x02,0x00,0x00,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x2d,0x00,0x08,0x04,0x03,0x04,0x08,0x03,0x80,0x00,0x03,0x06,0x04,0x03,0x06,0x7e,0x00,0x0a,0x07,0x01,0x04,0x08,0x0a,0x04,0x67, -0x00,0x06,0x00,0x01,0x00,0x06,0x01,0x68,0x05,0x02,0x02,0x00,0x00,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x40,0x10,0x40,0x3d,0x38,0x35,0x17,0x26,0x33,0x11,0x13,0x3b,0x11,0x11,0x10,0x0b,0x07,0x1f,0x2b,0x17,0x21,0x35,0x21,0x05,0x33,0x11,0x34,0x26,0x2f,0x01,0x2e,0x01,0x07,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35, -0x23,0x11,0x33,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x07,0x03,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x33,0x32,0x36,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x1f,0x01,0x1e,0x01,0xd6,0x01,0xad,0xfe,0x53,0x01,0xf4,0x48,0x0c,0x05,0x9d,0x05,0x1c,0x08,0x1e,0x17,0xfe, -0xbe,0x16,0x1e,0x01,0x48,0x48,0x20,0x15,0x01,0xd1,0x16,0x20,0x01,0xd6,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x64,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x02,0x05,0x17,0x36,0x0f,0x9c,0x10,0x16,0x07,0xd6,0xd6,0x01,0xf4,0x08,0x1a,0x07,0x9c,0x06,0x0c,0x01,0xe8,0x16,0x20,0x20,0x16,0xe8,0xfd,0x36, -0xe8,0x16,0x20,0x20,0x16,0x01,0x1e,0xb2,0x08,0x0a,0x0a,0x08,0xb2,0x07,0x0c,0x01,0x0a,0x0a,0xfd,0xfa,0x16,0x20,0x20,0x16,0x02,0xee,0x16,0x20,0x18,0x0e,0x9d,0x0f,0x36,0x00,0x00,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x03,0xe8,0x03,0x0b,0x00,0x03,0x00,0x13,0x00,0x3c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x15,0x00,0x01,0x01,0x03,0x5f, -0x00,0x03,0x03,0x10,0x4d,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x01,0x00,0x03,0x01,0x67,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x35,0x34,0x11,0x10,0x04,0x07,0x1a,0x2b,0x37,0x21,0x11,0x21,0x25,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x37,0x11,0x34,0x36, -0x37,0x21,0x32,0x16,0x8f,0x02,0xca,0xfd,0x36,0x03,0x59,0x34,0x25,0xfc,0xca,0x24,0x36,0x01,0x34,0x25,0x03,0x36,0x25,0x34,0x40,0x01,0xad,0xc4,0xfd,0x5a,0x25,0x34,0x01,0x36,0x24,0x02,0xa6,0x25,0x34,0x01,0x36,0x00,0x00,0x00,0x00,0x03,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x08,0x00,0x15,0x00,0x22,0x00,0x59,0x4b,0xb0, -0x26,0x50,0x58,0x40,0x1e,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x69,0x06,0x01,0x02,0x02,0x05,0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x03,0x03,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x1c,0x00,0x05,0x06,0x01,0x02,0x01,0x05,0x02,0x69,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x69,0x00,0x03,0x03,0x04,0x61,0x00,0x04,0x04,0x11, -0x04,0x4e,0x59,0x40,0x11,0x0a,0x09,0x20,0x1f,0x1a,0x19,0x10,0x0f,0x09,0x15,0x0a,0x15,0x13,0x12,0x07,0x07,0x18,0x2b,0x01,0x14,0x06,0x22,0x2e,0x01,0x36,0x32,0x16,0x27,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02,0x3b,0x52,0x78,0x52,0x02,0x56,0x74,0x56, -0x90,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0xf5,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x00,0x02,0x00,0x00, -0xff,0x6a,0x02,0x83,0x03,0x0b,0x00,0x0b,0x00,0x2e,0x00,0x65,0xb6,0x07,0x01,0x02,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x1d,0x00,0x03,0x02,0x03,0x86,0x09,0x05,0x02,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x08,0x06,0x02,0x00,0x00,0x07,0x5f,0x00,0x07,0x07,0x10,0x00,0x4e,0x1b,0x40,0x24,0x00,0x03,0x02,0x03,0x86, -0x00,0x07,0x08,0x06,0x02,0x00,0x01,0x07,0x00,0x69,0x09,0x05,0x02,0x01,0x02,0x02,0x01,0x59,0x09,0x05,0x02,0x01,0x01,0x02,0x5f,0x04,0x01,0x02,0x01,0x02,0x4f,0x59,0x40,0x0e,0x2d,0x2c,0x13,0x33,0x11,0x14,0x22,0x33,0x15,0x15,0x13,0x0a,0x07,0x1f,0x2b,0x01,0x35,0x34,0x26,0x22,0x06,0x1d,0x01,0x14,0x16,0x32,0x36,0x05,0x14,0x06, -0x27,0x23,0x03,0x0e,0x01,0x07,0x23,0x22,0x27,0x03,0x23,0x22,0x26,0x27,0x34,0x36,0x33,0x11,0x22,0x2e,0x01,0x36,0x37,0x21,0x32,0x16,0x14,0x06,0x27,0x11,0x32,0x16,0x01,0x0c,0x0a,0x10,0x0a,0x0a,0x10,0x0a,0x01,0x77,0x16,0x0e,0xef,0x1d,0x01,0x0a,0x06,0x01,0x0f,0x02,0x2b,0xe1,0x0f,0x14,0x01,0x58,0x37,0x1d,0x2a,0x02,0x2e,0x1b, -0x01,0x65,0x1d,0x2a,0x2a,0x1d,0x37,0x58,0x01,0x70,0xfa,0x08,0x0a,0x0a,0x08,0xfa,0x08,0x0a,0x0a,0xbd,0x0e,0x16,0x01,0xfe,0xf2,0x07,0x08,0x01,0x0f,0x01,0x0f,0x14,0x0f,0x45,0x6e,0x01,0x1e,0x2a,0x3a,0x2a,0x01,0x2c,0x38,0x2c,0x01,0xfe,0xe2,0x6e,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5b,0x03,0x0b,0x00,0x24,0x00,0x47,0x00,0x81, -0x40,0x13,0x43,0x25,0x02,0x06,0x09,0x2f,0x01,0x05,0x06,0x17,0x01,0x03,0x02,0x08,0x01,0x01,0x03,0x04,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x29,0x00,0x09,0x07,0x01,0x05,0x02,0x09,0x05,0x67,0x00,0x06,0x06,0x08,0x61,0x00,0x08,0x08,0x10,0x4d,0x04,0x01,0x02,0x02,0x01,0x61,0x00,0x01,0x01,0x14,0x4d,0x00,0x03,0x03,0x00,0x61,0x00, -0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x27,0x00,0x08,0x00,0x06,0x05,0x08,0x06,0x69,0x00,0x09,0x07,0x01,0x05,0x02,0x09,0x05,0x67,0x04,0x01,0x02,0x02,0x01,0x61,0x00,0x01,0x01,0x14,0x4d,0x00,0x03,0x03,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0x40,0x0e,0x46,0x45,0x26,0x25,0x25,0x36,0x25,0x26,0x35,0x14,0x24,0x0a,0x07,0x1f, -0x2b,0x01,0x14,0x15,0x0e,0x01,0x23,0x22,0x26,0x27,0x07,0x06,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x06,0x0f,0x01,0x1e,0x01,0x37,0x32,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x36,0x3f,0x01,0x26,0x23,0x22,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x37,0x35,0x3e, -0x01,0x33,0x32,0x16,0x17,0x37,0x36,0x32,0x16,0x03,0x4b,0x24,0xe4,0x99,0x51,0x98,0x3c,0x48,0x0b,0x1c,0x16,0x16,0x0e,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x28,0x64,0x37,0x4a,0x82,0x27,0x06,0x18,0x04,0x0c,0x6b,0x08,0x0a,0x0e,0x14,0x10,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x52,0x70,0x4b,0x82,0x27,0x06,0x17,0x05,0x0c,0x6f,0x07,0x0c,0x01, -0x24,0xe6,0x99,0x51,0x9a,0x3c,0x48,0x0b,0x1c,0x18,0x01,0x05,0x03,0x01,0x96,0xba,0x3e,0x39,0x48,0x0b,0x16,0x0e,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x24,0x2a,0x01,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x01,0xb8,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x4d,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x06,0x04,0x96,0xba,0x3e,0x39,0x48,0x0b,0x16,0x00, -0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x39,0x40,0x09,0x18,0x10,0x08,0x00,0x04,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0d,0x03,0x01,0x01,0x01,0x10,0x4d,0x02,0x01,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0d,0x03,0x01,0x01,0x01,0x00,0x5f,0x02,0x01,0x00,0x00,0x11,0x00,0x4e,0x59, -0xb6,0x35,0x35,0x35,0x33,0x04,0x07,0x1a,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0xfe,0x0b,0x14,0x10,0xfe,0xe3,0x0f,0x14, -0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0x02,0xe7,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x30,0xb6,0x08,0x00,0x02,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x0b,0x00,0x01,0x01, -0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x00,0x11,0x00,0x4e,0x59,0xb4,0x35,0x33,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfc,0xef,0x0f,0x14,0x01,0x16,0x0e,0x03,0x11,0x0f,0x16,0x02,0xe7,0xfc, -0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x00,0x00,0x01,0xff,0xfe,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x30,0x00,0x69,0x40,0x0a,0x2d,0x01,0x01,0x05,0x09,0x01,0x00,0x01,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x24,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x00,0x03,0x02,0x01,0x03,0x02,0x7e,0x00,0x01,0x01,0x05, -0x61,0x00,0x05,0x05,0x10,0x4d,0x00,0x02,0x02,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x22,0x00,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x00,0x03,0x02,0x01,0x03,0x02,0x7e,0x00,0x05,0x00,0x01,0x00,0x05,0x01,0x69,0x00,0x02,0x02,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x59,0x40,0x09,0x27,0x27,0x13,0x27,0x24,0x33,0x06, -0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3f,0x01,0x26,0x23,0x22,0x0e,0x02,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x3e,0x01,0x1f,0x01,0x1e,0x01,0x07,0x0e,0x01,0x07,0x22,0x2e,0x02,0x3e,0x03,0x33,0x32,0x16,0x17,0x37,0x36,0x16,0x03,0x59,0x14,0x10,0xfa,0x17,0x13,0x11,0x4d,0x52,0x70,0x3a,0x6a,0x4c,0x2e,0x2e,0x4c, -0x6a,0x3a,0x42,0x76,0x29,0x04,0x11,0x06,0x4c,0x05,0x02,0x06,0x3c,0xae,0x5f,0x57,0xa0,0x70,0x48,0x04,0x40,0x78,0x98,0x5b,0x52,0x98,0x3d,0x48,0x11,0x2c,0x02,0xc3,0xfa,0x0e,0x16,0x2d,0x10,0x4d,0x4d,0x2e,0x4c,0x6a,0x74,0x6a,0x4c,0x2e,0x3a,0x35,0x06,0x01,0x05,0x4d,0x04,0x0e,0x06,0x4a,0x50,0x01,0x44,0x74,0x9e,0xae,0x9e,0x74, -0x44,0x3e,0x39,0x48,0x12,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58,0x01,0xe6,0x00,0x15,0x00,0x19,0x40,0x16,0x0f,0x01,0x00,0x01,0x01,0x4c,0x02,0x01,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37, -0x36,0x32,0x1f,0x01,0x16,0x02,0x58,0x06,0xfe,0xfc,0x05,0x10,0x04,0xfe,0xfc,0x06,0x06,0x1c,0x05,0x0e,0x06,0xdb,0xdc,0x05,0x10,0x04,0x1c,0x06,0x01,0xb7,0x07,0x05,0xfe,0xfb,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x00,0x00,0x00,0x03,0xff,0xfd,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0c, -0x00,0x1c,0x00,0x2e,0x00,0x6a,0x40,0x0d,0x28,0x1e,0x02,0x05,0x04,0x16,0x15,0x0e,0x03,0x03,0x02,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1e,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x04,0x04,0x00,0x61,0x06,0x01,0x00,0x00,0x10,0x4d,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x40,0x1c,0x06,0x01,0x00, -0x00,0x04,0x05,0x00,0x04,0x67,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x11,0x01,0x4e,0x59,0x40,0x13,0x01,0x00,0x2c,0x2a,0x23,0x21,0x1a,0x18,0x12,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x07,0x07,0x16,0x2b,0x01,0x32,0x1e,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x13,0x35,0x34,0x26, -0x2b,0x01,0x22,0x06,0x07,0x15,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34,0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x13,0x14,0x16,0x3b,0x01,0x32,0x36,0x01,0xad,0x74,0xc6,0x72,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xc1,0x0a,0x07,0x6b,0x08,0x0a,0x01,0x0c,0x07,0x6b,0x07,0x0a,0x01,0x0a,0x06,0x05,0x08,0x7b,0x08,0x05,0x06, -0x0a,0x0a,0x09,0x67,0x08,0x0a,0x03,0x0b,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0xfd,0x48,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xc7,0x01,0x5a,0x07,0x03,0x05,0x05,0x03,0x07,0xfe,0xa6,0x06,0x08,0x08,0x00,0x01,0x00,0x00,0xff,0xef,0x02,0xd4,0x02,0x86,0x00,0x24,0x00,0x26,0x40,0x23,0x22,0x19,0x10,0x07, -0x04,0x00,0x02,0x01,0x4c,0x03,0x01,0x02,0x00,0x00,0x02,0x59,0x03,0x01,0x02,0x02,0x00,0x61,0x01,0x01,0x00,0x02,0x00,0x51,0x14,0x1c,0x14,0x14,0x04,0x07,0x1a,0x2b,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37,0x36,0x32,0x1f,0x01,0x16, -0x14,0x0f,0x01,0x17,0x16,0x02,0xd4,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10,0x10,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x0f,0x0f,0xa4,0xa4,0x0f,0x70,0x16,0x10,0x4c,0x0f,0x0f,0xa5,0xa5,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10, -0x10,0x4c,0x0f,0x2e,0x0f,0xa4,0xa4,0x0f,0x00,0x03,0x00,0x00,0xff,0xb1,0x03,0xc5,0x03,0x0b,0x00,0x0c,0x00,0x1c,0x00,0x2c,0x00,0x5c,0x40,0x0b,0x25,0x1d,0x02,0x04,0x05,0x00,0x01,0x01,0x00,0x02,0x4c,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1d,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x04,0x05,0x5f,0x00,0x05,0x05,0x10,0x4d, -0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x1b,0x00,0x05,0x00,0x04,0x03,0x05,0x04,0x67,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0x40,0x09,0x35,0x35,0x35,0x35,0x24,0x32,0x06,0x07,0x1c,0x2b,0x01,0x34,0x26,0x07,0x23,0x22,0x0e,0x01,0x16,0x17, -0x33,0x32,0x36,0x25,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x37,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x37,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x02,0x5f,0x14,0x10,0x8e,0x0f,0x14,0x02,0x18,0x0d,0x8e,0x0f,0x16,0x01,0x41,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x23,0x14, -0x0f,0xfc,0xa6,0x0e,0x16,0x01,0x14,0x0f,0x03,0x5a,0x0e,0x16,0x01,0x82,0x0e,0x16,0x01,0x14,0x1e,0x14,0x01,0x16,0x79,0xfd,0xe8,0x0e,0x16,0x16,0x0e,0x02,0x18,0x0e,0x16,0x16,0xec,0x8f,0x0e,0x16,0x16,0x0e,0x8f,0x0e,0x16,0x16,0x00,0x05,0x00,0x00,0xff,0x88,0x03,0xac,0x03,0x34,0x00,0x43,0x00,0x4c,0x00,0x55,0x00,0x5e,0x00,0x67, -0x00,0x61,0x40,0x5e,0x3c,0x33,0x02,0x05,0x0a,0x1a,0x0f,0x02,0x01,0x05,0x2b,0x22,0x19,0x10,0x09,0x00,0x06,0x08,0x01,0x03,0x4c,0x07,0x01,0x05,0x03,0x01,0x01,0x08,0x05,0x01,0x67,0x00,0x0a,0x0f,0x0c,0x02,0x08,0x09,0x0a,0x08,0x69,0x10,0x0e,0x0d,0x03,0x09,0x04,0x02,0x02,0x00,0x09,0x00,0x65,0x00,0x0b,0x0b,0x06,0x61,0x00,0x06, -0x06,0x12,0x0b,0x4e,0x60,0x5f,0x64,0x63,0x5f,0x67,0x60,0x67,0x5d,0x5c,0x59,0x58,0x54,0x53,0x50,0x4f,0x4b,0x4a,0x15,0x36,0x16,0x37,0x18,0x36,0x16,0x36,0x14,0x11,0x07,0x1f,0x2b,0x25,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x34,0x2b,0x01,0x22,0x27,0x15,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x06,0x2b, -0x01,0x22,0x0e,0x01,0x1d,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x3d,0x01,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x15,0x14,0x3b,0x01,0x32,0x16,0x15,0x05,0x34,0x26,0x22,0x06,0x14,0x16,0x32,0x36,0x13,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x34,0x26,0x22,0x06,0x14,0x16, -0x32,0x36,0x05,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x64,0x48,0x46,0x64,0x46,0x48,0x4c,0x64,0x2c,0x22,0x48,0x46,0x64,0x46,0x48,0x1e,0x2e,0x64,0x22,0x26,0x06,0x48,0x46,0x64,0x46,0x48,0x56,0x58,0x64,0x4c,0x48,0x46,0x64,0x46,0x48,0x4e,0x64,0x56,0x56,0xfd,0x5a,0x2a,0x38,0x28,0x28,0x38,0x2a,0xd4,0x28,0x38,0x2a,0x2a, -0x38,0x28,0x8a,0x2a,0x38,0x28,0x28,0x38,0x2a,0x01,0x18,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x70,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x4e,0x0c,0xcc,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0xcc,0x0c,0x26,0x1c,0x0c,0x72,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x40,0x6c,0x34,0x8c,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c, -0x22,0x8c,0x34,0x6c,0x40,0xe2,0x1e,0x28,0x28,0x3a,0x28,0x28,0x02,0xd8,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x26,0x1e,0x28,0x28,0x3a,0x28,0x28,0x28,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x6f,0x40,0x0a,0x0d,0x01,0x00,0x01,0x1f,0x01,0x04,0x03,0x02,0x4c, -0x4b,0xb0,0x24,0x50,0x58,0x40,0x26,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04,0x7e,0x00,0x01,0x01,0x07,0x5f,0x00,0x07,0x07,0x10,0x4d,0x00,0x04,0x04,0x06,0x60,0x00,0x06,0x06,0x11,0x06,0x4e,0x1b,0x40,0x24,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04, -0x7e,0x00,0x07,0x00,0x01,0x00,0x07,0x01,0x67,0x00,0x04,0x04,0x06,0x60,0x00,0x06,0x06,0x11,0x06,0x4e,0x59,0x40,0x0b,0x35,0x35,0x23,0x33,0x16,0x23,0x24,0x23,0x08,0x07,0x1e,0x2b,0x01,0x35,0x34,0x26,0x07,0x23,0x35,0x34,0x26,0x27,0x23,0x22,0x06,0x07,0x15,0x23,0x22,0x06,0x07,0x15,0x14,0x16,0x37,0x33,0x15,0x14,0x16,0x3b,0x01, -0x32,0x36,0x37,0x35,0x33,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xb3,0x16,0x0e,0x47,0x0f,0x14,0x01,0xb2,0x0f,0x14,0x01,0x16,0x0e,0xb2,0x16,0x0e,0x47,0x0f,0x14,0x01,0xb3,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01, -0x3a,0x48,0x0e,0x16,0x01,0xb3,0x0f,0x14,0x01,0x16,0x0e,0xb3,0x14,0x0f,0x48,0x0e,0x16,0x01,0xb3,0x0e,0x16,0x16,0x0e,0xb3,0x14,0x01,0x3f,0xfd,0xe8,0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x3c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x15,0x00, -0x00,0x00,0x03,0x5f,0x00,0x03,0x03,0x10,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x1b,0x40,0x13,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x59,0xb6,0x35,0x35,0x26,0x33,0x04,0x07,0x1a,0x2b,0x01,0x35,0x34,0x26,0x07,0x21,0x22,0x06,0x07,0x15,0x14,0x16, -0x37,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x01,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x01,0x3f,0xfd, -0xe8,0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x17,0x00,0x2c,0x00,0x51,0x4b,0xb0,0x26,0x50,0x58,0x40,0x1a,0x00,0x05,0x00,0x00,0x02,0x05,0x00,0x67,0x00,0x02,0x00,0x03,0x02,0x03,0x63,0x00,0x01,0x01,0x04,0x5f,0x00,0x04,0x04,0x10,0x01,0x4e,0x1b,0x40,0x20, -0x00,0x04,0x00,0x01,0x05,0x04,0x01,0x67,0x00,0x05,0x00,0x00,0x02,0x05,0x00,0x67,0x00,0x02,0x03,0x03,0x02,0x57,0x00,0x02,0x02,0x03,0x5f,0x00,0x03,0x02,0x03,0x4f,0x59,0x40,0x09,0x23,0x35,0x35,0x35,0x35,0x33,0x06,0x07,0x1c,0x2b,0x25,0x11,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06,0x15,0x11,0x14, -0x16,0x33,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0x59,0x1e,0x17,0xfe,0x77,0x17,0x1e,0x01,0x1e,0x17,0xb3,0x16,0x20,0x20,0x16,0x02,0xa7,0x16,0x20,0x47,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x76,0x01, -0x89,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfd,0xe8,0x16,0x20,0x20,0x01,0x9f,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x1b,0xf3,0xb7,0xb3,0x5f,0x0f,0x3c,0xf5,0x00,0x0f,0x03,0xe8,0x00,0x00,0x00,0x00,0xe1,0xa1,0x0d,0xf0, -0x00,0x00,0x00,0x00,0xe1,0xa1,0x0d,0xf1,0xff,0xf5,0xff,0x6a,0x04,0x2f,0x03,0x53,0x00,0x00,0x00,0x08,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x03,0x52,0xff,0x6a,0x00,0x00,0x04,0x2f,0xff,0xf5,0xff,0xf5,0x04,0x2f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c, -0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x80,0x00,0x00,0x03,0x11,0x00,0x00,0x00,0xf0,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x59,0xff,0xfd,0x03,0x59,0xff,0xfd,0x02,0x3b,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x11,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0xe8,0x00,0x00,0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00,0x02,0x3b,0xff,0xff, -0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x03,0xca,0x00,0x00,0x04,0x2f,0xff,0xff,0x03,0xa0,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xd4,0xff,0xf7,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xff,0x02,0x82,0x00,0x00,0x02,0xda,0x00,0x00, -0x04,0x2f,0xff,0xff,0x02,0xf8,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x59,0x00,0x00,0x02,0xda,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xf5,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x82,0x00,0x00, -0x03,0x42,0x00,0x00,0x04,0x2f,0x00,0x00,0x00,0xdc,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe7,0xff,0xfe,0x03,0x59,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x3b,0xff,0xff,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x02,0x82,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0xff,0xff,0x03,0x59,0xff,0xfd,0x02,0x82,0x00,0x00, -0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0xff,0xfe,0x02,0x82,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x11,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x01,0x0a,0x01,0xce,0x02,0x3a,0x02,0xb8,0x03,0x06, -0x03,0x34,0x03,0x60,0x04,0x0c,0x05,0x06,0x05,0x62,0x06,0x12,0x06,0x3c,0x06,0x5e,0x06,0x88,0x06,0xc0,0x06,0xf8,0x07,0xa0,0x08,0x00,0x08,0xd2,0x09,0x36,0x09,0x74,0x09,0x98,0x09,0xf2,0x0a,0x3a,0x0b,0x12,0x0c,0x18,0x0c,0xa4,0x0d,0xae,0x0e,0x06,0x0e,0x2c,0x0e,0x8e,0x0f,0x12,0x0f,0x64,0x0f,0xfa,0x10,0x22,0x10,0x76,0x11,0x7a, -0x11,0x98,0x11,0xd0,0x12,0x3a,0x12,0x96,0x12,0xf6,0x13,0xdc,0x14,0x78,0x14,0xee,0x15,0x28,0x15,0xec,0x16,0x96,0x16,0xba,0x17,0xc8,0x18,0x2a,0x18,0x82,0x18,0xa0,0x18,0xea,0x19,0x86,0x1a,0x06,0x1a,0x5a,0x1a,0xd6,0x1b,0x84,0x1b,0xc8,0x1c,0x30,0x1c,0xaa,0x1d,0x52,0x1d,0xa2,0x1d,0xd8,0x1e,0x56,0x1e,0x8c,0x1f,0x08,0x1f,0x56, -0x1f,0xc8,0x20,0x84,0x21,0x06,0x21,0x58,0x21,0xc3,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x4c,0x00,0x90,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x42,0x00,0x7b,0x00,0x8d,0x00,0x00,0x00,0xba,0x0e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0xde,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x01, -0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x35,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x00,0x3d,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x4c,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x0b,0x00,0x54,0x00,0x01,0x00,0x00,0x00,0x00, -0x00,0x06,0x00,0x08,0x00,0x5f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x2b,0x00,0x67,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x13,0x00,0x92,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x00,0x00,0x6a,0x00,0xa5,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x01,0x00,0x10,0x01,0x0f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x02,0x00,0x0e, -0x01,0x1f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x03,0x00,0x10,0x01,0x2d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x04,0x00,0x10,0x01,0x3d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x05,0x00,0x16,0x01,0x4d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x06,0x00,0x10,0x01,0x63,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0a,0x00,0x56,0x01,0x73,0x00,0x03, -0x00,0x01,0x04,0x09,0x00,0x0b,0x00,0x26,0x01,0xc9,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x43,0x29,0x20,0x32,0x30,0x32,0x33,0x20,0x62,0x79,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x61,0x75,0x74,0x68,0x6f,0x72,0x73,0x20,0x40,0x20,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x66, -0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x47,0x65,0x6e,0x65,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x76, -0x67,0x32,0x74,0x74,0x66,0x20,0x66,0x72,0x6f,0x6d,0x20,0x46,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x20,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x00,0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00, -0x74,0x00,0x20,0x00,0x28,0x00,0x43,0x00,0x29,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x32,0x00,0x33,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x6f,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x20,0x00,0x61,0x00,0x75,0x00,0x74,0x00,0x68,0x00,0x6f,0x00,0x72,0x00,0x73,0x00,0x20,0x00,0x40,0x00, -0x20,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00,0x61,0x00,0x72,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00, -0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x31,0x00,0x2e,0x00,0x30,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x47,0x00, -0x65,0x00,0x6e,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x64,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x73,0x00,0x76,0x00,0x67,0x00,0x32,0x00,0x74,0x00,0x74,0x00,0x66,0x00,0x20,0x00,0x66,0x00,0x72,0x00,0x6f,0x00,0x6d,0x00,0x20,0x00,0x46,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00, -0x6f,0x00,0x20,0x00,0x70,0x00,0x72,0x00,0x6f,0x00,0x6a,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x2e,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x00,0x00,0x00,0x02,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x01,0x02,0x01,0x03,0x01,0x04,0x01,0x05,0x01,0x06,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c,0x01,0x0d,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12, -0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e,0x01,0x1f,0x01,0x20,0x01,0x21,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29,0x01,0x2a,0x01,0x2b,0x01,0x2c,0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x01,0x32, -0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x01,0x41,0x01,0x42,0x01,0x43,0x01,0x44,0x01,0x45,0x01,0x46,0x01,0x47,0x01,0x48,0x01,0x49,0x01,0x4a,0x01,0x4b,0x01,0x4c,0x01,0x4d,0x00,0x0b,0x63,0x68,0x65,0x63,0x6b,0x2d,0x65,0x6d, -0x70,0x74,0x79,0x0d,0x66,0x6c,0x6f,0x77,0x2d,0x70,0x61,0x72,0x61,0x6c,0x6c,0x65,0x6c,0x05,0x74,0x72,0x61,0x73,0x68,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x6c,0x69,0x6e,0x65,0x0c,0x70,0x6c,0x75,0x73,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x0d,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x06,0x63,0x69,0x72, -0x63,0x6c,0x65,0x08,0x64,0x6f,0x77,0x6e,0x2d,0x64,0x69,0x72,0x05,0x63,0x68,0x65,0x63,0x6b,0x0b,0x74,0x72,0x61,0x73,0x68,0x2d,0x65,0x6d,0x70,0x74,0x79,0x04,0x75,0x73,0x65,0x72,0x09,0x62,0x72,0x69,0x65,0x66,0x63,0x61,0x73,0x65,0x08,0x6c,0x65,0x66,0x74,0x2d,0x64,0x69,0x72,0x09,0x72,0x69,0x67,0x68,0x74,0x2d,0x64,0x69,0x72, -0x06,0x75,0x70,0x2d,0x64,0x69,0x72,0x0a,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x6c,0x65,0x66,0x74,0x0b,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x72,0x69,0x67,0x68,0x74,0x0c,0x68,0x65,0x6c,0x70,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03,0x74,0x61,0x67,0x04,0x67,0x72,0x69,0x64,0x0b,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f,0x70,0x65,0x6e, -0x06,0x66,0x6f,0x6c,0x64,0x65,0x72,0x09,0x64,0x6f,0x77,0x6e,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x70,0x61,0x6c,0x65,0x74,0x74,0x65,0x07,0x64,0x6f,0x63,0x2d,0x69,0x6e,0x76,0x03,0x63,0x6f,0x67,0x02,0x74,0x68,0x0a,0x62,0x69,0x6e,0x6f,0x63,0x75,0x6c,0x61,0x72,0x73,0x04,0x6c,0x69,0x73,0x74,0x04,0x6c,0x6f,0x63,0x6b,0x09,0x6c,0x65, -0x66,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x64,0x65,0x73,0x6b,0x74,0x6f,0x70,0x06,0x73,0x65,0x61,0x72,0x63,0x68,0x0c,0x63,0x69,0x72,0x63,0x6c,0x65,0x2d,0x65,0x6d,0x70,0x74,0x79,0x06,0x70,0x65,0x6e,0x63,0x69,0x6c,0x0a,0x72,0x69,0x67,0x68,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x0b,0x63,0x6c,0x6f,0x73,0x65,0x5f,0x70,0x61,0x6e,0x65, -0x6c,0x08,0x73,0x74,0x65,0x70,0x69,0x6e,0x74,0x6f,0x07,0x75,0x70,0x2d,0x62,0x6f,0x6c,0x64,0x02,0x6f,0x6b,0x09,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x10,0x68,0x6f,0x72,0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x0e,0x76,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x08, -0x73,0x74,0x65,0x70,0x6f,0x76,0x65,0x72,0x10,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x11,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x08,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x75,0x70,0x09,0x63,0x6c,0x69,0x70,0x62,0x6f,0x61,0x72,0x64,0x11,0x66, -0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f,0x70,0x65,0x6e,0x2d,0x65,0x6d,0x70,0x74,0x79,0x03,0x64,0x6f,0x74,0x07,0x73,0x74,0x65,0x70,0x6f,0x75,0x74,0x07,0x67,0x6c,0x61,0x73,0x73,0x65,0x73,0x03,0x64,0x6f,0x63,0x04,0x70,0x6c,0x61,0x79,0x06,0x74,0x6f,0x2d,0x65,0x6e,0x64,0x0c,0x69,0x6e,0x66,0x6f,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65, -0x64,0x03,0x63,0x63,0x77,0x0d,0x6c,0x6f,0x63,0x6b,0x2d,0x6f,0x70,0x65,0x6e,0x2d,0x61,0x6c,0x74,0x06,0x74,0x61,0x72,0x67,0x65,0x74,0x06,0x66,0x6c,0x6f,0x70,0x70,0x79,0x0f,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2d,0x6d,0x61,0x78,0x69,0x6d,0x69,0x7a,0x65,0x0b,0x64,0x6f,0x74,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03,0x70,0x69, -0x6e,0x09,0x61,0x72,0x72,0x6f,0x77,0x73,0x2d,0x63,0x77,0x05,0x70,0x61,0x75,0x73,0x65,0x04,0x73,0x74,0x6f,0x70,0x02,0x63,0x77,0x0a,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x64,0x6f,0x77,0x6e,0x11,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x06,0x63,0x61,0x6e,0x63,0x65,0x6c,0x03,0x62,0x6f, -0x78,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x74,0x72,0x65,0x65,0x0c,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x0d,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x0c,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x65,0x6d,0x70,0x74,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0xff,0xff,0x00,0x0f, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x01,0x1e,0x00,0x7d,0x00,0x7d,0x01,0x1e,0x03,0x18,0xff,0xb1,0x03,0x38,0x02,0xc8,0xff,0xd0,0xff,0xb1,0x03,0x18,0xff,0xb1,0x03,0x38,0x02,0xc8,0xff,0xd0,0xff,0xb1,0xb0,0x00,0x2c,0x20,0xb0,0x00,0x55,0x58, -0x45,0x59,0x20,0x20,0x4b,0xb8,0x00,0x0e,0x51,0x4b,0xb0,0x06,0x53,0x5a,0x58,0xb0,0x34,0x1b,0xb0,0x28,0x59,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x62,0x1b,0x21,0x21,0xb0,0x00,0x59,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x01,0x2c,0xb0,0x20, -0x60,0x66,0x2d,0xb0,0x02,0x2c,0x23,0x21,0x23,0x21,0x2d,0xb0,0x03,0x2c,0x20,0x64,0xb3,0x03,0x14,0x15,0x00,0x42,0x43,0xb0,0x13,0x43,0x20,0x60,0x60,0x42,0xb1,0x02,0x14,0x43,0x42,0xb1,0x25,0x03,0x43,0xb0,0x02,0x43,0x54,0x78,0x20,0xb0,0x0c,0x23,0xb0,0x02,0x43,0x43,0x61,0x64,0xb0,0x04,0x50,0x78,0xb2,0x02,0x02,0x02,0x43,0x60, -0x42,0xb0,0x21,0x65,0x1c,0x21,0xb0,0x02,0x43,0x43,0xb2,0x0e,0x15,0x01,0x42,0x1c,0x20,0xb0,0x02,0x43,0x23,0x42,0xb2,0x13,0x01,0x13,0x43,0x60,0x42,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb2,0x16,0x01,0x02,0x43,0x60,0x42,0x2d,0xb0,0x04,0x2c,0xb0,0x03,0x2b,0xb0,0x15,0x43,0x58,0x23,0x21,0x23,0x21,0xb0,0x16,0x43,0x43,0x23,0xb0, -0x00,0x50,0x58,0x65,0x59,0x1b,0x20,0x64,0x20,0xb0,0xc0,0x50,0xb0,0x04,0x26,0x5a,0xb2,0x28,0x01,0x0d,0x43,0x45,0x63,0x45,0xb0,0x06,0x45,0x58,0x21,0xb0,0x03,0x25,0x59,0x52,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20,0xb0,0x38,0x50,0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb1, -0x01,0x0d,0x43,0x45,0x63,0x45,0x61,0x64,0xb0,0x28,0x50,0x58,0x21,0xb1,0x01,0x0d,0x43,0x45,0x63,0x45,0x20,0xb0,0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x0a,0x50,0x58,0x60,0x1b,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0a,0x60,0x1b,0x20,0xb0,0x36,0x50,0x58,0x21, -0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x02,0x25,0xb0,0x0c,0x43,0x63,0xb0,0x00,0x52,0x58,0xb0,0x00,0x4b,0xb0,0x0a,0x50,0x58,0x21,0xb0,0x0c,0x43,0x1b,0x4b,0xb0,0x1e,0x50,0x58,0x21,0xb0,0x1e,0x4b,0x61,0xb8,0x10,0x00,0x63,0xb0,0x0c,0x43,0x63,0xb8,0x05,0x00,0x62,0x59,0x59,0x64,0x61,0x59,0xb0,0x01,0x2b,0x59,0x59, -0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x59,0x20,0x64,0xb0,0x16,0x43,0x23,0x42,0x59,0x2d,0xb0,0x05,0x2c,0x20,0x45,0x20,0xb0,0x04,0x25,0x61,0x64,0x20,0xb0,0x07,0x43,0x50,0x58,0xb0,0x07,0x23,0x42,0xb0,0x08,0x23,0x42,0x1b,0x21,0x21,0x59,0xb0,0x01,0x60,0x2d,0xb0,0x06,0x2c,0x23,0x21,0x23,0x21,0xb0,0x03,0x2b,0x20,0x64,0xb1,0x07, -0x62,0x42,0x20,0xb0,0x08,0x23,0x42,0xb0,0x06,0x45,0x58,0x1b,0xb1,0x01,0x0d,0x43,0x45,0x63,0xb1,0x01,0x0d,0x43,0xb0,0x01,0x60,0x45,0x63,0xb0,0x05,0x2a,0x21,0x20,0xb0,0x08,0x43,0x20,0x8a,0x20,0x8a,0xb0,0x01,0x2b,0xb1,0x30,0x05,0x25,0xb0,0x04,0x26,0x51,0x58,0x60,0x50,0x1b,0x61,0x52,0x59,0x58,0x23,0x59,0x21,0x59,0x20,0xb0, -0x40,0x53,0x58,0xb0,0x01,0x2b,0x1b,0x21,0xb0,0x40,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x2d,0xb0,0x07,0x2c,0xb0,0x09,0x43,0x2b,0xb2,0x00,0x02,0x00,0x43,0x60,0x42,0x2d,0xb0,0x08,0x2c,0xb0,0x09,0x23,0x42,0x23,0x20,0xb0,0x00,0x23,0x42,0x61,0xb0,0x02,0x62,0x66,0xb0,0x01,0x63,0xb0,0x01,0x60,0xb0,0x07,0x2a,0x2d,0xb0,0x09, -0x2c,0x20,0x20,0x45,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0a,0x2c,0xb2,0x09,0x0e,0x00,0x43,0x45,0x42,0x2a,0x21,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x0b,0x2c,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00, -0x43,0x60,0x42,0x2d,0xb0,0x0c,0x2c,0x20,0x20,0x45,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x00,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0, -0x01,0x60,0x2d,0xb0,0x0d,0x2c,0x20,0x20,0x45,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0xb0,0x24,0x50,0x58,0xb0,0x00,0x1b,0xb0,0x40,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0e,0x2c,0x20,0xb0,0x00,0x23,0x42, -0xb3,0x0d,0x0c,0x00,0x03,0x45,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x2a,0x21,0x2d,0xb0,0x0f,0x2c,0xb1,0x02,0x02,0x45,0xb0,0x64,0x61,0x44,0x2d,0xb0,0x10,0x2c,0xb0,0x01,0x60,0x20,0x20,0xb0,0x0f,0x43,0x4a,0xb0,0x00,0x50,0x58,0x20,0xb0,0x0f,0x23,0x42,0x59,0xb0,0x10,0x43,0x4a,0xb0,0x00,0x52,0x58,0x20,0xb0,0x10,0x23,0x42,0x59, -0x2d,0xb0,0x11,0x2c,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0x20,0xb8,0x04,0x00,0x63,0x8a,0x23,0x61,0xb0,0x11,0x43,0x60,0x20,0x8a,0x60,0x20,0xb0,0x11,0x23,0x42,0x23,0x2d,0xb0,0x12,0x2c,0x4b,0x54,0x58,0xb1,0x04,0x64,0x44,0x59,0x24,0xb0,0x0d,0x65,0x23,0x78,0x2d,0xb0,0x13,0x2c,0x4b,0x51,0x58,0x4b,0x53,0x58,0xb1,0x04,0x64, -0x44,0x59,0x1b,0x21,0x59,0x24,0xb0,0x13,0x65,0x23,0x78,0x2d,0xb0,0x14,0x2c,0xb1,0x00,0x12,0x43,0x55,0x58,0xb1,0x12,0x12,0x43,0xb0,0x01,0x61,0x42,0xb0,0x11,0x2b,0x59,0xb0,0x00,0x43,0xb0,0x02,0x25,0x42,0xb1,0x0f,0x02,0x25,0x42,0xb1,0x10,0x02,0x25,0x42,0xb0,0x01,0x16,0x23,0x20,0xb0,0x03,0x25,0x50,0x58,0xb1,0x01,0x00,0x43, -0x60,0xb0,0x04,0x25,0x42,0x8a,0x8a,0x20,0x8a,0x23,0x61,0xb0,0x10,0x2a,0x21,0x23,0xb0,0x01,0x61,0x20,0x8a,0x23,0x61,0xb0,0x10,0x2a,0x21,0x1b,0xb1,0x01,0x00,0x43,0x60,0xb0,0x02,0x25,0x42,0xb0,0x02,0x25,0x61,0xb0,0x10,0x2a,0x21,0x59,0xb0,0x0f,0x43,0x47,0xb0,0x10,0x43,0x47,0x60,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0, -0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb1,0x00,0x00,0x13,0x23,0x44,0xb0,0x01,0x43,0xb0,0x00,0x3e,0xb2,0x01,0x01,0x01,0x43,0x60,0x42,0x2d,0xb0,0x15,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42, -0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60,0x42,0x20,0x60,0xb7,0x18,0x18,0x01,0x00,0x11,0x00,0x13,0x00,0x42,0x42,0x42,0x8a,0x60,0x20,0xb0,0x14,0x23,0x42,0xb0,0x01,0x61,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x16,0x2c,0xb1,0x00,0x15,0x2b,0x2d,0xb0,0x17,0x2c,0xb1,0x01,0x15,0x2b,0x2d, -0xb0,0x18,0x2c,0xb1,0x02,0x15,0x2b,0x2d,0xb0,0x19,0x2c,0xb1,0x03,0x15,0x2b,0x2d,0xb0,0x1a,0x2c,0xb1,0x04,0x15,0x2b,0x2d,0xb0,0x1b,0x2c,0xb1,0x05,0x15,0x2b,0x2d,0xb0,0x1c,0x2c,0xb1,0x06,0x15,0x2b,0x2d,0xb0,0x1d,0x2c,0xb1,0x07,0x15,0x2b,0x2d,0xb0,0x1e,0x2c,0xb1,0x08,0x15,0x2b,0x2d,0xb0,0x1f,0x2c,0xb1,0x09,0x15,0x2b,0x2d, -0xb0,0x2b,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x06,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x5d,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2c,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x16,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x71,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2d,0x2c,0x23,0x20,0xb0, -0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x26,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x72,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x20,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42,0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60,0x42,0x20,0x60,0xb0,0x01,0x61,0xb5,0x18,0x18,0x01,0x00,0x11, -0x00,0x42,0x42,0x8a,0x60,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x21,0x2c,0xb1,0x00,0x20,0x2b,0x2d,0xb0,0x22,0x2c,0xb1,0x01,0x20,0x2b,0x2d,0xb0,0x23,0x2c,0xb1,0x02,0x20,0x2b,0x2d,0xb0,0x24,0x2c,0xb1,0x03,0x20,0x2b,0x2d,0xb0,0x25,0x2c,0xb1,0x04,0x20,0x2b,0x2d,0xb0,0x26,0x2c,0xb1,0x05,0x20,0x2b,0x2d, -0xb0,0x27,0x2c,0xb1,0x06,0x20,0x2b,0x2d,0xb0,0x28,0x2c,0xb1,0x07,0x20,0x2b,0x2d,0xb0,0x29,0x2c,0xb1,0x08,0x20,0x2b,0x2d,0xb0,0x2a,0x2c,0xb1,0x09,0x20,0x2b,0x2d,0xb0,0x2e,0x2c,0x20,0x3c,0xb0,0x01,0x60,0x2d,0xb0,0x2f,0x2c,0x20,0x60,0xb0,0x18,0x60,0x20,0x43,0x23,0xb0,0x01,0x60,0x43,0xb0,0x02,0x25,0x61,0xb0,0x01,0x60,0xb0, -0x2e,0x2a,0x21,0x2d,0xb0,0x30,0x2c,0xb0,0x2f,0x2b,0xb0,0x2f,0x2a,0x2d,0xb0,0x31,0x2c,0x20,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x61,0x38,0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62, -0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x32,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0,0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x33,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02, -0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0,0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x34,0x2c,0x20,0x35,0xb0,0x01,0x60,0x2d,0xb0,0x35,0x2c,0x00,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x45,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01, -0x63,0xb0,0x01,0x2b,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0xb0,0x01,0x2b,0xb0,0x00,0x16,0xb4,0x00,0x00,0x00,0x00,0x00,0x44,0x3e,0x23,0x38,0xb1,0x34,0x01,0x15,0x2a,0x21,0x2d,0xb0,0x36,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62, -0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb0,0x00,0x43,0x61,0x38,0x2d,0xb0,0x37,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x38,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb0,0x00,0x43,0x61,0xb0,0x01,0x43, -0x63,0x38,0x2d,0xb0,0x39,0x2c,0xb1,0x02,0x00,0x16,0x25,0x20,0x2e,0x20,0x47,0xb0,0x00,0x23,0x42,0xb0,0x02,0x25,0x49,0x8a,0x8a,0x47,0x23,0x47,0x23,0x61,0x20,0x58,0x62,0x1b,0x21,0x59,0xb0,0x01,0x23,0x42,0xb2,0x38,0x01,0x01,0x15,0x14,0x2a,0x2d,0xb0,0x3a,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25, -0x47,0x23,0x47,0x23,0x61,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x65,0x8a,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x3b,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58, -0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3,0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0xb0,0x0a,0x43,0x20,0x8a,0x23,0x47,0x23,0x47,0x23,0x61,0x23,0x46,0x60,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01,0x2b,0x20,0x8a,0x8a,0x61,0x20, -0xb0,0x04,0x43,0x60,0x64,0x23,0xb0,0x05,0x43,0x61,0x64,0x50,0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x0a,0x43,0x46,0xb0,0x02,0x25,0xb0,0x0a, -0x43,0x47,0x23,0x47,0x23,0x61,0x60,0x20,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x06,0x43,0x60,0xb0,0x01,0x2b,0xb0,0x05,0x25,0x61,0xb0,0x05,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63, -0xb0,0x04,0x26,0x61,0x20,0xb0,0x04,0x25,0x60,0x64,0x23,0xb0,0x03,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x59,0x2d,0xb0,0x3c,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0x20,0x20,0xb0,0x05,0x26,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x23,0x3c,0x38,0x2d,0xb0,0x3d, -0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x23,0x42,0x20,0x20,0x20,0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x2d,0xb0,0x3e,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x03,0x25,0xb0,0x02,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x02,0x25,0x47, -0x23,0x47,0x23,0x61,0x20,0xb0,0x05,0x25,0xb0,0x04,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x06,0x25,0xb0,0x05,0x25,0x49,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x20,0x58,0x62,0x1b,0x21,0x59,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x2e,0x23,0x20, -0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x2d,0xb0,0x3f,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x43,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x40,0x2c,0x23,0x20,0x2e, -0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x41,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x42,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25, -0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x43,0x2c,0xb0,0x3a,0x2b,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20, -0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x44,0x2c,0xb0,0x3b,0x2b,0x8a,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x45,0x2c,0xb0,0x00, -0x16,0xb0,0x04,0x25,0xb0,0x04,0x26,0x20,0x20,0x20,0x46,0x23,0x47,0x61,0xb0,0x0c,0x23,0x42,0x2e,0x47,0x23,0x47,0x23,0x61,0xb0,0x0b,0x43,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x46,0x2c,0xb1,0x0a,0x04,0x25,0x42,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23, -0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3,0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0x47,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01, -0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x04,0x43,0x60,0x64,0x23,0xb0,0x05,0x43,0x61,0x64,0x50,0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0xb0,0x02,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0x20, -0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x21,0x59,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x47,0x2c,0xb1,0x00,0x3a,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x48,0x2c,0xb1,0x00,0x3b,0x2b,0x21,0x23,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x49, -0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4a,0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4b,0x2c,0xb1,0x00,0x01,0x14,0x13,0xb0,0x37,0x2a,0x2d,0xb0,0x4c,0x2c,0xb0,0x39,0x2a, -0x2d,0xb0,0x4d,0x2c,0xb0,0x00,0x16,0x45,0x23,0x20,0x2e,0x20,0x46,0x8a,0x23,0x61,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x4e,0x2c,0xb0,0x0a,0x23,0x42,0xb0,0x4d,0x2b,0x2d,0xb0,0x4f,0x2c,0xb2,0x00,0x00,0x46,0x2b,0x2d,0xb0,0x50,0x2c,0xb2,0x00,0x01,0x46,0x2b,0x2d,0xb0,0x51,0x2c,0xb2,0x01,0x00,0x46,0x2b,0x2d,0xb0,0x52,0x2c, -0xb2,0x01,0x01,0x46,0x2b,0x2d,0xb0,0x53,0x2c,0xb2,0x00,0x00,0x47,0x2b,0x2d,0xb0,0x54,0x2c,0xb2,0x00,0x01,0x47,0x2b,0x2d,0xb0,0x55,0x2c,0xb2,0x01,0x00,0x47,0x2b,0x2d,0xb0,0x56,0x2c,0xb2,0x01,0x01,0x47,0x2b,0x2d,0xb0,0x57,0x2c,0xb3,0x00,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x58,0x2c,0xb3,0x00,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x59, -0x2c,0xb3,0x01,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x5a,0x2c,0xb3,0x01,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x5b,0x2c,0xb3,0x00,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5c,0x2c,0xb3,0x00,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5d,0x2c,0xb3,0x01,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5e,0x2c,0xb3,0x01,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5f,0x2c,0xb2,0x00,0x00, -0x45,0x2b,0x2d,0xb0,0x60,0x2c,0xb2,0x00,0x01,0x45,0x2b,0x2d,0xb0,0x61,0x2c,0xb2,0x01,0x00,0x45,0x2b,0x2d,0xb0,0x62,0x2c,0xb2,0x01,0x01,0x45,0x2b,0x2d,0xb0,0x63,0x2c,0xb2,0x00,0x00,0x48,0x2b,0x2d,0xb0,0x64,0x2c,0xb2,0x00,0x01,0x48,0x2b,0x2d,0xb0,0x65,0x2c,0xb2,0x01,0x00,0x48,0x2b,0x2d,0xb0,0x66,0x2c,0xb2,0x01,0x01,0x48, -0x2b,0x2d,0xb0,0x67,0x2c,0xb3,0x00,0x00,0x00,0x44,0x2b,0x2d,0xb0,0x68,0x2c,0xb3,0x00,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x69,0x2c,0xb3,0x01,0x00,0x00,0x44,0x2b,0x2d,0xb0,0x6a,0x2c,0xb3,0x01,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x6b,0x2c,0xb3,0x00,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6c,0x2c,0xb3,0x00,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6d, -0x2c,0xb3,0x01,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6e,0x2c,0xb3,0x01,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6f,0x2c,0xb1,0x00,0x3c,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x70,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x71,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x72,0x2c,0xb0,0x00,0x16,0xb1,0x00,0x3c,0x2b, -0xb0,0x42,0x2b,0x2d,0xb0,0x73,0x2c,0xb1,0x01,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x74,0x2c,0xb1,0x01,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x75,0x2c,0xb0,0x00,0x16,0xb1,0x01,0x3c,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x76,0x2c,0xb1,0x00,0x3d,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x77,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x40,0x2b, -0x2d,0xb0,0x78,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x79,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7a,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7b,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x7c,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7d,0x2c,0xb1,0x00,0x3e,0x2b,0x2e, -0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x7e,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7f,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x80,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x81,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x82,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x83,0x2c, -0xb1,0x01,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x84,0x2c,0xb1,0x00,0x3f,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x85,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x86,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x87,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x88,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x40, -0x2b,0x2d,0xb0,0x89,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x8a,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x8b,0x2c,0xb2,0x0b,0x00,0x03,0x45,0x50,0x58,0xb0,0x06,0x1b,0xb2,0x04,0x02,0x03,0x45,0x58,0x23,0x21,0x1b,0x21,0x59,0x59,0x42,0x2b,0xb0,0x08,0x65,0xb0,0x03,0x24,0x50,0x78,0xb1,0x05,0x01,0x15,0x45, -0x58,0x30,0x59,0x2d,0x00,0x4b,0xb8,0x00,0xc8,0x52,0x58,0xb1,0x01,0x01,0x8e,0x59,0xb0,0x01,0xb9,0x08,0x00,0x08,0x00,0x63,0x70,0xb1,0x00,0x07,0x42,0xb2,0x19,0x01,0x00,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x0d,0x09,0x01,0x0a,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x16,0x06,0x01,0x0a,0x2a,0xb1,0x00,0x08,0x42,0xba,0x03,0x80,0x00,0x01,0x00, -0x0b,0x2a,0xb1,0x00,0x09,0x42,0xba,0x00,0x80,0x00,0x01,0x00,0x0b,0x2a,0xb9,0x00,0x03,0x00,0x00,0x44,0xb1,0x24,0x01,0x88,0x51,0x58,0xb0,0x40,0x88,0x58,0xb9,0x00,0x03,0x00,0x64,0x44,0xb1,0x28,0x01,0x88,0x51,0x58,0xb8,0x08,0x00,0x88,0x58,0xb9,0x00,0x03,0x00,0x00,0x44,0x59,0x1b,0xb1,0x27,0x01,0x88,0x51,0x58,0xba,0x08,0x80, -0x00,0x01,0x04,0x40,0x88,0x63,0x54,0x58,0xb9,0x00,0x03,0x00,0x00,0x44,0x59,0x59,0x59,0x59,0x59,0xb3,0x10,0x06,0x01,0x0e,0x2a,0xb8,0x01,0xff,0x85,0xb0,0x04,0x8d,0xb1,0x02,0x00,0x44,0xb3,0x05,0x64,0x06,0x00,0x44,0x44,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x03,0xd0,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x50,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x05,0x00,0x00, +0x00,0x28,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x2e,0x00,0x00, +0x00,0x2e,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x35,0x00,0x00, +0x00,0x10,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x15,0x00,0x00, +0x00,0x3e,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x19,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x43,0x00,0x00, +0x00,0x43,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x45,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x48,0x00,0x00, +0x00,0x20,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x25,0x00,0x00, +0x00,0x4e,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x26,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x27,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x51,0x00,0x00,0x00,0x29,0x00,0x00,0x00,0x52,0x00,0x00,0x00,0x52,0x00,0x00,0x00,0x2a,0x00,0x00,0x00,0x53,0x00,0x00, +0x00,0x53,0x00,0x00,0x00,0x2b,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x55,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x56,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x57,0x00,0x00,0x00,0x2f,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x58,0x00,0x00, +0x00,0x30,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x5a,0x00,0x00,0x00,0x32,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x5b,0x00,0x00,0x00,0x33,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x5d,0x00,0x00,0x00,0x34,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x5e,0x00,0x00,0x00,0x35,0x00,0x00, +0x00,0x61,0x00,0x00,0x00,0x61,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x62,0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x63,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x39,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x65,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,0x66,0x00,0x00, +0x00,0x66,0x00,0x00,0x00,0x3b,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x67,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x68,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x69,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,0x6a,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x6b,0x00,0x00,0x00,0x6b,0x00,0x00, +0x00,0x40,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x6d,0x00,0x00,0x00,0x42,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x6e,0x00,0x00,0x00,0x43,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x6f,0x00,0x00,0x00,0x44,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x45,0x00,0x00, +0x00,0x71,0x00,0x00,0x00,0x71,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x72,0x00,0x00,0x00,0x47,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x73,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x75,0x00,0x00,0x00,0x49,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x77,0x00,0x00, +0x00,0x77,0x00,0x00,0x00,0x4b,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x4c,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x79,0x00,0x00,0x00,0x4d,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x7a,0x00,0x00,0x00,0x4e,0x00,0x00,0x00,0x7b,0x00,0x00,0x00,0x7b,0x00,0x00,0x00,0x4f,0x00,0x00,0x00,0x7d,0x00,0x00,0x00,0x7d,0x00,0x00, +0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x25,0x40,0x22,0x00,0x01,0x00,0x02,0x01,0x02,0x63,0x04,0x01,0x00,0x00,0x03,0x5f,0x00,0x03,0x03,0x13,0x00,0x4e,0x02,0x00,0x1e,0x1b,0x16,0x13,0x0a,0x07,0x00,0x0f,0x02,0x0f,0x05,0x07,0x16,0x2b,0x01,0x21,0x22,0x06,0x07,0x11,0x14, +0x16,0x17,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x71,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x34,0x7c,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x02,0xc3,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01, +0xd0,0x25,0x34,0x59,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x60,0x00,0x06,0x00,0x00,0xff,0xba,0x02,0x80,0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x39,0x00,0x42,0x00,0x4b,0x00,0x54,0x40,0x51,0x39,0x30,0x2f,0x26,0x0d,0x0c,0x03,0x02,0x08,0x02,0x04,0x01,0x4c,0x08,0x0c,0x02,0x04,0x0b,0x01,0x02,0x03,0x04, +0x02,0x69,0x09,0x01,0x05,0x05,0x01,0x61,0x07,0x01,0x01,0x01,0x13,0x4d,0x0d,0x0a,0x02,0x03,0x03,0x00,0x61,0x06,0x01,0x00,0x00,0x11,0x00,0x4e,0x44,0x43,0x1e,0x1d,0x48,0x47,0x43,0x4b,0x44,0x4b,0x41,0x40,0x3d,0x3c,0x35,0x34,0x2b,0x2a,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x14,0x19,0x17,0x0e,0x07,0x1a,0x2b,0x13,0x14,0x07,0x11, +0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x03,0x34,0x26,0x22,0x06,0x14,0x16,0x32,0x36,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13, +0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xf0,0x48,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x32,0x2a,0x38,0x28,0x28,0x38,0x2a,0x46,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x01,0xdc,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x02,0x8a,0x4c,0x22,0xfe, +0x86,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0xfd,0x76,0x1e,0x28,0x28,0x3a,0x28,0x28,0x02,0x30,0x28,0x3a,0x28,0x28,0x3a,0x28,0xfe,0x5c,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x6e,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28, +0x28,0x3a,0x28,0x00,0x00,0x05,0x00,0x00,0xff,0x6a,0x03,0xe8,0x03,0x52,0x00,0x1f,0x00,0x22,0x00,0x25,0x00,0x33,0x00,0x3c,0x00,0x70,0x40,0x6d,0x23,0x01,0x00,0x06,0x1d,0x01,0x09,0x00,0x27,0x20,0x02,0x07,0x05,0x03,0x4c,0x00,0x03,0x00,0x06,0x00,0x03,0x06,0x67,0x0c,0x01,0x00,0x00,0x09,0x05,0x00,0x09,0x67,0x00,0x05,0x00,0x07, +0x04,0x05,0x07,0x67,0x00,0x04,0x00,0x0a,0x08,0x04,0x0a,0x67,0x00,0x08,0x00,0x02,0x0b,0x08,0x02,0x67,0x0d,0x01,0x0b,0x01,0x01,0x0b,0x57,0x0d,0x01,0x0b,0x0b,0x01,0x5f,0x00,0x01,0x0b,0x01,0x4f,0x34,0x34,0x01,0x00,0x34,0x3c,0x34,0x3c,0x3b,0x39,0x36,0x35,0x30,0x2f,0x2e,0x2c,0x29,0x28,0x25,0x24,0x22,0x21,0x1a,0x17,0x0e,0x0c, +0x09,0x06,0x00,0x1f,0x01,0x1e,0x0e,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x35,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x3f,0x01,0x3e,0x01,0x3b,0x01,0x32,0x16,0x17,0x15,0x36,0x33,0x0f,0x01,0x33,0x01,0x07,0x33,0x17,0x37,0x35,0x23,0x15,0x14,0x06,0x07,0x23,0x11,0x21,0x35,0x34,0x36,0x01,0x11, +0x23,0x15,0x14,0x06,0x27,0x23,0x11,0x03,0xb2,0x17,0x1e,0x01,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0xfe,0xd1,0x17,0x1e,0x01,0x16,0x10,0xe4,0x0f,0x36,0x16,0xe8,0x17,0x1e,0x01,0x26,0x21,0x47,0xa7,0xa7,0xfe,0x9b,0xa7,0xa7,0x6d,0xb0,0xd6,0x1e,0x17,0xe9,0x01,0x1e,0x16,0x02,0x26,0xd7,0x1e,0x17,0xe8,0x02,0x7c,0x20,0x16,0xfd,0x5a, +0x17,0x1e,0x01,0x20,0x16,0xa0,0x20,0x16,0x01,0x77,0x16,0x36,0x0f,0xe4,0x10,0x16,0x20,0x16,0xb7,0x17,0x77,0xa7,0x01,0x7d,0xa7,0xc2,0xb0,0xe9,0xe9,0x16,0x1e,0x01,0xfe,0x9b,0x8f,0x16,0x36,0xfe,0x4e,0x02,0x83,0xe8,0x16,0x20,0x01,0xfe,0x9a,0x00,0x00,0x04,0xff,0xff,0xff,0xb1,0x04,0x2f,0x03,0x0b,0x00,0x08,0x00,0x0f,0x00,0x1f, +0x00,0x2f,0x00,0x52,0x40,0x4f,0x1d,0x14,0x02,0x01,0x03,0x0f,0x01,0x00,0x01,0x0e,0x0d,0x0c,0x09,0x04,0x02,0x00,0x1c,0x15,0x02,0x04,0x02,0x04,0x4c,0x00,0x02,0x00,0x04,0x00,0x02,0x04,0x80,0x00,0x01,0x00,0x00,0x02,0x01,0x00,0x69,0x07,0x01,0x03,0x03,0x06,0x5f,0x00,0x06,0x06,0x13,0x4d,0x00,0x04,0x04,0x05,0x5f,0x00,0x05,0x05, +0x11,0x05,0x4e,0x11,0x10,0x2e,0x2b,0x26,0x23,0x19,0x17,0x10,0x1f,0x11,0x1f,0x13,0x13,0x12,0x08,0x07,0x19,0x2b,0x01,0x14,0x0e,0x01,0x26,0x34,0x36,0x1e,0x01,0x01,0x15,0x21,0x35,0x37,0x17,0x01,0x25,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x37,0x21,0x32,0x36,0x27,0x11,0x34,0x26,0x17,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x37,0x11, +0x34,0x36,0x37,0x21,0x32,0x16,0x01,0x65,0x3e,0x5a,0x3e,0x3e,0x5a,0x3e,0x02,0x3c,0xfc,0xee,0xb2,0x5a,0x01,0x1d,0x01,0x1e,0xfc,0x83,0x07,0x0a,0x01,0x0c,0x06,0x03,0x7d,0x07,0x0c,0x01,0x0a,0x51,0x34,0x25,0xfc,0x83,0x24,0x36,0x01,0x34,0x25,0x03,0x7d,0x25,0x34,0x02,0x11,0x2d,0x3e,0x02,0x42,0x56,0x42,0x04,0x3a,0xfe,0xfa,0xfa, +0x6b,0xb3,0x59,0x01,0x1d,0xa1,0x0a,0x08,0xfd,0x5a,0x07,0x0c,0x01,0x0a,0x08,0x02,0xa6,0x08,0x0a,0x12,0xfd,0x5a,0x25,0x34,0x01,0x36,0x24,0x02,0xa6,0x25,0x34,0x01,0x36,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xba,0x00,0xf0,0x03,0x02,0x00,0x13,0x00,0x1c,0x00,0x25,0x00,0x39,0x40,0x36,0x13,0x0a,0x09,0x00,0x04,0x05,0x02,0x01, +0x4c,0x00,0x02,0x00,0x05,0x04,0x02,0x05,0x69,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x13,0x4d,0x06,0x01,0x04,0x04,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x1e,0x1d,0x22,0x21,0x1d,0x25,0x1e,0x25,0x13,0x17,0x19,0x14,0x07,0x07,0x1a,0x2b,0x37,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x11,0x26,0x35,0x34,0x36,0x32,0x16, +0x15,0x14,0x07,0x27,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0xa8,0x48,0x46,0x64,0x46,0x48,0x48,0x46,0x64,0x46,0x48,0x74,0x28,0x38,0x2a,0x2a,0x38,0x28,0x44,0x1c,0x2a,0x2a,0x38,0x28,0x28,0xa2,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x01,0x7a,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c, +0x22,0x6e,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x46,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x03,0xff,0xff,0xff,0x6a,0x04,0x78,0x03,0x52,0x00,0x03,0x00,0x0c,0x00,0x26,0x00,0x38,0x40,0x35,0x00,0x08,0x00,0x03,0x04,0x08,0x03,0x67,0x07,0x01,0x04,0x00,0x01,0x02,0x04,0x01,0x67,0x00,0x02,0x00,0x05,0x00,0x02,0x05,0x67,0x00,0x00,0x06, +0x06,0x00,0x57,0x00,0x00,0x00,0x06,0x60,0x00,0x06,0x00,0x06,0x50,0x33,0x25,0x33,0x26,0x21,0x11,0x11,0x11,0x10,0x09,0x07,0x1f,0x2b,0x17,0x21,0x11,0x29,0x02,0x11,0x21,0x15,0x33,0x32,0x16,0x15,0x01,0x11,0x14,0x06,0x23,0x21,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x37,0x11,0x34,0x36,0x33,0x21,0x35,0x34,0x36,0x33,0x21,0x32,0x16, +0x8f,0x01,0xac,0xfe,0x54,0x02,0x3b,0x01,0x1e,0xfe,0x53,0x36,0x25,0x34,0x01,0xad,0x34,0x25,0xfe,0xac,0x34,0x25,0xfd,0xe8,0x24,0x36,0x01,0x34,0x25,0x01,0x54,0x34,0x25,0x02,0x18,0x24,0x36,0x07,0x01,0x1e,0x01,0xac,0x8f,0x34,0x25,0x01,0x1e,0xfd,0xe8,0x25,0x34,0xc5,0x25,0x34,0x34,0x25,0x02,0x18,0x25,0x34,0xc5,0x25,0x34,0x34, +0x00,0x01,0xff,0xff,0xff,0xb1,0x03,0xe8,0x00,0xcf,0x00,0x0f,0x00,0x13,0x40,0x10,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x00,0x11,0x00,0x4e,0x35,0x33,0x02,0x07,0x18,0x2b,0x25,0x15,0x14,0x06,0x07,0x21,0x22,0x26,0x37,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0xe8,0x34,0x25,0xfc,0xca,0x24,0x36,0x01,0x34,0x25,0x03,0x36,0x25,0x34, +0x76,0x6b,0x25,0x34,0x01,0x36,0x24,0x6b,0x25,0x34,0x34,0x00,0x00,0x03,0x00,0x00,0xff,0x6a,0x03,0xa1,0x03,0x0b,0x00,0x03,0x00,0x07,0x00,0x1f,0x00,0x1f,0x40,0x1c,0x07,0x06,0x05,0x03,0x02,0x01,0x00,0x07,0x00,0x01,0x01,0x4c,0x00,0x00,0x00,0x01,0x61,0x00,0x01,0x01,0x13,0x00,0x4e,0x1b,0x1e,0x02,0x07,0x18,0x2b,0x05,0x25,0x11, +0x05,0x27,0x2d,0x01,0x0d,0x01,0x11,0x14,0x06,0x07,0x05,0x06,0x22,0x27,0x25,0x2e,0x01,0x35,0x11,0x34,0x36,0x37,0x25,0x36,0x32,0x17,0x05,0x1e,0x01,0x01,0xf4,0x01,0x65,0xfe,0x9b,0x24,0x01,0x86,0xfe,0x7a,0xfe,0x7b,0x03,0x56,0x14,0x12,0xfe,0x77,0x0f,0x26,0x0f,0xfe,0x77,0x11,0x14,0x1a,0x15,0x01,0x89,0x0c,0x18,0x0d,0x01,0x89, +0x15,0x1a,0x3b,0xc3,0x01,0x63,0x82,0x3f,0x8d,0x8e,0x8e,0x01,0xfe,0x54,0x14,0x22,0x09,0xd6,0x09,0x09,0xd6,0x0a,0x20,0x15,0x01,0xac,0x17,0x24,0x08,0x8f,0x05,0x05,0x8f,0x08,0x24,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x44,0x02,0x80,0x00,0x13,0x00,0x31,0x40,0x2e,0x00,0x05,0x00,0x02,0x05,0x59,0x04,0x06,0x02,0x00,0x03,0x01, +0x01,0x02,0x00,0x01,0x67,0x00,0x05,0x05,0x02,0x61,0x00,0x02,0x05,0x02,0x51,0x01,0x00,0x11,0x10,0x0e,0x0c,0x0b,0x09,0x07,0x06,0x04,0x02,0x00,0x13,0x01,0x13,0x07,0x07,0x16,0x2b,0x01,0x32,0x14,0x2b,0x01,0x15,0x14,0x22,0x3d,0x01,0x23,0x22,0x34,0x3b,0x01,0x35,0x34,0x32,0x1d,0x01,0x02,0x26,0x1e,0x1e,0xd2,0x64,0xd2,0x1e,0x1e, +0xd2,0x64,0x01,0x90,0x64,0xd2,0x1e,0x1e,0xd2,0x64,0xd2,0x1e,0x1e,0xd2,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x44,0x01,0x90,0x00,0x07,0x00,0x20,0x40,0x1d,0x02,0x01,0x00,0x01,0x01,0x00,0x57,0x02,0x01,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x01,0x00,0x05,0x02,0x00,0x07,0x01,0x06,0x03,0x07,0x16,0x2b,0x01,0x32, +0x14,0x23,0x21,0x22,0x34,0x33,0x02,0x26,0x1e,0x1e,0xfd,0xf8,0x1e,0x1e,0x01,0x90,0x64,0x64,0x00,0x00,0x00,0x01,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x13,0x40,0x10,0x00,0x01,0x01,0x13,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x15,0x13,0x02,0x07,0x18,0x2b,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e, +0x01,0x03,0x59,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4,0xba,0x7e,0x01,0x5e,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x3c,0x01,0xed,0x00,0x0e,0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01, +0x00,0x51,0x35,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x26,0x34,0x36,0x33,0x21,0x32,0x16,0x02,0x3b,0x0a,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x01,0xc9,0x0e,0x0b,0xfa,0x0b,0x0b,0xfa,0x0b,0x1c,0x16,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa0,0x03,0x0b,0x00,0x2d, +0x00,0x42,0x00,0x48,0x40,0x45,0x3b,0x01,0x04,0x06,0x25,0x01,0x05,0x04,0x02,0x4c,0x00,0x07,0x01,0x02,0x01,0x07,0x02,0x80,0x00,0x06,0x02,0x04,0x02,0x06,0x04,0x80,0x00,0x04,0x05,0x02,0x04,0x05,0x7e,0x00,0x05,0x03,0x02,0x05,0x03,0x7e,0x00,0x03,0x00,0x00,0x03,0x00,0x64,0x00,0x02,0x02,0x01,0x5f,0x00,0x01,0x01,0x13,0x02,0x4e, +0x14,0x17,0x15,0x27,0x35,0x39,0x35,0x33,0x08,0x07,0x1e,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x17,0x1e,0x01,0x0f,0x01,0x06,0x23,0x27,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x3d,0x01,0x34,0x3f,0x01,0x36,0x33,0x32,0x17,0x16,0x13,0x01,0x06,0x22,0x2f,0x01, +0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x14,0x03,0x12,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x23,0x1e,0x09,0x03,0x07,0x1b,0x06,0x07,0x05,0x0d,0x0c,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x05,0x24,0x06,0x07,0x03,0x04,0x0b,0x81,0xfe,0x39,0x0d,0x24,0x0e,0xf0,0x0e, +0x0e,0x3d,0x0e,0x24,0x0e,0x93,0x01,0x69,0x0d,0x24,0x0e,0x3e,0x0d,0x01,0x4b,0xb1,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x5e,0x01,0x0e,0x04,0x13,0x06,0x1c,0x05,0x01,0x03,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x8d,0x08,0x05,0x23,0x06,0x02,0x04,0x01,0x05,0xfe,0x3a,0x0e,0x0e,0xf0,0x0d,0x24,0x0e,0x3e,0x0d,0x0d,0x93,0x01, +0x69,0x0d,0x0d,0x3d,0x0e,0x24,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0xb1,0x03,0x12,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3b,0x00,0x43,0x00,0x67,0x00,0x5d,0x40,0x5a,0x57,0x45,0x02,0x06,0x08,0x29,0x21,0x19,0x11,0x09,0x01,0x06,0x00,0x01,0x02,0x4c,0x00,0x09,0x0e,0x08,0x0e,0x09,0x08,0x80,0x0f,0x0d,0x02,0x08,0x0c,0x0a, +0x02,0x06,0x01,0x08,0x06,0x68,0x05,0x03,0x02,0x01,0x04,0x02,0x02,0x00,0x07,0x01,0x00,0x69,0x00,0x0e,0x0e,0x13,0x4d,0x00,0x07,0x07,0x0b,0x5f,0x00,0x0b,0x0b,0x11,0x0b,0x4e,0x65,0x64,0x61,0x5e,0x5b,0x59,0x53,0x52,0x4f,0x4c,0x49,0x47,0x41,0x3f,0x14,0x24,0x14,0x26,0x26,0x26,0x26,0x26,0x23,0x10,0x07,0x1f,0x2b,0x01,0x11,0x14, +0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x13,0x11,0x21,0x11,0x14,0x1e,0x01,0x33,0x21,0x32,0x3e,0x01,0x01,0x33,0x27,0x26,0x27,0x23,0x06, +0x07,0x05,0x15,0x14,0x06,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x37,0x3e,0x01,0x37,0x33,0x32,0x16,0x1f,0x01,0x33,0x32,0x16,0x01,0x1e,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8f,0x0a,0x08,0x24,0x08,0x0a,0x0a,0x08,0x24,0x08,0x0a,0x8e,0x0a,0x07,0x24, +0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x48,0xfe,0x0c,0x08,0x08,0x02,0x01,0xd0,0x02,0x08,0x08,0xfe,0x89,0xfa,0x1b,0x04,0x05,0xb1,0x06,0x04,0x01,0xeb,0x0a,0x08,0x36,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x35,0x08,0x0a,0x0a,0x08,0xac,0x27,0x09,0x2c,0x16,0xb2,0x17,0x2a,0x09,0x27,0xad,0x08,0x0a,0x01,0xb7,0xfe,0xbf,0x08,0x0a,0x0a, +0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0x08,0xfe,0xbf,0x08,0x0a,0x0a,0x08,0x01,0x41,0x08,0x0a,0x0a,0xfe,0x64,0x02,0x11,0xfd,0xef,0x0c,0x14,0x0a,0x0a,0x14,0x02,0x65,0x41,0x05,0x01,0x01,0x05,0x53,0x24,0x08,0x0a,0xfd,0xef,0x2e,0x44,0x42,0x2e,0x02,0x13,0x0a,0x08,0x24,0x08, +0x0a,0x5d,0x15,0x1c,0x01,0x1e,0x14,0x5d,0x0a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0x9c,0x03,0xac,0x03,0x20,0x00,0x2a,0x00,0x34,0x40,0x09,0x20,0x1e,0x16,0x12,0x04,0x00,0x01,0x01,0x4c,0x4b,0xb0,0x18,0x50,0x58,0x40,0x0b,0x00,0x01,0x01,0x10,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x1b,0x40,0x0b,0x00,0x00,0x00,0x01,0x61,0x00, +0x01,0x01,0x10,0x00,0x4e,0x59,0xb5,0x1b,0x1a,0x13,0x02,0x07,0x17,0x2b,0x25,0x16,0x1d,0x01,0x21,0x35,0x34,0x37,0x3e,0x01,0x35,0x34,0x26,0x27,0x2e,0x03,0x27,0x34,0x36,0x3f,0x01,0x26,0x27,0x26,0x36,0x32,0x16,0x0f,0x01,0x16,0x15,0x0e,0x03,0x07,0x0e,0x01,0x15,0x14,0x16,0x02,0xe0,0xcc,0xfc,0x54,0xcc,0x5e,0x44,0x2c,0x0a,0x02, +0x0e,0x0e,0x0e,0x02,0x0a,0x04,0x04,0x08,0x04,0x04,0x5a,0xe0,0x5c,0x06,0x0c,0x12,0x02,0x0e,0x0e,0x0e,0x02,0x08,0x2e,0x46,0x80,0x48,0x32,0x6a,0x6a,0x32,0x48,0x22,0x46,0x3c,0x16,0x36,0x2e,0x0c,0x0c,0x04,0x1e,0x1c,0x10,0x14,0x02,0x04,0x32,0x26,0x36,0x74,0x74,0x36,0x58,0x08,0x22,0x1c,0x1e,0x04,0x0c,0x0c,0x30,0x34,0x16,0x3c, +0x46,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xb6,0x03,0xe8,0x03,0x08,0x00,0x18,0x00,0x20,0x00,0x2d,0x00,0x94,0xb5,0x25,0x01,0x09,0x0b,0x01,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x30,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x72,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07, +0x07,0x02,0x5f,0x00,0x02,0x02,0x13,0x4d,0x0a,0x01,0x08,0x08,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x1b,0x40,0x31,0x0d,0x01,0x0b,0x08,0x09,0x08,0x0b,0x09,0x80,0x0c,0x01,0x05,0x00,0x01,0x05,0x57,0x06,0x03,0x02,0x01,0x04,0x01,0x00,0x08,0x01,0x00,0x67,0x00,0x07,0x07,0x02,0x5f,0x00,0x02,0x02,0x13,0x4d,0x0a,0x01,0x08,0x08, +0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x59,0x40,0x1e,0x21,0x21,0x00,0x00,0x21,0x2d,0x21,0x2d,0x2c,0x2b,0x29,0x26,0x23,0x22,0x20,0x1d,0x1b,0x1a,0x00,0x18,0x00,0x18,0x12,0x24,0x35,0x22,0x11,0x0e,0x07,0x1b,0x2b,0x01,0x15,0x21,0x13,0x36,0x3b,0x01,0x36,0x3f,0x01,0x3e,0x01,0x3b,0x01,0x32,0x16,0x17,0x16,0x17,0x33,0x32,0x17, +0x13,0x21,0x35,0x03,0x07,0x21,0x27,0x26,0x2b,0x01,0x22,0x13,0x35,0x21,0x06,0x07,0x06,0x23,0x21,0x22,0x35,0x27,0x21,0x15,0x01,0xc8,0xfe,0x38,0x0a,0x04,0x60,0xa0,0x10,0x15,0x17,0x0e,0x12,0x1c,0xde,0x1a,0x14,0x0c,0x12,0x2a,0xa0,0x60,0x04,0x0a,0xfe,0x3a,0xa4,0x1c,0x01,0x24,0x1c,0x0e,0x1c,0x98,0x1c,0x96,0x01,0xae,0x06,0x04, +0x06,0x54,0xfd,0x12,0x5a,0x0a,0x01,0xae,0x01,0x46,0x64,0x01,0x24,0x6c,0x1a,0x29,0x2d,0x1a,0x0c,0x0e,0x18,0x20,0x50,0x6c,0xfe,0xdc,0x64,0x01,0x62,0x36,0x36,0x1a,0xfd,0x8a,0x64,0x58,0x4e,0x54,0x54,0xa6,0x64,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xdc,0x01,0xcc,0x00,0x08,0x00,0x20,0x40,0x1d,0x02,0x01,0x00,0x01, +0x01,0x00,0x59,0x02,0x01,0x00,0x00,0x01,0x61,0x00,0x01,0x00,0x01,0x51,0x01,0x00,0x05,0x04,0x00,0x08,0x01,0x08,0x03,0x07,0x16,0x2b,0x13,0x32,0x16,0x14,0x06,0x22,0x26,0x34,0x36,0x6e,0x2e,0x40,0x40,0x5c,0x40,0x40,0x01,0xcc,0x40,0x5a,0x42,0x42,0x5a,0x40,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x67,0x02,0x7c,0x00,0x0d, +0x00,0x1e,0x40,0x1b,0x00,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x13,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x16,0x01,0x65,0x14,0x20,0x09,0xfa,0x0a,0x0a,0xfa,0x0b,0x1c,0x18,0x02,0x58,0xfe,0x0c,0x0e,0x16, +0x0b,0xfa,0x0b,0x1c,0x0b,0xfa,0x0b,0x16,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x41,0x02,0x7d,0x00,0x0e,0x00,0x0a,0xb7,0x00,0x00,0x00,0x76,0x14,0x01,0x07,0x17,0x2b,0x01,0x14,0x0f,0x01,0x06,0x22,0x26,0x35,0x11,0x34,0x3e,0x01,0x1f,0x01,0x16,0x01,0x41,0x0a,0xfa,0x0b,0x1c,0x16,0x16,0x1c,0x0b,0xfa,0x0a,0x01,0x5e,0x0e,0x0b,0xfa, +0x0b,0x16,0x0e,0x01,0xf4,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x00,0x00,0x01,0xff,0xff,0x00,0x00,0x02,0x3b,0x01,0xc9,0x00,0x0e,0x00,0x18,0x40,0x15,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x15,0x32,0x02,0x07,0x18,0x2b,0x25,0x14,0x06,0x27,0x21,0x22,0x2e,0x01,0x3f,0x01,0x36,0x32,0x1f,0x01, +0x16,0x02,0x3b,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x02,0x0c,0xfa,0x0a,0x1e,0x0a,0xfa,0x0a,0xab,0x0e,0x16,0x01,0x14,0x1e,0x0b,0xfa,0x0a,0x0a,0xfa,0x0b,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x5e,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x03,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00, +0x61,0x00,0x00,0x01,0x00,0x51,0x17,0x19,0x02,0x07,0x18,0x2b,0x01,0x14,0x0f,0x01,0x17,0x16,0x14,0x0f,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x37,0x01,0x36,0x32,0x1f,0x01,0x16,0x01,0x5e,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0xfe,0xfc,0x06,0x06,0x01,0x04,0x05,0x10,0x04,0x1c,0x06,0x02,0x22,0x07,0x05,0xdc,0xdb,0x06,0x0e, +0x06,0x1c,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0x1c,0x05,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x4c,0x02,0x51,0x00,0x15,0x00,0x1e,0x40,0x1b,0x0b,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x01,0x59,0x00,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x1c,0x14,0x02,0x07,0x18,0x2b,0x01,0x14,0x07,0x01, +0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x17,0x01,0x16,0x01,0x4c,0x05,0xfe,0xfb,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x10,0x04,0x01,0x05,0x05,0x01,0x3a,0x07,0x05,0xfe,0xfb,0x05,0x05,0x1c,0x06,0x0e,0x06,0xdb,0xdc,0x05,0x0e,0x06,0x1c,0x06,0x06,0xfe,0xfc,0x05,0x00, +0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x16,0x00,0x3f,0x00,0x83,0x40,0x0b,0x38,0x36,0x02,0x03,0x05,0x13,0x01,0x02,0x03,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x00,0x06,0x00,0x03,0x02,0x06,0x03,0x69,0x08,0x01,0x02,0x00,0x01,0x02,0x01,0x66,0x00,0x04, +0x04,0x00,0x61,0x07,0x01,0x00,0x00,0x12,0x04,0x4e,0x1b,0x40,0x2b,0x00,0x05,0x06,0x03,0x06,0x05,0x03,0x80,0x07,0x01,0x00,0x00,0x04,0x06,0x00,0x04,0x69,0x00,0x06,0x00,0x03,0x02,0x06,0x03,0x69,0x08,0x01,0x02,0x01,0x01,0x02,0x59,0x08,0x01,0x02,0x02,0x01,0x62,0x00,0x01,0x02,0x01,0x52,0x59,0x40,0x19,0x0a,0x09,0x01,0x00,0x27, +0x26,0x22,0x20,0x1d,0x1b,0x11,0x0e,0x09,0x16,0x0a,0x16,0x05,0x04,0x00,0x08,0x01,0x08,0x09,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x13,0x32,0x36,0x35,0x36,0x26,0x2b,0x01,0x22,0x06,0x07,0x14,0x16,0x17,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x07,0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x32,0x17,0x16,0x15, +0x14,0x07,0x06,0x0f,0x01,0x06,0x0f,0x01,0x06,0x07,0x06,0x07,0x15,0x33,0x35,0x34,0x37,0x36,0x3f,0x01,0x36,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xbc,0x1e,0x26,0x02,0x26,0x1e,0x02,0x1c,0x26,0x02,0x26,0x1c,0xa8,0x1a,0x6a,0x52,0x40,0x28,0x44,0x04,0x6e,0x10,0x10,0x4e,0x0c,0x10,0x10,0x08, +0x0c,0x16,0x0a,0x0a,0x15,0x0b,0x06,0x0e,0x04,0x6c,0x04,0x06,0x16,0x1c,0x2e,0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0xfd,0x1e,0x26,0x1c,0x1e,0x26,0x24,0x1c,0x1e,0x26,0x02,0x01,0x48,0x22,0x2c,0x4e,0x4c,0x1a,0x2a,0x68,0x04,0x04,0x1a,0x1c,0x18,0x14,0x14,0x18,0x12,0x16,0x0c,0x08,0x0f, +0x07,0x08,0x11,0x09,0x08,0x14,0x3a,0x08,0x04,0x0c,0x10,0x14,0x10,0x12,0x22,0x00,0x00,0x02,0x00,0x00,0xff,0xbd,0x03,0x4d,0x03,0x0b,0x00,0x08,0x00,0x1d,0x00,0x3a,0xb5,0x00,0x01,0x01,0x00,0x01,0x4c,0x4b,0xb0,0x29,0x50,0x58,0x40,0x10,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x13,0x4d,0x00,0x01,0x01,0x11,0x01,0x4e,0x1b,0x40, +0x10,0x00,0x01,0x00,0x01,0x86,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x13,0x00,0x4e,0x59,0xb5,0x38,0x1a,0x12,0x03,0x07,0x19,0x2b,0x13,0x34,0x26,0x0e,0x01,0x1e,0x02,0x36,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x2e,0x01,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x17,0x01,0x16,0xfa,0x2a,0x3a,0x2c,0x02,0x28,0x3e,0x26,0x02, +0x55,0x14,0xfe,0xee,0x16,0x3b,0x14,0xfe,0x71,0x15,0x1e,0x2a,0x1d,0xe9,0x1d,0x48,0x15,0x01,0x8f,0x14,0x02,0x58,0x1e,0x2a,0x02,0x26,0x40,0x24,0x06,0x30,0xfe,0xd9,0x1e,0x15,0xfe,0xee,0x15,0x15,0x01,0x8f,0x15,0x48,0x1d,0xe8,0x1d,0x2a,0x01,0x1e,0x15,0xfe,0x71,0x15,0x00,0x0d,0x00,0x00,0xff,0xea,0x03,0xca,0x02,0xd2,0x00,0x03, +0x00,0x07,0x00,0x0b,0x00,0x0f,0x00,0x13,0x00,0x17,0x00,0x1b,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x2b,0x00,0x2f,0x00,0x33,0x00,0xa9,0x40,0xa6,0x18,0x12,0x0c,0x03,0x06,0x00,0x07,0x00,0x06,0x07,0x80,0x20,0x19,0x13,0x1d,0x0d,0x05,0x07,0x03,0x00,0x07,0x03,0x7e,0x17,0x11,0x0b,0x03,0x05,0x02,0x04,0x02,0x05,0x04,0x80,0x16,0x10, +0x0a,0x03,0x04,0x01,0x02,0x04,0x01,0x7e,0x00,0x00,0x14,0x1e,0x0f,0x08,0x1b,0x05,0x03,0x02,0x00,0x03,0x67,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x05,0x01,0x02,0x58,0x1f,0x15,0x0e,0x1c,0x09,0x05,0x02,0x02,0x01,0x5f,0x1a,0x01,0x01,0x02,0x01,0x4f,0x30,0x30,0x28,0x28,0x1c,0x1c,0x18,0x18,0x10,0x10,0x04,0x04,0x00,0x00,0x30,0x33, +0x30,0x33,0x32,0x31,0x2f,0x2e,0x2d,0x2c,0x28,0x2b,0x28,0x2b,0x2a,0x29,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x1c,0x1f,0x1c,0x1f,0x1e,0x1d,0x18,0x1b,0x18,0x1b,0x1a,0x19,0x17,0x16,0x15,0x14,0x10,0x13,0x10,0x13,0x12,0x11,0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x04,0x07,0x04,0x07,0x06,0x05,0x00,0x03,0x00,0x03,0x11,0x21, +0x07,0x17,0x2b,0x15,0x11,0x21,0x11,0x01,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x05,0x15,0x33,0x35,0x03,0x33,0x35,0x23,0x13,0x23,0x15,0x33,0x17,0x35,0x23,0x1d,0x01,0x33,0x35,0x23,0x13,0x35,0x23,0x15,0x03,0xca,0xfe,0x3d,0x9f,0x9f,0x9f,0x9f,0x9f, +0x9f,0x9f,0xe1,0x9e,0x9e,0x9e,0x9e,0x9e,0xfd,0x5b,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0x9e,0xe1,0x9d,0x9d,0x9d,0x9d,0x9d,0x16,0x02,0xe8,0xfd,0x18,0x01,0xc4,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e,0x9e,0x43,0x9f,0x9f,0xfe,0x80,0x9d,0x01,0xc4,0x9e,0xe2,0x9f,0x9f,0xe1,0x9d,0x01,0x26,0x9e, +0x9e,0x00,0x00,0x00,0x00,0x02,0xff,0xff,0xff,0xf9,0x04,0x19,0x03,0x0b,0x00,0x12,0x00,0x29,0x00,0x20,0x40,0x1d,0x00,0x04,0x00,0x02,0x01,0x04,0x02,0x68,0x00,0x01,0x00,0x00,0x01,0x00,0x63,0x00,0x03,0x03,0x13,0x03,0x4e,0x23,0x3a,0x23,0x36,0x35,0x05,0x07,0x1b,0x2b,0x01,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x2e,0x01,0x3f, +0x01,0x3e,0x01,0x33,0x21,0x32,0x16,0x27,0x15,0x21,0x22,0x06,0x0f,0x02,0x27,0x26,0x37,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x04,0x19,0x12,0xbb,0x18,0x56,0x26,0xfd,0xa1,0x13,0x1c,0x01,0x11,0xbc,0x18,0x56,0x25,0x02,0x5f,0x13,0x1e,0xc0,0xfe,0x30,0x35,0x72,0x23,0xbc,0x02,0x01,0x01,0x01,0x4a,0x33,0xb3, +0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x3f,0x11,0x14,0xdd,0x1c,0x28,0x0e,0x22,0x14,0xdd,0x1c,0x28,0x0e,0xaf,0x5a,0x34,0x29,0xdd,0x03,0x07,0x05,0x02,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x14,0x00,0x16,0x40,0x13,0x00,0x02,0x00,0x00,0x02,0x00,0x64,0x00, +0x01,0x01,0x13,0x01,0x4e,0x23,0x35,0x33,0x03,0x07,0x19,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0xa1,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x01,0xff,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33, +0x12,0x4a,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x1d,0x40,0x1a,0x01,0x01,0x00,0x49,0x00,0x01,0x00,0x01,0x85,0x03,0x02,0x02,0x00,0x00,0x76,0x00,0x00,0x00,0x06,0x00,0x06,0x11,0x12,0x04,0x07,0x18,0x2b,0x09,0x02,0x33,0x11,0x21,0x11,0x02,0xf8,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x78,0x01,0x6e, +0xfe,0x84,0x01,0x7c,0x01,0x5e,0xfe,0xa2,0x00,0x02,0xff,0xf7,0xff,0xe2,0x03,0xdb,0x03,0x12,0x00,0x17,0x00,0x20,0x00,0x26,0x40,0x23,0x00,0x02,0x01,0x02,0x85,0x03,0x01,0x01,0x00,0x00,0x01,0x59,0x03,0x01,0x01,0x01,0x00,0x61,0x00,0x00,0x01,0x00,0x51,0x19,0x18,0x1d,0x1c,0x18,0x20,0x19,0x20,0x2f,0x04,0x07,0x17,0x2b,0x01,0x1e, +0x01,0x06,0x07,0x06,0x26,0x06,0x07,0x06,0x1e,0x01,0x07,0x0e,0x02,0x23,0x22,0x26,0x37,0x3e,0x01,0x37,0x24,0x03,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x59,0x48,0x3a,0x12,0x1a,0x10,0x4c,0x54,0x26,0x1e,0x12,0x32,0x02,0x02,0x44,0xb8,0x7c,0xba,0xd2,0x0a,0x08,0xc0,0x78,0x01,0x22,0x48,0x1e,0x2c,0x2c,0x3e,0x2c,0x2c,0x02, +0x6e,0x30,0x7c,0x54,0x06,0x04,0x1c,0x08,0x2a,0x2e,0x3a,0x48,0x0e,0x1a,0x4a,0x4a,0xca,0x90,0x76,0xea,0x22,0x54,0xfd,0x8a,0x2c,0x40,0x2a,0x2a,0x40,0x2c,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x06,0x00,0x18,0x00,0x33,0x40,0x30,0x01,0x01,0x00,0x03,0x01,0x4c,0x00,0x03,0x00,0x03,0x85,0x04,0x01,0x00, +0x01,0x00,0x85,0x00,0x01,0x02,0x02,0x01,0x57,0x00,0x01,0x01,0x02,0x60,0x00,0x02,0x01,0x02,0x50,0x00,0x00,0x18,0x16,0x11,0x0e,0x0b,0x09,0x00,0x06,0x00,0x06,0x05,0x07,0x16,0x2b,0x01,0x11,0x16,0x1f,0x01,0x16,0x17,0x05,0x14,0x16,0x17,0x21,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21,0x02,0x3b,0x0d,0x08, +0xe3,0x08,0x08,0xfe,0xb1,0x20,0x16,0x01,0x2f,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xbe,0x02,0x34,0x01,0x08,0x08,0x08,0xe4,0x07,0x0d,0x12,0x16,0x1e,0x01,0xfd,0xb3,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c,0x17,0x1e,0x01,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x08,0x00,0x6a,0x00,0x45, +0x40,0x42,0x65,0x59,0x4c,0x41,0x04,0x00,0x04,0x3b,0x0a,0x02,0x01,0x00,0x34,0x28,0x1b,0x10,0x04,0x03,0x01,0x03,0x4c,0x06,0x01,0x04,0x00,0x03,0x02,0x04,0x03,0x69,0x00,0x00,0x00,0x05,0x5f,0x00,0x05,0x05,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x5c,0x5b,0x53,0x51,0x49,0x48,0x2b,0x2a,0x22,0x20,0x13, +0x12,0x07,0x07,0x18,0x2b,0x01,0x34,0x26,0x22,0x0e,0x01,0x16,0x32,0x36,0x25,0x15,0x14,0x06,0x0f,0x01,0x06,0x07,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x27,0x22,0x2f,0x01,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x35,0x27,0x26,0x27,0x07,0x06,0x22,0x27,0x26,0x27,0x26,0x34,0x37,0x3e,0x01,0x37,0x26,0x2f,0x01,0x2e,0x01,0x27, +0x35,0x34,0x36,0x3f,0x01,0x36,0x37,0x26,0x27,0x26,0x34,0x37,0x3e,0x01,0x33,0x32,0x1f,0x01,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x1f,0x01,0x16,0x17,0x37,0x36,0x32,0x17,0x16,0x17,0x16,0x14,0x07,0x0e,0x01,0x07,0x16,0x1f,0x01,0x1e,0x01,0x02,0x3b,0x52,0x78,0x52,0x02,0x56,0x74,0x56,0x01,0x1c,0x08,0x07,0x68,0x0a,0x0b, +0x13,0x28,0x06,0x05,0x0f,0x50,0x0d,0x07,0x07,0x4d,0x19,0x1a,0x09,0x07,0x04,0x10,0x7c,0x08,0x0c,0x10,0x1b,0x17,0x4f,0x06,0x10,0x06,0x46,0x16,0x04,0x05,0x08,0x28,0x0a,0x0f,0x08,0x66,0x07,0x08,0x01,0x0a,0x05,0x68,0x08,0x0e,0x17,0x25,0x06,0x05,0x0f,0x50,0x0d,0x07,0x08,0x4d,0x18,0x1a,0x09,0x08,0x03,0x11,0x7c,0x07,0x0c,0x01, +0x0f,0x1c,0x17,0x4f,0x05,0x0f,0x07,0x48,0x14,0x04,0x04,0x09,0x28,0x0a,0x0f,0x08,0x66,0x07,0x0a,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0x78,0x7c,0x07,0x0c,0x01,0x10,0x1e,0x15,0x1b,0x32,0x06,0x0e,0x06,0x15,0x50,0x01,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a,0x07,0x67,0x09,0x0c,0x3c,0x05,0x06,0x40,0x1e,0x05,0x0e,0x06,0x0c, +0x32,0x0f,0x1c,0x1b,0x0f,0x01,0x0c,0x07,0x7c,0x07,0x0c,0x01,0x10,0x19,0x1a,0x20,0x2d,0x07,0x0c,0x07,0x14,0x50,0x05,0x3c,0x0d,0x08,0x4c,0x1c,0x10,0x0a,0x07,0x67,0x09,0x0b,0x3b,0x05,0x05,0x43,0x1c,0x05,0x0e,0x06,0x0c,0x32,0x0f,0x1c,0x1a,0x10,0x01,0x0c,0x00,0x00,0x00,0x09,0x00,0x00,0xff,0xf9,0x03,0xe8,0x03,0x0b,0x00,0x0f, +0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0x8f,0x00,0x47,0x40,0x44,0x0f,0x09,0x02,0x03,0x0e,0x08,0x02,0x02,0x01,0x03,0x02,0x67,0x0b,0x05,0x02,0x01,0x0a,0x04,0x02,0x00,0x01,0x00,0x63,0x10,0x0c,0x02,0x06,0x06,0x07,0x5f,0x11,0x0d,0x02,0x07,0x07,0x13,0x06,0x4e,0x8e,0x8b,0x86,0x83,0x7e,0x7b, +0x76,0x73,0x6e,0x6b,0x66,0x63,0x5e,0x5b,0x56,0x53,0x4e,0x4b,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x35,0x33,0x12,0x07,0x1f,0x2b,0x25,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x07,0x23,0x22, +0x26,0x27,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x17,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22, +0x26,0x27,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x37,0x33,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x1e,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2, +0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0xfe,0x9c,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2, +0x17,0x1e,0x01,0x66,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x01,0x20,0x16,0xb2,0x16,0x20,0x20,0x16,0xb2,0x17,0x1e,0x9a,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x01,0x06,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x02, +0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0xfe,0xcd,0x6c,0x16,0x1e,0x01,0x20,0x15,0x6c,0x16,0x20,0x01,0x1e,0x02,0x24,0x6b,0x16,0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0xfe,0xcc,0x6b,0x16,0x20,0x01,0x1e,0x17,0x6b,0x17,0x1e,0x01,0x20,0x01,0x08,0x6b,0x16, +0x20,0x20,0x16,0x6b,0x16,0x20,0x20,0x00,0x00,0x05,0x00,0x00,0xff,0x6a,0x03,0xe8,0x03,0x52,0x00,0x10,0x00,0x14,0x00,0x25,0x00,0x2f,0x00,0x39,0x00,0x65,0x40,0x62,0x33,0x29,0x02,0x07,0x08,0x21,0x01,0x05,0x02,0x1d,0x15,0x0d,0x0c,0x04,0x00,0x05,0x03,0x4c,0x04,0x01,0x05,0x01,0x4b,0x0a,0x01,0x08,0x09,0x01,0x07,0x01,0x08,0x07, +0x67,0x00,0x02,0x05,0x01,0x02,0x57,0x06,0x0c,0x03,0x0b,0x04,0x01,0x00,0x05,0x00,0x01,0x05,0x69,0x06,0x0c,0x03,0x0b,0x04,0x01,0x01,0x00,0x5f,0x04,0x01,0x00,0x01,0x00,0x4f,0x11,0x11,0x00,0x00,0x37,0x35,0x32,0x31,0x2d,0x2b,0x28,0x27,0x24,0x22,0x1f,0x1e,0x1b,0x19,0x11,0x14,0x11,0x14,0x13,0x12,0x00,0x10,0x00,0x0f,0x37,0x0d, +0x07,0x17,0x2b,0x01,0x11,0x14,0x06,0x07,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x13,0x36,0x33,0x21,0x11,0x23,0x11,0x01,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x22,0x26,0x27,0x11,0x33,0x32,0x17,0x25,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x05,0x15,0x23,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x89,0x16, +0x0e,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x8b,0x04,0x0d,0x01,0x9f,0x8e,0x02,0x3b,0x16,0x0e,0xfe,0xe3,0x0f,0x14,0x01,0x0f,0x14,0x01,0xed,0x0d,0x04,0xfe,0x3e,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x01,0x77,0xc5,0x0a,0x08,0xa1,0x08,0x0a,0x02,0x9f,0xfe,0x54,0x0f,0x14,0x01,0xfe,0xbf,0x0f,0x14,0x01,0x16,0x0e,0x01,0x1d,0x01,0xe8,0x0c, +0xfe,0x78,0x01,0x88,0xfe,0x0c,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x41,0x16,0x0e,0x01,0xac,0x0c,0xad,0x7d,0x7d,0x08,0x0a,0x0a,0x08,0x7d,0x7d,0x08,0x0a,0x0a,0x00,0x08,0xff,0xff,0xff,0xf8,0x03,0xe9,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x3f,0x00,0x4f,0x00,0x5f,0x00,0x6f,0x00,0x7f,0x00,0x6f,0x40,0x6c,0x79,0x78, +0x71,0x49,0x48,0x41,0x06,0x08,0x09,0x69,0x61,0x60,0x29,0x21,0x20,0x06,0x04,0x05,0x59,0x58,0x51,0x50,0x19,0x18,0x11,0x10,0x08,0x02,0x03,0x39,0x38,0x31,0x09,0x08,0x01,0x06,0x00,0x01,0x04,0x4c,0x0d,0x01,0x05,0x0c,0x01,0x04,0x03,0x05,0x04,0x67,0x0b,0x01,0x03,0x0a,0x01,0x02,0x01,0x03,0x02,0x67,0x07,0x01,0x01,0x06,0x01,0x00, +0x01,0x00,0x63,0x0e,0x01,0x08,0x08,0x09,0x5f,0x0f,0x01,0x09,0x09,0x13,0x08,0x4e,0x7d,0x7b,0x75,0x73,0x6d,0x6b,0x65,0x64,0x5d,0x5b,0x55,0x54,0x4d,0x4c,0x26,0x26,0x17,0x26,0x17,0x17,0x17,0x17,0x14,0x10,0x07,0x1f,0x2b,0x37,0x15,0x14,0x06,0x27,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x27,0x15,0x14,0x06,0x27, +0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x17,0x33,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x23,0x22,0x26,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x01,0x15,0x14,0x06,0x27,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x35,0x34,0x36,0x37,0x33,0x32,0x16,0x01,0x15,0x14,0x06,0x27, +0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x27,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x8f,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08, +0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0xfc,0xa6,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x03,0x58,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd,0x12,0x07, +0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x01,0x0a,0x08,0xfd,0x12,0x07,0x0a,0x01,0x0c,0x06,0x02,0xee,0x07,0x0c,0x76,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xd0,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xfe,0x4c,0x6b,0x07,0x0c,0x01,0x0a, +0x08,0x6b,0x07,0x0a,0x01,0x0c,0x02,0x7d,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0xfe,0x4d,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0xce,0x6b,0x07,0x0a,0x01,0x0c,0x06,0x6b,0x08,0x0a,0x0a,0xcf,0x6b,0x08,0x0a,0x0a,0x08,0x6b,0x07,0x0a,0x01,0x0c,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x02,0x83, +0x03,0x0b,0x00,0x07,0x00,0x1f,0x00,0x20,0x40,0x1d,0x05,0x03,0x02,0x00,0x00,0x02,0x00,0x02,0x63,0x00,0x01,0x01,0x04,0x61,0x00,0x04,0x04,0x13,0x01,0x4e,0x23,0x13,0x25,0x36,0x13,0x10,0x06,0x07,0x1c,0x2b,0x13,0x21,0x35,0x34,0x26,0x0e,0x01,0x17,0x05,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17,0x33,0x35,0x34, +0x36,0x32,0x16,0x07,0x15,0x33,0x32,0x16,0xb3,0x01,0x1d,0x54,0x76,0x54,0x01,0x01,0xd0,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20,0x16,0x11,0x94,0xcc,0x96,0x02,0x12,0x17,0x1e,0x01,0xa5,0x6c,0x3b,0x54,0x02,0x50,0x3d,0xa1,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01,0x6c,0x66,0x94,0x94,0x66,0x6c,0x1e,0x00,0x00, +0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x06,0x01,0x01,0x00,0x01,0x4c,0x00,0x01,0x00,0x4a,0x05,0x01,0x01,0x49,0x00,0x00,0x01,0x01,0x00,0x57,0x00,0x00,0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x11,0x11,0x02,0x07,0x18,0x2b,0x01,0x15,0x21,0x11,0x21,0x15,0x01,0x01,0x7a,0x01,0x60,0xfe, +0xa0,0xfe,0x86,0x02,0xda,0xbe,0xfe,0x86,0xc0,0x01,0x7c,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x04,0x2f,0x03,0x52,0x00,0x0f,0x00,0x2f,0x00,0x2e,0x40,0x2b,0x09,0x01,0x02,0x01,0x00,0x20,0x01,0x03,0x02,0x02,0x4c,0x00,0x05,0x00,0x00,0x01,0x05,0x00,0x67,0x00,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x00,0x03,0x03,0x11,0x03,0x4e, +0x35,0x26,0x36,0x26,0x26,0x14,0x06,0x07,0x1c,0x2b,0x01,0x11,0x34,0x26,0x27,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x14,0x1e,0x01,0x17,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x34,0x3e,0x01,0x35,0x21,0x22,0x26,0x37,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0xe8,0x0a,0x08,0xfc,0x83, +0x07,0x0a,0x01,0x0c,0x06,0x03,0x7d,0x07,0x0c,0x46,0x34,0x25,0xfe,0xd1,0x12,0x10,0x01,0x14,0x0f,0xfe,0xe2,0x0f,0x14,0x01,0x12,0x12,0xfe,0xd0,0x24,0x36,0x01,0x34,0x25,0x03,0x7d,0x25,0x34,0x01,0x28,0x01,0xd1,0x07,0x0a,0x01,0x0c,0x06,0xfe,0x2f,0x07,0x0a,0x0a,0x01,0xd8,0xfd,0xa1,0x25,0x34,0x01,0x14,0x2e,0x22,0x07,0x0e,0x16, +0x16,0x0e,0x08,0x22,0x2c,0x15,0x36,0x24,0x02,0x5f,0x25,0x34,0x34,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xe1,0x02,0xf8,0x02,0xdb,0x00,0x21,0x00,0x31,0x00,0x2f,0x40,0x2c,0x11,0x06,0x02,0x00,0x03,0x01,0x4c,0x00,0x01,0x00,0x01,0x86,0x00,0x02,0x00,0x04,0x03,0x02,0x04,0x69,0x00,0x03,0x00,0x00,0x03,0x59,0x00,0x03,0x03,0x00, +0x61,0x00,0x00,0x03,0x00,0x51,0x15,0x2b,0x1d,0x25,0x22,0x05,0x07,0x1b,0x2b,0x01,0x0e,0x01,0x23,0x22,0x26,0x27,0x0f,0x01,0x06,0x23,0x22,0x26,0x35,0x34,0x3f,0x02,0x2e,0x01,0x35,0x34,0x37,0x3e,0x01,0x32,0x17,0x16,0x17,0x16,0x15,0x14,0x07,0x06,0x25,0x1e,0x01,0x33,0x32,0x3e,0x01,0x34,0x2e,0x01,0x22,0x0e,0x01,0x15,0x14,0x16, +0x02,0xa8,0x29,0x66,0x36,0x31,0x5d,0x28,0x33,0x82,0x15,0x18,0x1e,0x2d,0x0f,0x81,0x7e,0x20,0x22,0x27,0x25,0x80,0x95,0x40,0x3f,0x26,0x26,0x14,0x14,0xfe,0x99,0x19,0x40,0x21,0x2d,0x4f,0x2e,0x2f,0x4e,0x5b,0x4f,0x2f,0x1a,0x01,0x00,0x29,0x2a,0x22,0x20,0x7d,0x82,0x0f,0x2f,0x1e,0x1a,0x13,0x82,0x33,0x26,0x5e,0x32,0x4b,0x40,0x3f, +0x4b,0x27,0x25,0x3f,0x41,0x4a,0x38,0x32,0x34,0x24,0x18,0x1a,0x2e,0x4f,0x5d,0x4e,0x2e,0x2f,0x4e,0x2d,0x22,0x40,0x00,0x00,0x00,0x02,0xff,0xfd,0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x0c,0x00,0x19,0x00,0x28,0x40,0x25,0x04,0x01,0x00,0x00,0x03,0x61,0x00,0x03,0x03,0x13,0x4d,0x00,0x01,0x01,0x02,0x61,0x00,0x02,0x02,0x11,0x02,0x4e, +0x01,0x00,0x17,0x16,0x11,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x05,0x07,0x16,0x2b,0x01,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x01,0xad,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xf4, +0xba,0x7e,0x02,0x8e,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x4d,0x02,0xff,0x00,0x06,0x00,0x14,0x00,0x19,0x00,0x24,0x00,0xe3,0x40,0x17,0x1e,0x01,0x02,0x05,0x1d,0x16,0x0e,0x07,0x04,0x03,0x02,0x19,0x03,0x02, +0x03,0x00,0x03,0x01,0x01,0x01,0x00,0x04,0x4c,0x4b,0xb0,0x0a,0x50,0x58,0x40,0x26,0x00,0x02,0x05,0x03,0x05,0x02,0x03,0x80,0x00,0x03,0x00,0x00,0x03,0x70,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x05,0x05,0x13,0x4d,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x4b,0xb0,0x12,0x50,0x58,0x40,0x27,0x00,0x02, +0x05,0x03,0x05,0x02,0x03,0x80,0x00,0x03,0x00,0x05,0x03,0x00,0x7e,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x72,0x00,0x05,0x05,0x13,0x4d,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x4b,0xb0,0x29,0x50,0x58,0x40,0x28,0x00,0x02,0x05,0x03,0x05,0x02,0x03,0x80,0x00,0x03,0x00,0x05,0x03,0x00,0x7e,0x06,0x01,0x01,0x00, +0x04,0x00,0x01,0x04,0x80,0x00,0x05,0x05,0x13,0x4d,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x1b,0x40,0x23,0x00,0x05,0x02,0x05,0x85,0x00,0x02,0x03,0x02,0x85,0x00,0x03,0x00,0x03,0x85,0x06,0x01,0x01,0x00,0x04,0x00,0x01,0x04,0x80,0x00,0x00,0x00,0x04,0x60,0x00,0x04,0x04,0x11,0x04,0x4e,0x59,0x59,0x59,0x40,0x12, +0x00,0x00,0x21,0x20,0x18,0x17,0x10,0x0f,0x09,0x08,0x00,0x06,0x00,0x06,0x14,0x07,0x07,0x17,0x2b,0x17,0x37,0x27,0x07,0x15,0x33,0x15,0x01,0x34,0x23,0x22,0x07,0x01,0x06,0x15,0x14,0x33,0x32,0x37,0x01,0x36,0x27,0x17,0x01,0x23,0x35,0x01,0x14,0x0f,0x01,0x27,0x37,0x36,0x32,0x1f,0x01,0x16,0xcb,0x32,0x83,0x33,0x48,0x01,0x5f,0x0c, +0x05,0x04,0xfe,0xd1,0x04,0x0d,0x05,0x04,0x01,0x2f,0x03,0x1e,0xe8,0xfe,0x30,0xe8,0x03,0x4d,0x14,0x5d,0xe8,0x5d,0x14,0x3b,0x16,0x83,0x14,0x07,0x33,0x83,0x33,0x3c,0x47,0x02,0x06,0x0c,0x04,0xfe,0xd2,0x04,0x06,0x0c,0x04,0x01,0x2e,0x04,0x71,0xe8,0xfe,0x2f,0xe9,0x01,0x9a,0x1d,0x15,0x5d,0xe9,0x5c,0x15,0x15,0x83,0x16,0x00,0x00, +0x00,0x05,0xff,0xff,0xff,0xf9,0x03,0x59,0x02,0xc4,0x00,0x08,0x00,0x11,0x00,0x21,0x00,0x2b,0x00,0x41,0x00,0x8e,0x40,0x0f,0x13,0x01,0x01,0x04,0x09,0x00,0x02,0x00,0x01,0x1b,0x01,0x05,0x00,0x03,0x4c,0x4b,0xb0,0x0a,0x50,0x58,0x40,0x30,0x03,0x01,0x01,0x04,0x00,0x04,0x01,0x00,0x80,0x02,0x01,0x00,0x05,0x08,0x00,0x70,0x00,0x09, +0x00,0x07,0x06,0x09,0x07,0x67,0x00,0x06,0x00,0x04,0x01,0x06,0x04,0x67,0x00,0x05,0x08,0x08,0x05,0x58,0x00,0x05,0x05,0x08,0x60,0x00,0x08,0x05,0x08,0x50,0x1b,0x40,0x31,0x03,0x01,0x01,0x04,0x00,0x04,0x01,0x00,0x80,0x02,0x01,0x00,0x05,0x04,0x00,0x05,0x7e,0x00,0x09,0x00,0x07,0x06,0x09,0x07,0x67,0x00,0x06,0x00,0x04,0x01,0x06, +0x04,0x67,0x00,0x05,0x08,0x08,0x05,0x58,0x00,0x05,0x05,0x08,0x60,0x00,0x08,0x05,0x08,0x50,0x59,0x40,0x0e,0x3d,0x3a,0x37,0x23,0x13,0x26,0x25,0x13,0x14,0x13,0x12,0x0a,0x07,0x1f,0x2b,0x25,0x14,0x06,0x22,0x26,0x3e,0x01,0x1e,0x01,0x17,0x14,0x06,0x22,0x26,0x3e,0x01,0x1e,0x01,0x17,0x35,0x34,0x26,0x27,0x21,0x22,0x06,0x07,0x15, +0x14,0x16,0x17,0x21,0x32,0x36,0x01,0x21,0x03,0x2e,0x01,0x23,0x21,0x22,0x06,0x07,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x37,0x35,0x34,0x37,0x13,0x3e,0x01,0x17,0x21,0x32,0x16,0x17,0x13,0x16,0x02,0x44,0x1a,0x24,0x1c,0x02,0x18,0x28,0x16,0x91,0x1a,0x24,0x1c,0x02,0x18,0x28,0x16,0x41,0x0c,0x06,0xfd,0x59,0x07,0x0a,0x01,0x0c, +0x06,0x02,0xa7,0x07,0x0a,0xfd,0x52,0x02,0x93,0x58,0x02,0x0e,0x07,0xfe,0x4b,0x07,0x0e,0x02,0x02,0x9e,0x34,0x25,0xfd,0x59,0x24,0x36,0x01,0x09,0x6e,0x09,0x34,0x1e,0x01,0xb5,0x1f,0x32,0x0a,0x6e,0x09,0xab,0x12,0x1a,0x1a,0x24,0x1c,0x02,0x18,0x14,0x12,0x1a,0x1a,0x24,0x1c,0x02,0x18,0x6d,0xb3,0x07,0x0a,0x01,0x0c,0x06,0xb3,0x07, +0x0a,0x01,0x0c,0x01,0x12,0x01,0x0d,0x07,0x0a,0x0a,0x07,0xfe,0x9a,0xb3,0x25,0x34,0x34,0x25,0xb3,0x0e,0x1c,0x01,0x52,0x1d,0x26,0x01,0x24,0x1e,0xfe,0xae,0x1c,0x00,0x00,0x01,0x00,0x00,0xff,0xe2,0x02,0xda,0x02,0xda,0x00,0x06,0x00,0x26,0x40,0x23,0x01,0x01,0x00,0x01,0x01,0x4c,0x00,0x01,0x01,0x4a,0x02,0x01,0x00,0x49,0x00,0x01, +0x00,0x00,0x01,0x57,0x00,0x01,0x01,0x00,0x5f,0x00,0x00,0x01,0x00,0x4f,0x11,0x13,0x02,0x07,0x18,0x2b,0x09,0x02,0x35,0x21,0x11,0x21,0x01,0x5e,0x01,0x7c,0xfe,0x84,0xfe,0xa2,0x01,0x5e,0x02,0xda,0xfe,0x84,0xfe,0x84,0xc0,0x01,0x7a,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xab,0x03,0x6b,0x03,0x20,0x00,0x0f,0x00,0x13,0x00,0x1f, +0x00,0x38,0x40,0x35,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,0x17,0x16,0x15,0x0b,0x03,0x02,0x01,0x4c,0x00,0x02,0x02,0x00,0x5f,0x04,0x01,0x00,0x00,0x10,0x4d,0x00,0x03,0x03,0x01,0x5f,0x00,0x01,0x01,0x11,0x01,0x4e,0x01,0x00,0x13,0x12,0x11,0x10,0x09,0x06,0x00,0x0f,0x01,0x0e,0x05,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14, +0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x07,0x17,0x07,0x17,0x37,0x17,0x37,0x27,0x37,0x27,0x07,0x87,0x0c,0x11,0x11,0x0c,0x02,0xc6,0x0c,0x11,0x11,0x0c,0xfd,0x58,0x02,0x8b,0xfd,0x75,0x01,0x87,0x2d,0x52,0x52,0x2d,0x53,0x52,0x2e,0x53,0x53,0x2e,0x52,0x03,0x1f,0x12,0x0c,0xfc,0xc8,0x0c,0x11, +0x11,0x0c,0x03,0x38,0x0c,0x12,0x3b,0xfd,0x02,0x02,0xcb,0x2e,0x52,0x53,0x2d,0x52,0x52,0x2d,0x53,0x52,0x2e,0x52,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x84,0x03,0x8f,0x03,0x33,0x00,0x02,0x00,0x10,0x00,0x3c,0x00,0x68,0x01,0x4d,0x40,0x0b,0x01,0x01,0x0a,0x02,0x62,0x36,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x0c,0x50,0x58,0x40,0x36, +0x12,0x01,0x01,0x03,0x01,0x85,0x04,0x11,0x02,0x00,0x03,0x02,0x03,0x00,0x72,0x0e,0x05,0x02,0x02,0x0a,0x0a,0x02,0x59,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x0f,0x01,0x0a,0x0a,0x03,0x5f,0x00,0x03,0x03,0x13,0x03,0x4e,0x1b,0x4b,0xb0,0x13,0x50,0x58,0x40,0x3c,0x12,0x01, +0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80,0x11,0x01,0x00,0x02,0x03,0x00,0x70,0x0e,0x05,0x02,0x02,0x0a,0x0a,0x02,0x59,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x0f,0x01,0x0a,0x0a,0x03,0x5f,0x00,0x03,0x03,0x13,0x03,0x4e,0x1b,0x4b,0xb0,0x16,0x50,0x58, +0x40,0x3d,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80,0x11,0x01,0x00,0x02,0x03,0x00,0x02,0x7e,0x0e,0x05,0x02,0x02,0x0a,0x0a,0x02,0x59,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x0f,0x01,0x0a,0x0a,0x03,0x5f,0x00,0x03,0x03,0x13,0x03,0x4e,0x1b, +0x40,0x44,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80,0x11,0x01,0x00,0x02,0x03,0x00,0x02,0x7e,0x00,0x03,0x04,0x0a,0x03,0x57,0x0e,0x05,0x02,0x02,0x0f,0x01,0x0a,0x06,0x02,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x69,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61, +0x0b,0x01,0x08,0x09,0x08,0x51,0x59,0x59,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x68,0x66,0x5e,0x5c,0x5b,0x59,0x4d,0x4b,0x4a,0x48,0x3f,0x3d,0x3c,0x3a,0x32,0x30,0x2f,0x2d,0x21,0x1f,0x1e,0x1c,0x13,0x11,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d, +0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x13,0x33,0x32,0x16,0x1d,0x01,0x14,0x16,0x17,0x16,0x17,0x16,0x3b,0x01,0x15,0x23,0x22,0x07,0x06,0x07,0x06,0x07,0x06,0x1d,0x01,0x14,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e, +0x01,0x2b,0x01,0x35,0x33,0x32,0x36,0x37,0x36,0x37,0x36,0x3d,0x01,0x34,0x37,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0x90,0x63,0x64,0xfe,0xcd,0x0d,0x13,0x3f,0x01,0x58,0x3f,0x12,0x0d,0x55,0x1b,0x47,0x45,0x07,0x0b,0x09,0x12,0x0e,0x1c,0x0f,0x0f,0x1a,0x12,0x0f,0x0c,0x08,0x05, +0x03,0x0f,0x22,0x34,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x20,0x0a,0x08,0x05,0x04,0x07,0x07,0x23,0x33,0x27,0x1b,0x15,0x55,0x4e,0x4e,0x55,0x15,0x02,0xb1,0xac,0xac,0x82,0x12,0x0d,0xe7,0xc7,0x2e,0x4e,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x09,0x0a, +0x05,0x05,0x33,0x05,0x03,0x0a,0x08,0x0f,0x0d,0x14,0x80,0x1d,0x33,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09,0x0b,0x33,0x08,0x09,0x08,0x0f,0x14,0x0d,0x57,0x21,0x16,0x19,0x24,0x12,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x00,0x01,0x00,0x00, +0xff,0xf2,0x02,0xf8,0x02,0xcc,0x00,0x06,0x00,0x17,0x40,0x14,0x06,0x01,0x00,0x4a,0x02,0x01,0x00,0x01,0x00,0x85,0x00,0x01,0x01,0x76,0x11,0x11,0x10,0x03,0x07,0x19,0x2b,0x01,0x23,0x11,0x21,0x11,0x23,0x01,0x02,0xf8,0xc0,0xfe,0x88,0xc0,0x01,0x7c,0x01,0x50,0xfe,0xa2,0x01,0x5e,0x01,0x7c,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0xa5, +0x02,0x98,0x00,0x15,0x00,0x1d,0x40,0x1a,0x0f,0x01,0x00,0x01,0x01,0x4c,0x00,0x02,0x01,0x02,0x85,0x00,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x01,0x36,0x32,0x1f,0x01,0x16,0x03,0xa5,0x10,0xfe,0x20,0x10,0x2c, +0x10,0xfe,0xea,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0x01,0x6e,0x10,0x2c,0x10,0x4c,0x10,0x02,0x16,0x16,0x10,0xfe,0x20,0x0f,0x0f,0x01,0x16,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa5,0x01,0x6f,0x10,0x10,0x4c,0x0f,0x00,0x03,0xff,0xf5,0xff,0xb1,0x03,0xf3,0x03,0x52,0x00,0x0f,0x00,0x21,0x00,0x33,0x00,0x33,0x40,0x30,0x1b,0x11,0x02,0x03, +0x02,0x09,0x01,0x02,0x01,0x00,0x02,0x4c,0x00,0x05,0x00,0x02,0x03,0x05,0x02,0x67,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x01,0x01,0x04,0x5f,0x00,0x04,0x04,0x11,0x04,0x4e,0x17,0x38,0x27,0x27,0x26,0x23,0x06,0x07,0x1c,0x2b,0x25,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x1d,0x01,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34, +0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x17,0x14,0x16,0x37,0x33,0x32,0x36,0x03,0x01,0x16,0x07,0x0e,0x01,0x07,0x21,0x22,0x26,0x27,0x26,0x37,0x01,0x3e,0x01,0x32,0x16,0x02,0x3b,0x0a,0x07,0x6c,0x07,0x0a,0x0a,0x07,0x6c,0x07,0x0a,0x01,0x0a,0x05,0x07,0x07,0x7a,0x06,0x08,0x05,0x09,0x0c,0x07,0x67,0x08,0x0c,0x08,0x01,0xac,0x14, +0x15,0x09,0x22,0x12,0xfc,0xa6,0x12,0x22,0x09,0x15,0x14,0x01,0xad,0x09,0x22,0x26,0x22,0x53,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xd7,0x01,0x01,0x06,0x04,0x06,0x06,0x04,0x08,0xff,0x05,0x08,0x01,0x06,0x02,0x10,0xfc,0xee,0x23,0x23,0x11,0x12,0x01,0x14,0x10,0x23,0x23,0x03,0x12,0x11,0x14,0x14,0x00,0x04,0x00,0x00, +0xff,0x79,0x03,0xd1,0x03,0x3c,0x00,0x0f,0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x36,0x40,0x33,0x07,0x01,0x05,0x03,0x01,0x01,0x05,0x01,0x63,0x06,0x01,0x04,0x04,0x00,0x5f,0x09,0x02,0x08,0x03,0x00,0x00,0x12,0x04,0x4e,0x11,0x10,0x01,0x00,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,0x19,0x16,0x10,0x1f,0x11,0x1e,0x09,0x06,0x00,0x0f, +0x01,0x0e,0x0a,0x07,0x16,0x2b,0x13,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x33,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x05,0x21,0x11,0x21,0x01,0x21,0x11,0x21,0x38,0x0d,0x13,0x13,0x0d,0x01,0x7c,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0x01,0x7d, +0x0d,0x12,0x12,0x0d,0xfc,0xa6,0x01,0x3e,0xfe,0xc2,0x01,0xfc,0x01,0x3e,0xfe,0xc2,0x03,0x3b,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d,0x12,0x12,0x0d,0x03,0x83,0x0d,0x12,0x3e,0xfc,0xbb,0x03,0x45,0xfc,0xbb,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x7e,0x03,0xd6,0x03,0x37,0x00,0x0f, +0x00,0x1f,0x00,0x23,0x00,0x27,0x00,0x3d,0x40,0x3a,0x00,0x04,0x00,0x01,0x02,0x04,0x01,0x67,0x00,0x02,0x09,0x01,0x07,0x06,0x02,0x07,0x67,0x00,0x06,0x00,0x03,0x06,0x03,0x63,0x08,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x00,0x12,0x05,0x4e,0x24,0x24,0x20,0x20,0x24,0x27,0x24,0x27,0x26,0x25,0x20,0x23,0x20,0x23,0x14,0x35,0x35,0x35, +0x32,0x0a,0x07,0x1b,0x2b,0x01,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x15,0x34,0x26,0x23,0x21,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x35,0x03,0x11,0x21,0x11,0x01,0x11,0x21,0x11,0x03,0xd5,0x12,0x0d,0xfc,0x7d,0x0d,0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x12,0x0d,0xfc,0x7d,0x0d, +0x13,0x13,0x0d,0x03,0x83,0x0d,0x12,0x3f,0xfc,0xbc,0x03,0x44,0xfc,0xbc,0x03,0x17,0x0d,0x12,0x12,0x0d,0xfe,0x84,0x0d,0x12,0x12,0x0d,0x80,0x0d,0x12,0x12,0x0d,0xfe,0x83,0x0d,0x12,0x12,0x0d,0x03,0x5a,0xfe,0xc2,0x01,0x3e,0xfe,0x04,0xfe,0xc1,0x01,0x3f,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0x89,0x03,0xdc,0x03,0x38,0x00,0x02, +0x00,0x10,0x00,0x39,0x00,0x62,0x01,0x0d,0x40,0x0b,0x01,0x01,0x06,0x0a,0x5c,0x33,0x02,0x07,0x06,0x02,0x4c,0x4b,0xb0,0x1c,0x50,0x58,0x40,0x38,0x12,0x01,0x01,0x03,0x01,0x85,0x04,0x11,0x02,0x00,0x03,0x02,0x03,0x00,0x02,0x80,0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10, +0x01,0x09,0x0b,0x01,0x08,0x09,0x08,0x65,0x0f,0x01,0x0a,0x0a,0x03,0x5f,0x00,0x03,0x03,0x13,0x0a,0x4e,0x1b,0x4b,0xb0,0x21,0x50,0x58,0x40,0x3f,0x12,0x01,0x01,0x03,0x01,0x85,0x04,0x11,0x02,0x00,0x03,0x02,0x03,0x00,0x02,0x80,0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f,0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01, +0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x1b,0x40,0x45,0x12,0x01,0x01,0x03,0x01,0x85,0x00,0x04,0x03,0x00,0x03,0x04,0x00,0x80,0x11,0x01,0x00,0x02,0x03,0x00,0x02,0x7e,0x0e,0x05,0x02,0x02,0x0a,0x03,0x02,0x0a,0x7e,0x00,0x03,0x0f, +0x01,0x0a,0x06,0x03,0x0a,0x69,0x0d,0x01,0x06,0x0c,0x01,0x07,0x09,0x06,0x07,0x6a,0x10,0x01,0x09,0x08,0x08,0x09,0x59,0x10,0x01,0x09,0x09,0x08,0x61,0x0b,0x01,0x08,0x09,0x08,0x51,0x59,0x59,0x40,0x2d,0x04,0x03,0x00,0x00,0x62,0x60,0x58,0x56,0x55,0x53,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x1f,0x1d,0x1c, +0x1a,0x13,0x11,0x0c,0x0b,0x0a,0x09,0x08,0x07,0x03,0x10,0x04,0x0f,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x01,0x07,0x27,0x25,0x22,0x06,0x1d,0x01,0x33,0x35,0x21,0x15,0x33,0x35,0x34,0x26,0x23,0x01,0x33,0x32,0x16,0x1d,0x01,0x14,0x1e,0x02,0x3b,0x01,0x15,0x23,0x22,0x07,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35, +0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x02,0x3d,0x01,0x34,0x3e,0x02,0x3b,0x01,0x15,0x23,0x22,0x1d,0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x03,0xdc,0x63,0x64,0xfd,0x31,0x0d,0x13,0x3f,0x02,0xf4,0x3f,0x12, +0x0d,0xfe,0xb9,0x1b,0x47,0x45,0x07,0x16,0x22,0x18,0x10,0x10,0x16,0x16,0x10,0x14,0x07,0x08,0x06,0x21,0x38,0x25,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa8,0x1b,0x47,0x44,0x04,0x04,0x0b,0x09,0x23,0x18,0x10,0x10,0x1c,0x1f,0x15,0x07,0x0f,0x21,0x34,0x27,0x1b,0x15,0x55,0x4d,0x4e,0x54,0x15,0x02,0x85,0xad,0xad,0xb3,0x12,0x0d,0xe7, +0xc7,0x6d,0x8d,0x0d,0x12,0xfe,0xfa,0x42,0x44,0x54,0x14,0x1b,0x13,0x0a,0x33,0x04,0x04,0x12,0x1c,0x14,0x80,0x1d,0x1a,0x19,0x23,0x13,0x34,0x52,0x7f,0x5a,0x0a,0x09,0x5c,0x54,0x54,0xfd,0x8a,0x43,0x43,0x7e,0x0e,0x12,0x0e,0x0a,0x09,0x0b,0x33,0x08,0x13,0x1a,0x14,0x57,0x20,0x30,0x23,0x13,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d, +0x54,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x43,0x00,0x44,0x40,0x41,0x18,0x01,0x03,0x04,0x13,0x01,0x02,0x00,0x03,0x06,0x01,0x01,0x00,0x03,0x4c,0x05,0x01,0x03,0x02,0x01,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x00,0x01,0x07,0x04,0x01,0x69,0x00,0x07,0x00,0x08,0x07,0x08,0x63, +0x00,0x06,0x06,0x09,0x5f,0x00,0x09,0x09,0x13,0x06,0x4e,0x42,0x3f,0x35,0x35,0x36,0x14,0x23,0x26,0x14,0x23,0x23,0x0a,0x07,0x1f,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3d,0x01,0x23,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x35,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x33,0x32,0x16,0x13,0x11, +0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x47,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24, +0x01,0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0xc4,0x08,0x0a,0x0a,0x08,0xc4,0x0a,0x08,0x24,0x07,0x0a,0xc5,0x08,0x0a,0x0a,0x08,0xc5,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0, +0x42,0x5e,0x01,0x60,0x00,0x03,0x00,0x00,0xff,0xf9,0x03,0x13,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x2f,0x00,0x2d,0x40,0x2a,0x09,0x01,0x02,0x00,0x01,0x01,0x4c,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x67,0x00,0x03,0x00,0x04,0x03,0x04,0x63,0x00,0x02,0x02,0x05,0x5f,0x00,0x05,0x05,0x13,0x02,0x4e,0x35,0x35,0x35,0x36,0x26,0x23,0x06, +0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x3d,0x01,0x34,0x36,0x33,0x21,0x32,0x16,0x13,0x11,0x34,0x26,0x23,0x21,0x22,0x06,0x07,0x11,0x14,0x16,0x17,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0x83,0x0a,0x08,0xfe,0x30,0x08,0x0a,0x0a,0x08,0x01,0xd0,0x08, +0x0a,0x47,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x24,0x01,0xd0,0x25,0x34,0x48,0x5e,0x43,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42,0x60,0x01,0x94,0x24,0x08,0x0a,0x0a,0x08,0x24,0x07,0x0a,0x0a,0xfe,0xff,0x01,0xd0,0x25,0x34,0x34,0x25,0xfe,0x30,0x25,0x34,0x01,0x36,0x01,0xf4,0xfe,0x30,0x43,0x5e,0x5e,0x43,0x01,0xd0,0x42, +0x5e,0x01,0x60,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58,0x01,0xd4,0x00,0x15,0x00,0x21,0xb1,0x06,0x64,0x44,0x40,0x16,0x07,0x01,0x00,0x02,0x01,0x4c,0x00,0x02,0x00,0x02,0x85,0x01,0x01,0x00,0x00,0x76,0x17,0x14,0x14,0x03,0x07,0x19,0x2b,0xb1,0x06,0x00,0x44,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01, +0x26,0x34,0x37,0x01,0x36,0x32,0x17,0x01,0x16,0x02,0x58,0x06,0x1c,0x05,0x0e,0x06,0xdc,0xdb,0x05,0x10,0x04,0x1c,0x06,0x06,0x01,0x04,0x05,0x0e,0x06,0x01,0x04,0x06,0xbd,0x07,0x05,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x0e,0x06,0x01,0x04,0x06,0x06,0xfe,0xfc,0x05,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0xff,0x89,0x03,0x42, +0x03,0x33,0x00,0x0f,0x00,0x19,0x00,0x33,0x00,0x3f,0x00,0x4b,0x00,0x57,0x00,0x8c,0x40,0x89,0x56,0x01,0x0c,0x0d,0x44,0x01,0x0a,0x0b,0x3e,0x01,0x08,0x09,0x03,0x4c,0x00,0x02,0x03,0x05,0x03,0x02,0x05,0x80,0x00,0x05,0x0d,0x03,0x05,0x0d,0x7e,0x00,0x0b,0x0c,0x0a,0x0c,0x0b,0x0a,0x80,0x00,0x0a,0x09,0x0c,0x0a,0x09,0x7e,0x00,0x09, +0x08,0x0c,0x09,0x08,0x7e,0x10,0x01,0x08,0x07,0x0c,0x08,0x07,0x7e,0x00,0x0d,0x11,0x01,0x0c,0x0b,0x0d,0x0c,0x67,0x00,0x07,0x00,0x01,0x07,0x01,0x64,0x06,0x04,0x0f,0x03,0x03,0x03,0x00,0x5f,0x0e,0x01,0x00,0x00,0x12,0x03,0x4e,0x4e,0x4c,0x36,0x34,0x10,0x10,0x01,0x00,0x54,0x52,0x4c,0x57,0x4e,0x57,0x48,0x45,0x42,0x40,0x3c,0x3a, +0x34,0x3f,0x36,0x3f,0x32,0x2f,0x2a,0x28,0x25,0x22,0x1f,0x1d,0x10,0x19,0x10,0x19,0x16,0x13,0x09,0x06,0x00,0x0f,0x01,0x0e,0x12,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x17,0x15,0x14,0x16,0x3b,0x01,0x32,0x36,0x3d,0x01,0x13,0x11,0x34,0x26,0x07,0x23,0x15,0x14,0x06,0x07, +0x23,0x22,0x26,0x37,0x35,0x23,0x22,0x06,0x17,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x27,0x21,0x22,0x35,0x34,0x36,0x37,0x21,0x32,0x16,0x07,0x14,0x27,0x21,0x22,0x26,0x37,0x34,0x33,0x21,0x32,0x15,0x14,0x06,0x27,0x21,0x22,0x35,0x34,0x36,0x17,0x21,0x32,0x16,0x07,0x14,0x02,0xa6,0x41,0x5a,0x01,0x5c,0x40,0xfd,0xf6,0x41,0x5a,0x01, +0x5c,0x40,0x68,0x20,0x15,0xd0,0x16,0x1e,0x9c,0x1e,0x15,0x35,0x3c,0x2c,0xd0,0x2b,0x3e,0x01,0x35,0x15,0x20,0x01,0x1e,0x16,0x02,0x0a,0x15,0x1e,0x68,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x1a,0xfe,0x60,0x0b,0x10,0x01,0x1a,0x01,0xa0,0x1a,0x0e,0x0c,0xfe,0x60,0x1a,0x0e,0x0c,0x01,0xa0,0x0b,0x10,0x01,0x03,0x33,0x5c, +0x40,0xfd,0x8f,0x41,0x5c,0x5c,0x41,0x02,0x71,0x41,0x5a,0x01,0x68,0x34,0x15,0x20,0x20,0x15,0x34,0xfd,0x5b,0x02,0x71,0x15,0x20,0x01,0x34,0x2b,0x3c,0x01,0x3e,0x2a,0x34,0x1e,0x16,0xfd,0x8f,0x15,0x20,0x20,0x49,0x19,0x0c,0x0e,0x01,0x10,0x0b,0x19,0x9d,0x0e,0x0c,0x19,0x19,0x0b,0x10,0x9d,0x19,0x0b,0x10,0x01,0x0e,0x0c,0x19,0x00, +0x00,0x03,0x00,0x00,0xff,0xf9,0x04,0x29,0x03,0x0b,0x00,0x11,0x00,0x27,0x00,0x45,0x00,0x4b,0x40,0x48,0x24,0x01,0x01,0x00,0x01,0x4c,0x00,0x07,0x04,0x03,0x04,0x07,0x03,0x80,0x00,0x03,0x02,0x04,0x03,0x02,0x7e,0x08,0x09,0x02,0x02,0x00,0x00,0x01,0x02,0x00,0x68,0x00,0x01,0x00,0x05,0x01,0x05,0x63,0x00,0x04,0x04,0x06,0x5f,0x00, +0x06,0x06,0x13,0x04,0x4e,0x13,0x12,0x42,0x40,0x3d,0x3b,0x38,0x35,0x30,0x2d,0x21,0x1e,0x19,0x16,0x12,0x27,0x13,0x27,0x36,0x31,0x0a,0x07,0x18,0x2b,0x01,0x34,0x23,0x21,0x22,0x06,0x0f,0x01,0x06,0x15,0x14,0x33,0x21,0x32,0x36,0x3f,0x01,0x36,0x25,0x21,0x35,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06, +0x15,0x11,0x37,0x3e,0x01,0x05,0x14,0x0f,0x01,0x0e,0x01,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x17,0x15,0x33,0x32,0x16,0x17,0x16,0x03,0xe2,0x1e,0xfd,0xa1,0x16,0x34,0x0d,0xa4,0x0b,0x1e,0x02,0x5f,0x17,0x32,0x0f,0xa4,0x0a,0xfd,0x83,0x01,0xad,0x20,0x16,0xfe,0xbf,0x17,0x1e,0x01, +0x1e,0x17,0xb3,0x16,0x20,0x8f,0x19,0x50,0x02,0xea,0x19,0xa5,0x18,0x52,0x25,0xfd,0xa1,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x2f,0x34,0x48,0x01,0x6b,0x1e,0x34,0x0b,0x08,0x01,0x4b,0x13,0x18,0x11,0xcb,0x0d,0x09,0x14,0x1a,0x10,0xcb,0x0c,0x64,0x5a,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfe,0x24,0xaf,0x1e, +0x26,0x5a,0x23,0x20,0xcb,0x1e,0x26,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33,0x12,0x4a,0x33,0x5a,0x1a,0x1b,0x11,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xf9,0x03,0xa1,0x03,0x0b,0x00,0x17,0x00,0x2c,0x00,0x26,0x40,0x23,0x00,0x05,0x00,0x00,0x02,0x05,0x00,0x67,0x00,0x02,0x00,0x03,0x02,0x03,0x63,0x00,0x01,0x01,0x04,0x5f,0x00,0x04, +0x04,0x13,0x01,0x4e,0x23,0x35,0x35,0x35,0x35,0x33,0x06,0x07,0x1c,0x2b,0x25,0x11,0x34,0x26,0x07,0x21,0x22,0x26,0x27,0x35,0x34,0x26,0x07,0x23,0x22,0x06,0x15,0x11,0x14,0x16,0x33,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x1d,0x01,0x21,0x32,0x16,0x03,0x59,0x1e,0x17,0xfe, +0x77,0x17,0x1e,0x01,0x1e,0x17,0xb3,0x16,0x20,0x20,0x16,0x02,0xa7,0x16,0x20,0x47,0x4a,0x33,0xfd,0x59,0x33,0x4a,0x4a,0x33,0xb3,0x33,0x4a,0x01,0x77,0x33,0x4a,0x76,0x01,0x89,0x16,0x20,0x01,0x20,0x16,0x24,0x16,0x20,0x01,0x1e,0x17,0xfd,0xe8,0x16,0x20,0x20,0x01,0x9f,0xfe,0x77,0x33,0x4a,0x4a,0x33,0x02,0x18,0x33,0x4a,0x4a,0x33, +0x12,0x4a,0x00,0x00,0x00,0x04,0x00,0x00,0xff,0xb8,0x03,0x94,0x03,0x1f,0x00,0x02,0x00,0x10,0x00,0x39,0x00,0x66,0x01,0x0d,0x40,0x0b,0x60,0x33,0x02,0x07,0x06,0x01,0x01,0x02,0x07,0x02,0x4c,0x4b,0xb0,0x13,0x50,0x58,0x40,0x38,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02, +0x06,0x07,0x69,0x0b,0x08,0x12,0x04,0x11,0x05,0x00,0x01,0x09,0x00,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x3f,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80,0x12,0x04,0x11,0x03,0x00,0x08,0x01,0x08,0x00,0x01,0x80,0x00, +0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x1b,0x40,0x45,0x00,0x02,0x07,0x09,0x07,0x02,0x09,0x80,0x11,0x01,0x00,0x08,0x04,0x08,0x00,0x04,0x80,0x12, +0x01,0x04,0x01,0x08,0x04,0x01,0x7e,0x00,0x03,0x01,0x03,0x86,0x0d,0x01,0x06,0x0c,0x01,0x07,0x02,0x06,0x07,0x69,0x0b,0x01,0x08,0x00,0x09,0x08,0x59,0x10,0x01,0x09,0x00,0x01,0x03,0x09,0x01,0x67,0x0f,0x01,0x0a,0x0a,0x05,0x61,0x0e,0x01,0x05,0x05,0x10,0x0a,0x4e,0x59,0x59,0x40,0x2d,0x03,0x03,0x00,0x00,0x66,0x64,0x5c,0x5a,0x59, +0x57,0x4a,0x48,0x47,0x45,0x3c,0x3a,0x39,0x37,0x2f,0x2d,0x2c,0x2a,0x20,0x1e,0x1d,0x1b,0x13,0x11,0x03,0x10,0x03,0x10,0x0d,0x0a,0x07,0x06,0x05,0x04,0x00,0x02,0x00,0x02,0x13,0x07,0x16,0x2b,0x25,0x37,0x17,0x07,0x15,0x21,0x35,0x23,0x15,0x14,0x16,0x33,0x21,0x32,0x36,0x3d,0x01,0x01,0x33,0x32,0x16,0x1d,0x01,0x14,0x17,0x1e,0x02, +0x3b,0x01,0x15,0x23,0x22,0x0e,0x02,0x1d,0x01,0x14,0x07,0x0e,0x02,0x2b,0x01,0x35,0x33,0x32,0x3d,0x01,0x34,0x37,0x26,0x3d,0x01,0x34,0x2b,0x01,0x03,0x23,0x22,0x26,0x3d,0x01,0x34,0x27,0x26,0x27,0x2e,0x01,0x2b,0x01,0x35,0x33,0x32,0x3e,0x01,0x37,0x36,0x3d,0x01,0x34,0x37,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x15,0x23,0x22,0x1d, +0x01,0x14,0x07,0x16,0x1d,0x01,0x14,0x3b,0x01,0x02,0xcd,0x64,0x63,0x82,0xfe,0xa7,0x3e,0x12,0x0d,0x01,0x97,0x0d,0x13,0xfe,0xa0,0x1c,0x47,0x44,0x04,0x05,0x11,0x25,0x18,0x10,0x10,0x1c,0x20,0x14,0x07,0x07,0x07,0x22,0x35,0x26,0x1c,0x16,0x55,0x4d,0x4e,0x54,0x16,0xa7,0x1b,0x48,0x44,0x04,0x05,0x09,0x0a,0x23,0x18,0x0f,0x0f,0x1d, +0x20,0x13,0x03,0x04,0x07,0x08,0x10,0x10,0x1b,0x1b,0x27,0x1b,0x16,0x55,0x4d,0x4e,0x54,0x16,0x6a,0xac,0xac,0x09,0x6a,0xb3,0xd3,0x0d,0x12,0x12,0x0d,0x8a,0x02,0xbe,0x42,0x44,0x54,0x14,0x0c,0x10,0x10,0x0c,0x33,0x08,0x14,0x19,0x15,0x80,0x21,0x16,0x19,0x23,0x12,0x33,0x52,0x7f,0x59,0x0b,0x09,0x5c,0x54,0x54,0xfd,0x8b,0x42,0x43, +0x7e,0x14,0x0c,0x10,0x08,0x0b,0x09,0x33,0x09,0x12,0x0e,0x0c,0x15,0x56,0x1a,0x1e,0x18,0x12,0x10,0x0b,0x09,0x33,0x53,0x55,0x59,0x0c,0x07,0x5d,0x7d,0x54,0x00,0x00,0x00,0x03,0xff,0xfe,0x00,0x00,0x03,0xe8,0x02,0x60,0x00,0x20,0x00,0x24,0x00,0x28,0x00,0x36,0x40,0x33,0x00,0x00,0x08,0x06,0x07,0x03,0x04,0x03,0x00,0x04,0x67,0x05, +0x01,0x03,0x01,0x01,0x03,0x57,0x05,0x01,0x03,0x03,0x01,0x5f,0x02,0x01,0x01,0x03,0x01,0x4f,0x25,0x25,0x21,0x21,0x25,0x28,0x25,0x28,0x27,0x26,0x21,0x24,0x21,0x24,0x14,0x27,0x2a,0x18,0x09,0x07,0x1a,0x2b,0x11,0x26,0x37,0x25,0x36,0x17,0x16,0x0f,0x01,0x21,0x27,0x26,0x37,0x36,0x17,0x05,0x16,0x07,0x03,0x06,0x23,0x21,0x26,0x2f, +0x01,0x26,0x0f,0x01,0x06,0x23,0x21,0x26,0x27,0x37,0x17,0x21,0x37,0x33,0x17,0x21,0x37,0x02,0x0a,0x01,0x68,0x1d,0x0c,0x0b,0x19,0xe3,0x02,0x92,0xe4,0x19,0x0b,0x0e,0x1d,0x01,0x6a,0x0b,0x02,0x1b,0x08,0x19,0xfe,0xc7,0x19,0x06,0x31,0x27,0x35,0x32,0x06,0x1a,0xfe,0xc8,0x1b,0x04,0x27,0x13,0x01,0x04,0x2b,0xdd,0x29,0x01,0x03,0x14, +0x01,0x82,0x0d,0x0c,0xba,0x0b,0x1b,0x21,0x0c,0x68,0x68,0x10,0x1d,0x1b,0x0b,0xba,0x0c,0x0d,0xff,0x00,0x1e,0x02,0x18,0xdf,0x19,0x18,0xe0,0x1a,0x02,0x1c,0xe2,0xbd,0xbd,0xbd,0xbd,0x00,0x00,0x03,0x00,0x00,0xff,0x6a,0x03,0x59,0x03,0x52,0x00,0x13,0x00,0x1a,0x00,0x23,0x00,0x39,0x40,0x36,0x14,0x01,0x02,0x04,0x01,0x4c,0x00,0x01, +0x00,0x04,0x02,0x01,0x04,0x67,0x00,0x02,0x00,0x03,0x05,0x02,0x03,0x67,0x06,0x01,0x05,0x00,0x00,0x05,0x57,0x06,0x01,0x05,0x05,0x00,0x5f,0x00,0x00,0x05,0x00,0x4f,0x1b,0x1b,0x1b,0x23,0x1b,0x23,0x13,0x26,0x14,0x35,0x36,0x07,0x07,0x1b,0x2b,0x01,0x1e,0x01,0x15,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x37,0x21, +0x32,0x16,0x17,0x07,0x15,0x33,0x26,0x2f,0x01,0x26,0x13,0x11,0x23,0x22,0x26,0x27,0x35,0x21,0x11,0x03,0x33,0x10,0x16,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x01,0xf4,0x16,0x36,0x0f,0x4a,0xd2,0x05,0x07,0xaf,0x06,0xc6,0xe8,0x17,0x1e,0x01,0xfe,0x53,0x02,0x7e,0x10,0x34,0x18,0xfd,0x7e,0x17,0x1e,0x01,0x20,0x16,0x03,0x7c, +0x17,0x1e,0x01,0x16,0x10,0x26,0xd2,0x11,0x06,0xaf,0x07,0xfc,0xb0,0x02,0x3c,0x20,0x15,0xe9,0xfc,0xa6,0x00,0x01,0x00,0x00,0xff,0xaa,0x03,0x11,0x03,0x13,0x00,0x0b,0x00,0x06,0xb3,0x07,0x02,0x01,0x32,0x2b,0x09,0x01,0x06,0x26,0x35,0x11,0x34,0x36,0x17,0x01,0x16,0x14,0x03,0x04,0xfd,0x1b,0x0d,0x12,0x12,0x0d,0x02,0xe5,0x0d,0x01, +0x4d,0xfe,0x64,0x07,0x0a,0x0f,0x03,0x36,0x0e,0x0c,0x08,0xfe,0x64,0x07,0x14,0x00,0x00,0x01,0xff,0xff,0xff,0xae,0x02,0x3c,0x03,0x0f,0x00,0x1d,0x00,0x1b,0x40,0x18,0x1b,0x1a,0x12,0x03,0x01,0x00,0x01,0x4c,0x00,0x00,0x00,0x13,0x4d,0x00,0x01,0x01,0x11,0x01,0x4e,0x35,0x3d,0x02,0x07,0x18,0x2b,0x17,0x06,0x26,0x37,0x11,0x34,0x36, +0x17,0x01,0x16,0x17,0x11,0x34,0x36,0x3b,0x01,0x32,0x16,0x07,0x11,0x14,0x06,0x2b,0x01,0x22,0x26,0x37,0x11,0x06,0x07,0x19,0x0a,0x10,0x01,0x0e,0x0b,0x01,0x8c,0x05,0x03,0x14,0x0f,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48,0x0e,0x16,0x01,0x03,0x05,0x47,0x0b,0x06,0x0f,0x03,0x36,0x0e,0x08,0x0c,0xfe,0x74,0x05,0x05,0x01,0x7a,0x0e,0x16, +0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x01,0x7b,0x06,0x05,0x00,0x03,0xff,0xfc,0xff,0x90,0x03,0x9a,0x03,0x2c,0x00,0x08,0x00,0x13,0x00,0x29,0x00,0xa7,0x40,0x0d,0x0c,0x01,0x03,0x02,0x23,0x22,0x18,0x17,0x04,0x05,0x07,0x02,0x4c,0x4b,0xb0,0x24,0x50,0x58,0x40,0x32,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02, +0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00,0x05,0x04,0x02,0x05,0x04,0x7e,0x0a,0x01,0x04,0x00,0x01,0x04,0x01,0x66,0x09,0x01,0x02,0x02,0x00,0x61,0x08,0x01,0x00,0x00,0x12,0x02,0x4e,0x1b,0x40,0x39,0x00,0x03,0x02,0x06,0x02,0x03,0x06,0x80,0x00,0x06,0x07,0x02,0x06,0x07,0x7e,0x00,0x07,0x05,0x02,0x07,0x05,0x7e,0x00, +0x05,0x04,0x02,0x05,0x04,0x7e,0x08,0x01,0x00,0x09,0x01,0x02,0x03,0x00,0x02,0x69,0x0a,0x01,0x04,0x01,0x01,0x04,0x59,0x0a,0x01,0x04,0x04,0x01,0x62,0x00,0x01,0x04,0x01,0x52,0x59,0x40,0x1f,0x15,0x14,0x0a,0x09,0x01,0x00,0x26,0x24,0x20,0x1e,0x1b,0x19,0x14,0x29,0x15,0x29,0x10,0x0e,0x09,0x13,0x0a,0x13,0x05,0x04,0x00,0x08,0x01, +0x08,0x0b,0x07,0x16,0x2b,0x01,0x36,0x00,0x12,0x00,0x04,0x00,0x02,0x00,0x17,0x22,0x06,0x15,0x06,0x16,0x33,0x32,0x36,0x35,0x34,0x03,0x32,0x36,0x37,0x27,0x06,0x23,0x22,0x3f,0x01,0x36,0x23,0x22,0x06,0x07,0x17,0x36,0x33,0x32,0x0f,0x01,0x06,0x01,0xc6,0xbe,0x01,0x10,0x06,0xfe,0xf6,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0c,0xf2,0x2a, +0x2e,0x02,0x22,0x20,0x26,0x2e,0xb4,0x1e,0x6c,0x34,0x12,0x30,0x18,0x0e,0x0a,0x2a,0x1a,0x30,0x1e,0x76,0x38,0x10,0x34,0x16,0x0c,0x0c,0x24,0x1a,0x03,0x2a,0x02,0xfe,0xf8,0xfe,0x84,0xfe,0xee,0x06,0x01,0x0a,0x01,0x7c,0x01,0x12,0x96,0x30,0x1a,0x1c,0x20,0x2c,0x20,0x3a,0xfd,0xae,0x34,0x34,0x18,0x24,0x26,0xa0,0x60,0x3a,0x2e,0x1a, +0x22,0x22,0x98,0x68,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x31,0x00,0x3b,0x40,0x38,0x2a,0x01,0x03,0x05,0x25,0x1d,0x02,0x04,0x03,0x02,0x4c,0x00,0x04,0x03,0x01,0x03,0x04,0x01,0x80,0x00,0x01,0x02,0x03,0x01,0x02,0x7e,0x00,0x03,0x03,0x05,0x61,0x00,0x05,0x05,0x13,0x4d,0x00,0x02,0x02,0x00,0x61,0x00,0x00,0x00, +0x11,0x00,0x4e,0x29,0x35,0x17,0x23,0x17,0x24,0x06,0x07,0x1c,0x2b,0x01,0x14,0x0e,0x02,0x23,0x22,0x26,0x27,0x26,0x34,0x3f,0x01,0x36,0x16,0x17,0x1e,0x01,0x33,0x32,0x3e,0x03,0x2e,0x02,0x22,0x06,0x07,0x17,0x16,0x06,0x2b,0x01,0x22,0x26,0x27,0x35,0x34,0x36,0x1f,0x01,0x3e,0x01,0x33,0x32,0x1e,0x02,0x03,0x59,0x44,0x72,0xa0,0x56, +0x60,0xae,0x3c,0x04,0x05,0x4c,0x06,0x11,0x04,0x29,0x76,0x43,0x3a,0x68,0x50,0x2a,0x02,0x2e,0x4c,0x6c,0x6f,0x64,0x28,0x4d,0x11,0x13,0x17,0xfa,0x0f,0x14,0x01,0x2c,0x11,0x48,0x3c,0x9a,0x52,0x57,0x9e,0x74,0x42,0x01,0x5e,0x57,0x9e,0x74,0x44,0x52,0x49,0x06,0x0e,0x04,0x4d,0x05,0x01,0x06,0x35,0x3a,0x2e,0x4c,0x6a,0x74,0x6a,0x4c, +0x2e,0x28,0x25,0x4d,0x10,0x2d,0x16,0x0e,0xfa,0x18,0x13,0x12,0x48,0x39,0x3e,0x44,0x74,0x9e,0x00,0x00,0x00,0x01,0x00,0x00,0xff,0xf9,0x02,0x83,0x03,0x53,0x00,0x23,0x00,0x3a,0x40,0x37,0x00,0x04,0x05,0x00,0x05,0x04,0x00,0x80,0x00,0x03,0x00,0x05,0x04,0x03,0x05,0x69,0x02,0x06,0x02,0x00,0x01,0x01,0x00,0x59,0x02,0x06,0x02,0x00, +0x00,0x01,0x5f,0x00,0x01,0x00,0x01,0x4f,0x01,0x00,0x20,0x1f,0x1b,0x18,0x14,0x13,0x10,0x0e,0x09,0x06,0x00,0x23,0x01,0x23,0x07,0x07,0x16,0x2b,0x01,0x32,0x16,0x17,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x17,0x33,0x35,0x34,0x36,0x1e,0x01,0x07,0x14,0x06,0x2b,0x01,0x22,0x26,0x35,0x34,0x26,0x22,0x06,0x17,0x15, +0x02,0x4d,0x17,0x1e,0x01,0x20,0x16,0xfd,0xe9,0x17,0x1e,0x01,0x20,0x16,0x11,0x94,0xcc,0x96,0x02,0x14,0x0f,0x24,0x0e,0x16,0x54,0x76,0x54,0x01,0x01,0xa5,0x1e,0x17,0xfe,0xbe,0x16,0x1e,0x01,0x20,0x15,0x01,0x42,0x16,0x20,0x01,0xb3,0x67,0x94,0x02,0x90,0x69,0x0e,0x16,0x16,0x0e,0x3b,0x54,0x54,0x3b,0xb3,0x00,0x00,0x08,0x00,0x00, +0xff,0x9f,0x03,0x8f,0x03,0x1d,0x00,0x04,0x00,0x09,0x00,0x0e,0x00,0x13,0x00,0x1b,0x00,0x23,0x00,0x2b,0x00,0x33,0x00,0x41,0x40,0x3e,0x21,0x20,0x15,0x14,0x0e,0x01,0x06,0x00,0x4a,0x31,0x30,0x25,0x24,0x10,0x09,0x06,0x01,0x49,0x05,0x04,0x02,0x08,0x04,0x00,0x01,0x00,0x85,0x07,0x06,0x09,0x03,0x04,0x01,0x01,0x76,0x0f,0x0f,0x00, +0x00,0x2d,0x2c,0x29,0x28,0x1d,0x1c,0x19,0x18,0x0f,0x13,0x0f,0x13,0x0b,0x0a,0x06,0x05,0x00,0x04,0x00,0x04,0x0a,0x07,0x16,0x2b,0x01,0x35,0x1e,0x01,0x17,0x07,0x33,0x0e,0x01,0x07,0x03,0x23,0x3e,0x01,0x37,0x11,0x15,0x2e,0x01,0x27,0x01,0x35,0x1e,0x01,0x17,0x23,0x2e,0x01,0x01,0x23,0x3e,0x01,0x37,0x15,0x0e,0x01,0x01,0x15,0x2e, +0x01,0x27,0x33,0x1e,0x01,0x01,0x33,0x0e,0x01,0x07,0x35,0x3e,0x01,0x02,0x09,0x3c,0x56,0x10,0xa2,0xa2,0x10,0x56,0x3c,0x71,0xa2,0x10,0x56,0x3c,0x3c,0x56,0x10,0x01,0x13,0x98,0xda,0x14,0x71,0x12,0x9a,0xfe,0x11,0x71,0x13,0xda,0x99,0x6a,0x98,0x01,0x02,0x9a,0xd8,0x14,0x71,0x12,0x9a,0x01,0xef,0x71,0x15,0xd8,0x99,0x69,0x9a,0x01, +0x97,0xa2,0x10,0x58,0x3a,0x71,0x3b,0x58,0x0f,0x01,0x13,0x3b,0x56,0x11,0xfe,0xed,0xa2,0x10,0x56,0x3c,0x01,0x86,0x71,0x13,0xda,0x99,0x6b,0x98,0xfe,0xfd,0x98,0xda,0x14,0x71,0x12,0x98,0xfe,0x0f,0x72,0x13,0xdc,0x98,0x6b,0x98,0x01,0x03,0x99,0xda,0x14,0x72,0x12,0x98,0x00,0x04,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x03, +0x00,0x21,0x00,0x31,0x00,0x45,0x00,0x53,0x40,0x50,0x2b,0x2a,0x23,0x22,0x04,0x08,0x04,0x01,0x4c,0x0d,0x01,0x04,0x06,0x01,0x08,0x02,0x4b,0x00,0x08,0x04,0x03,0x04,0x08,0x03,0x80,0x00,0x03,0x06,0x04,0x03,0x06,0x7e,0x00,0x06,0x00,0x01,0x00,0x06,0x01,0x68,0x07,0x01,0x04,0x04,0x0a,0x5f,0x00,0x0a,0x0a,0x13,0x4d,0x05,0x02,0x02, +0x00,0x00,0x09,0x5f,0x00,0x09,0x09,0x11,0x09,0x4e,0x40,0x3d,0x38,0x35,0x17,0x26,0x33,0x11,0x13,0x3b,0x11,0x11,0x10,0x0b,0x07,0x1f,0x2b,0x17,0x21,0x35,0x21,0x05,0x33,0x11,0x34,0x26,0x2f,0x01,0x2e,0x01,0x07,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x35,0x23,0x11,0x33,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x07,0x03,0x35,0x34, +0x26,0x2b,0x01,0x22,0x06,0x17,0x15,0x14,0x16,0x37,0x33,0x32,0x36,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x1f,0x01,0x1e,0x01,0xd6,0x01,0xad,0xfe,0x53,0x01,0xf4,0x48,0x0c,0x05,0x9d,0x05,0x1c,0x08,0x1e,0x17,0xfe,0xbe,0x16,0x1e,0x01,0x48,0x48,0x20,0x15,0x01,0xd1,0x16,0x20,0x01,0xd6, +0x0a,0x08,0x6b,0x07,0x0c,0x01,0x0a,0x08,0x6b,0x07,0x0c,0x01,0x64,0x1e,0x17,0xfd,0x12,0x17,0x1e,0x01,0x20,0x16,0x02,0x05,0x17,0x36,0x0f,0x9c,0x10,0x16,0x07,0xd6,0xd6,0x01,0xf4,0x08,0x1a,0x07,0x9c,0x06,0x0c,0x01,0xe8,0x16,0x20,0x20,0x16,0xe8,0xfd,0x36,0xe8,0x16,0x20,0x20,0x16,0x01,0x1e,0xb2,0x08,0x0a,0x0a,0x08,0xb2,0x07, +0x0c,0x01,0x0a,0x0a,0xfd,0xfa,0x16,0x20,0x20,0x16,0x02,0xee,0x16,0x20,0x18,0x0e,0x9d,0x0f,0x36,0x00,0x00,0x02,0xff,0xff,0xff,0xb1,0x03,0xe8,0x03,0x0b,0x00,0x03,0x00,0x13,0x00,0x1f,0x40,0x1c,0x00,0x01,0x01,0x03,0x5f,0x00,0x03,0x03,0x13,0x4d,0x00,0x00,0x00,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x35,0x34,0x11,0x10,0x04, +0x07,0x1a,0x2b,0x37,0x21,0x11,0x21,0x25,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x37,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x8f,0x02,0xca,0xfd,0x36,0x03,0x59,0x34,0x25,0xfc,0xca,0x24,0x36,0x01,0x34,0x25,0x03,0x36,0x25,0x34,0x40,0x01,0xad,0xc4,0xfd,0x5a,0x25,0x34,0x01,0x36,0x24,0x02,0xa6,0x25,0x34,0x01,0x36,0x00,0x03,0xff,0xfd, +0xff,0xb1,0x03,0x5f,0x03,0x0b,0x00,0x08,0x00,0x15,0x00,0x22,0x00,0x32,0x40,0x2f,0x00,0x01,0x00,0x00,0x03,0x01,0x00,0x69,0x06,0x01,0x02,0x02,0x05,0x61,0x00,0x05,0x05,0x13,0x4d,0x00,0x03,0x03,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x0a,0x09,0x20,0x1f,0x1a,0x19,0x10,0x0f,0x09,0x15,0x0a,0x15,0x13,0x12,0x07,0x07,0x18,0x2b, +0x01,0x14,0x06,0x22,0x2e,0x01,0x36,0x32,0x16,0x27,0x22,0x0e,0x02,0x1e,0x01,0x32,0x3e,0x01,0x2e,0x02,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x32,0x1e,0x01,0x02,0x3b,0x52,0x78,0x52,0x02,0x56,0x74,0x56,0x90,0x53,0x8c,0x50,0x02,0x54,0x88,0xaa,0x86,0x56,0x04,0x4e,0x8e,0x01,0x5b,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc, +0xf4,0xba,0x7e,0x01,0x5e,0x3b,0x54,0x54,0x76,0x54,0x54,0xf5,0x52,0x8c,0xa4,0x8c,0x52,0x52,0x8c,0xa4,0x8c,0x52,0xfe,0xd0,0x75,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0x6a,0x02,0x83,0x03,0x0b,0x00,0x0b,0x00,0x2e,0x00,0x35,0x40,0x32,0x07,0x01,0x02,0x01,0x00,0x01,0x4c,0x00,0x03,0x02, +0x03,0x86,0x09,0x05,0x02,0x01,0x04,0x01,0x02,0x03,0x01,0x02,0x67,0x08,0x06,0x02,0x00,0x00,0x07,0x5f,0x00,0x07,0x07,0x13,0x00,0x4e,0x2d,0x2c,0x13,0x33,0x11,0x14,0x22,0x33,0x15,0x15,0x13,0x0a,0x07,0x1f,0x2b,0x01,0x35,0x34,0x26,0x22,0x06,0x1d,0x01,0x14,0x16,0x32,0x36,0x05,0x14,0x06,0x27,0x23,0x03,0x0e,0x01,0x07,0x23,0x22, +0x27,0x03,0x23,0x22,0x26,0x27,0x34,0x36,0x33,0x11,0x22,0x2e,0x01,0x36,0x37,0x21,0x32,0x16,0x14,0x06,0x27,0x11,0x32,0x16,0x01,0x0c,0x0a,0x10,0x0a,0x0a,0x10,0x0a,0x01,0x77,0x16,0x0e,0xef,0x1d,0x01,0x0a,0x06,0x01,0x0f,0x02,0x2b,0xe1,0x0f,0x14,0x01,0x58,0x37,0x1d,0x2a,0x02,0x2e,0x1b,0x01,0x65,0x1d,0x2a,0x2a,0x1d,0x37,0x58, +0x01,0x70,0xfa,0x08,0x0a,0x0a,0x08,0xfa,0x08,0x0a,0x0a,0xbd,0x0e,0x16,0x01,0xfe,0xf2,0x07,0x08,0x01,0x0f,0x01,0x0f,0x14,0x0f,0x45,0x6e,0x01,0x1e,0x2a,0x3a,0x2a,0x01,0x2c,0x38,0x2c,0x01,0xfe,0xe2,0x6e,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5b,0x03,0x0b,0x00,0x24,0x00,0x47,0x00,0x4b,0x40,0x48,0x43,0x25,0x02,0x06,0x09,0x2f, +0x01,0x05,0x06,0x17,0x01,0x03,0x02,0x08,0x01,0x01,0x03,0x04,0x4c,0x00,0x09,0x07,0x01,0x05,0x02,0x09,0x05,0x67,0x04,0x01,0x02,0x00,0x01,0x00,0x02,0x01,0x69,0x00,0x06,0x06,0x08,0x61,0x00,0x08,0x08,0x13,0x4d,0x00,0x03,0x03,0x00,0x61,0x00,0x00,0x00,0x11,0x00,0x4e,0x46,0x45,0x26,0x25,0x25,0x36,0x25,0x26,0x35,0x14,0x24,0x0a, +0x07,0x1f,0x2b,0x01,0x14,0x15,0x0e,0x01,0x23,0x22,0x26,0x27,0x07,0x06,0x22,0x26,0x3d,0x01,0x34,0x36,0x3b,0x01,0x32,0x16,0x06,0x0f,0x01,0x1e,0x01,0x37,0x32,0x36,0x37,0x36,0x37,0x36,0x3b,0x01,0x32,0x16,0x13,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x36,0x3f,0x01,0x26,0x23,0x22,0x06,0x07,0x06,0x07,0x06,0x2b,0x01,0x22,0x26,0x37, +0x35,0x3e,0x01,0x33,0x32,0x16,0x17,0x37,0x36,0x32,0x16,0x03,0x4b,0x24,0xe4,0x99,0x51,0x98,0x3c,0x48,0x0b,0x1c,0x16,0x16,0x0e,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x28,0x64,0x37,0x4a,0x82,0x27,0x06,0x18,0x04,0x0c,0x6b,0x08,0x0a,0x0e,0x14,0x10,0xfa,0x0e,0x16,0x02,0x09,0x4d,0x52,0x70,0x4b,0x82,0x27,0x06,0x17,0x05,0x0c,0x6f,0x07, +0x0c,0x01,0x24,0xe6,0x99,0x51,0x9a,0x3c,0x48,0x0b,0x1c,0x18,0x01,0x05,0x03,0x01,0x96,0xba,0x3e,0x39,0x48,0x0b,0x16,0x0e,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x24,0x2a,0x01,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x01,0xb8,0xfa,0x0e,0x16,0x16,0x1c,0x0b,0x4d,0x4d,0x4a,0x3e,0x0a,0x38,0x0d,0x0c,0x06,0x04,0x96,0xba,0x3e,0x39,0x48,0x0b, +0x16,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x20,0x40,0x1d,0x18,0x10,0x08,0x00,0x04,0x00,0x01,0x01,0x4c,0x03,0x01,0x01,0x01,0x13,0x4d,0x02,0x01,0x00,0x00,0x11,0x00,0x4e,0x35,0x35,0x35,0x33,0x04,0x07,0x1a,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36, +0x33,0x21,0x32,0x16,0x05,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0xfe,0x0b,0x14,0x10,0xfe,0xe3,0x0f,0x14,0x01,0x16,0x0e,0x01,0x1d,0x0f,0x16,0x02,0xe7,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x0e, +0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x00,0x01,0x00,0x00,0xff,0xb1,0x03,0x5a,0x03,0x0b,0x00,0x0f,0x00,0x1a,0x40,0x17,0x08,0x00,0x02,0x00,0x01,0x01,0x4c,0x00,0x01,0x01,0x13,0x4d,0x00,0x00,0x00,0x11,0x00,0x4e,0x35,0x33,0x02,0x07,0x18,0x2b,0x01,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x27,0x11,0x34,0x36, +0x33,0x21,0x32,0x16,0x03,0x59,0x14,0x10,0xfc,0xef,0x0f,0x14,0x01,0x16,0x0e,0x03,0x11,0x0f,0x16,0x02,0xe7,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x16,0x00,0x01,0xff,0xfe,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x30,0x00,0x3a,0x40,0x37,0x2d,0x01,0x01,0x05,0x09,0x01,0x00,0x01,0x02,0x4c,0x00,0x00,0x01,0x03,0x01,0x00, +0x03,0x80,0x00,0x03,0x02,0x01,0x03,0x02,0x7e,0x00,0x01,0x01,0x05,0x61,0x00,0x05,0x05,0x13,0x4d,0x00,0x02,0x02,0x04,0x61,0x00,0x04,0x04,0x11,0x04,0x4e,0x27,0x27,0x13,0x27,0x24,0x33,0x06,0x07,0x1c,0x2b,0x01,0x15,0x14,0x06,0x2b,0x01,0x22,0x26,0x3f,0x01,0x26,0x23,0x22,0x0e,0x02,0x14,0x1e,0x02,0x33,0x32,0x36,0x37,0x3e,0x01, +0x1f,0x01,0x1e,0x01,0x07,0x0e,0x01,0x07,0x22,0x2e,0x02,0x3e,0x03,0x33,0x32,0x16,0x17,0x37,0x36,0x16,0x03,0x59,0x14,0x10,0xfa,0x17,0x13,0x11,0x4d,0x52,0x70,0x3a,0x6a,0x4c,0x2e,0x2e,0x4c,0x6a,0x3a,0x42,0x76,0x29,0x04,0x11,0x06,0x4c,0x05,0x02,0x06,0x3c,0xae,0x5f,0x57,0xa0,0x70,0x48,0x04,0x40,0x78,0x98,0x5b,0x52,0x98,0x3d, +0x48,0x11,0x2c,0x02,0xc3,0xfa,0x0e,0x16,0x2d,0x10,0x4d,0x4d,0x2e,0x4c,0x6a,0x74,0x6a,0x4c,0x2e,0x3a,0x35,0x06,0x01,0x05,0x4d,0x04,0x0e,0x06,0x4a,0x50,0x01,0x44,0x74,0x9e,0xae,0x9e,0x74,0x44,0x3e,0x39,0x48,0x12,0x13,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0x58,0x01,0xe6,0x00,0x15,0x00,0x19,0x40,0x16,0x0f,0x01,0x00,0x01, +0x01,0x4c,0x02,0x01,0x01,0x00,0x01,0x85,0x00,0x00,0x00,0x76,0x14,0x17,0x14,0x03,0x07,0x19,0x2b,0x01,0x14,0x07,0x01,0x06,0x22,0x27,0x01,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37,0x36,0x32,0x1f,0x01,0x16,0x02,0x58,0x06,0xfe,0xfc,0x05,0x10,0x04,0xfe,0xfc,0x06,0x06,0x1c,0x05,0x0e,0x06,0xdb,0xdc,0x05,0x10,0x04,0x1c,0x06, +0x01,0xb7,0x07,0x05,0xfe,0xfb,0x05,0x05,0x01,0x05,0x05,0x0e,0x06,0x1c,0x06,0x06,0xdb,0xdb,0x06,0x06,0x1c,0x05,0x00,0x00,0x00,0x03,0xff,0xfd,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0c,0x00,0x1c,0x00,0x2e,0x00,0x41,0x40,0x3e,0x28,0x1e,0x02,0x05,0x04,0x16,0x15,0x0e,0x03,0x03,0x02,0x02,0x4c,0x00,0x05,0x00,0x02,0x03,0x05,0x02, +0x67,0x00,0x04,0x04,0x00,0x61,0x06,0x01,0x00,0x00,0x13,0x4d,0x00,0x03,0x03,0x01,0x61,0x00,0x01,0x01,0x11,0x01,0x4e,0x01,0x00,0x2c,0x2a,0x23,0x21,0x1a,0x18,0x12,0x10,0x07,0x06,0x00,0x0c,0x01,0x0c,0x07,0x07,0x16,0x2b,0x01,0x32,0x1e,0x01,0x14,0x0e,0x01,0x22,0x2e,0x02,0x3e,0x01,0x13,0x35,0x34,0x26,0x2b,0x01,0x22,0x06,0x07, +0x15,0x14,0x16,0x17,0x33,0x32,0x36,0x27,0x13,0x34,0x27,0x26,0x2b,0x01,0x22,0x07,0x06,0x15,0x13,0x14,0x16,0x3b,0x01,0x32,0x36,0x01,0xad,0x74,0xc6,0x72,0x72,0xc6,0xe8,0xc8,0x6e,0x06,0x7a,0xbc,0xc1,0x0a,0x07,0x6b,0x08,0x0a,0x01,0x0c,0x07,0x6b,0x07,0x0a,0x01,0x0a,0x06,0x05,0x08,0x7b,0x08,0x05,0x06,0x0a,0x0a,0x09,0x67,0x08, +0x0a,0x03,0x0b,0x74,0xc4,0xea,0xc4,0x74,0x74,0xc4,0xea,0xc4,0x74,0xfd,0x48,0x6a,0x08,0x0a,0x0a,0x08,0x6a,0x08,0x0a,0x01,0x0c,0xc7,0x01,0x5a,0x07,0x03,0x05,0x05,0x03,0x07,0xfe,0xa6,0x06,0x08,0x08,0x00,0x00,0x01,0x00,0x00,0xff,0xef,0x02,0xd4,0x02,0x86,0x00,0x24,0x00,0x26,0x40,0x23,0x22,0x19,0x10,0x07,0x04,0x00,0x02,0x01, +0x4c,0x03,0x01,0x02,0x00,0x00,0x02,0x59,0x03,0x01,0x02,0x02,0x00,0x61,0x01,0x01,0x00,0x02,0x00,0x51,0x14,0x1c,0x14,0x14,0x04,0x07,0x1a,0x2b,0x25,0x14,0x0f,0x01,0x06,0x22,0x2f,0x01,0x07,0x06,0x22,0x2f,0x01,0x26,0x34,0x3f,0x01,0x27,0x26,0x34,0x3f,0x01,0x36,0x32,0x1f,0x01,0x37,0x36,0x32,0x1f,0x01,0x16,0x14,0x0f,0x01,0x17, +0x16,0x02,0xd4,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10,0x10,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x0f,0x0f,0xa4,0xa4,0x0f,0x70,0x16,0x10,0x4c,0x0f,0x0f,0xa5,0xa5,0x0f,0x0f,0x4c,0x10,0x2c,0x10,0xa4,0xa4,0x10,0x2c,0x10,0x4c,0x10,0x10,0xa4,0xa4,0x10,0x10,0x4c,0x0f,0x2e, +0x0f,0xa4,0xa4,0x0f,0x00,0x03,0x00,0x00,0xff,0xb1,0x03,0xc5,0x03,0x0b,0x00,0x0c,0x00,0x1c,0x00,0x2c,0x00,0x34,0x40,0x31,0x25,0x1d,0x02,0x04,0x05,0x00,0x01,0x01,0x00,0x02,0x4c,0x00,0x03,0x00,0x00,0x01,0x03,0x00,0x67,0x00,0x04,0x04,0x05,0x5f,0x00,0x05,0x05,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e, +0x35,0x35,0x35,0x35,0x24,0x32,0x06,0x07,0x1c,0x2b,0x01,0x34,0x26,0x07,0x23,0x22,0x0e,0x01,0x16,0x17,0x33,0x32,0x36,0x25,0x11,0x14,0x06,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x21,0x32,0x16,0x37,0x15,0x14,0x06,0x23,0x21,0x22,0x26,0x37,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x02,0x5f,0x14,0x10,0x8e,0x0f,0x14,0x02,0x18, +0x0d,0x8e,0x0f,0x16,0x01,0x41,0x16,0x0e,0xfc,0xee,0x0e,0x16,0x16,0x0e,0x03,0x12,0x0e,0x16,0x23,0x14,0x0f,0xfc,0xa6,0x0e,0x16,0x01,0x14,0x0f,0x03,0x5a,0x0e,0x16,0x01,0x82,0x0e,0x16,0x01,0x14,0x1e,0x14,0x01,0x16,0x79,0xfd,0xe8,0x0e,0x16,0x16,0x0e,0x02,0x18,0x0e,0x16,0x16,0xec,0x8f,0x0e,0x16,0x16,0x0e,0x8f,0x0e,0x16,0x16, +0x00,0x05,0x00,0x00,0xff,0x88,0x03,0xac,0x03,0x34,0x00,0x43,0x00,0x4c,0x00,0x55,0x00,0x5e,0x00,0x67,0x00,0x61,0x40,0x5e,0x3c,0x33,0x02,0x05,0x0a,0x1a,0x0f,0x02,0x01,0x05,0x2b,0x22,0x19,0x10,0x09,0x00,0x06,0x08,0x01,0x03,0x4c,0x07,0x01,0x05,0x03,0x01,0x01,0x08,0x05,0x01,0x67,0x00,0x0a,0x0f,0x0c,0x02,0x08,0x09,0x0a,0x08, +0x69,0x10,0x0e,0x0d,0x03,0x09,0x04,0x02,0x02,0x00,0x09,0x00,0x65,0x00,0x0b,0x0b,0x06,0x61,0x00,0x06,0x06,0x12,0x0b,0x4e,0x60,0x5f,0x64,0x63,0x5f,0x67,0x60,0x67,0x5d,0x5c,0x59,0x58,0x54,0x53,0x50,0x4f,0x4b,0x4a,0x15,0x36,0x16,0x37,0x18,0x36,0x16,0x36,0x14,0x11,0x07,0x1f,0x2b,0x25,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34, +0x37,0x35,0x34,0x2b,0x01,0x22,0x27,0x15,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x06,0x2b,0x01,0x22,0x0e,0x01,0x1d,0x01,0x16,0x15,0x14,0x06,0x22,0x26,0x35,0x34,0x37,0x35,0x34,0x36,0x3b,0x01,0x32,0x3d,0x01,0x26,0x35,0x34,0x36,0x32,0x16,0x15,0x14,0x07,0x15,0x14,0x3b,0x01,0x32,0x16,0x15,0x05,0x34,0x26,0x22,0x06, +0x14,0x16,0x32,0x36,0x13,0x14,0x16,0x32,0x36,0x34,0x26,0x22,0x06,0x13,0x34,0x26,0x22,0x06,0x14,0x16,0x32,0x36,0x05,0x32,0x36,0x34,0x26,0x22,0x06,0x14,0x16,0x03,0x64,0x48,0x46,0x64,0x46,0x48,0x4c,0x64,0x2c,0x22,0x48,0x46,0x64,0x46,0x48,0x1e,0x2e,0x64,0x22,0x26,0x06,0x48,0x46,0x64,0x46,0x48,0x56,0x58,0x64,0x4c,0x48,0x46, +0x64,0x46,0x48,0x4e,0x64,0x56,0x56,0xfd,0x5a,0x2a,0x38,0x28,0x28,0x38,0x2a,0xd4,0x28,0x38,0x2a,0x2a,0x38,0x28,0x8a,0x2a,0x38,0x28,0x28,0x38,0x2a,0x01,0x18,0x1c,0x2a,0x2a,0x38,0x28,0x28,0x70,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x4e,0x0c,0xcc,0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0xcc,0x0c,0x26,0x1c,0x0c,0x72, +0x22,0x4e,0x32,0x46,0x46,0x32,0x4e,0x22,0x72,0x40,0x6c,0x34,0x8c,0x22,0x4c,0x32,0x46,0x46,0x32,0x4c,0x22,0x8c,0x34,0x6c,0x40,0xe2,0x1e,0x28,0x28,0x3a,0x28,0x28,0x02,0xd8,0x1c,0x28,0x28,0x3a,0x28,0x28,0xfd,0x26,0x1e,0x28,0x28,0x3a,0x28,0x28,0x28,0x28,0x3a,0x28,0x28,0x3a,0x28,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59, +0x03,0x0b,0x00,0x23,0x00,0x33,0x00,0x3e,0x40,0x3b,0x0d,0x01,0x00,0x01,0x1f,0x01,0x04,0x03,0x02,0x4c,0x02,0x01,0x00,0x01,0x03,0x01,0x00,0x03,0x80,0x05,0x01,0x03,0x04,0x01,0x03,0x04,0x7e,0x00,0x01,0x01,0x07,0x5f,0x00,0x07,0x07,0x13,0x4d,0x00,0x04,0x04,0x06,0x60,0x00,0x06,0x06,0x11,0x06,0x4e,0x35,0x35,0x23,0x33,0x16,0x23, +0x24,0x23,0x08,0x07,0x1e,0x2b,0x01,0x35,0x34,0x26,0x07,0x23,0x35,0x34,0x26,0x27,0x23,0x22,0x06,0x07,0x15,0x23,0x22,0x06,0x07,0x15,0x14,0x16,0x37,0x33,0x15,0x14,0x16,0x3b,0x01,0x32,0x36,0x37,0x35,0x33,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xb3,0x16, +0x0e,0x47,0x0f,0x14,0x01,0xb2,0x0f,0x14,0x01,0x16,0x0e,0xb2,0x16,0x0e,0x47,0x0f,0x14,0x01,0xb3,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01,0x3a,0x48,0x0e,0x16,0x01,0xb3,0x0f,0x14,0x01,0x16,0x0e,0xb3,0x14,0x0f,0x48,0x0e,0x16,0x01,0xb3,0x0e,0x16,0x16,0x0e,0xb3,0x14,0x01,0x3f,0xfd,0xe8, +0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x00,0x02,0x00,0x00,0xff,0xb1,0x03,0x59,0x03,0x0b,0x00,0x0f,0x00,0x1f,0x00,0x1f,0x40,0x1c,0x00,0x00,0x00,0x03,0x5f,0x00,0x03,0x03,0x13,0x4d,0x00,0x01,0x01,0x02,0x5f,0x00,0x02,0x02,0x11,0x02,0x4e,0x35,0x35,0x26,0x33,0x04,0x07,0x1a,0x2b,0x01,0x35,0x34,0x26,0x07, +0x21,0x22,0x06,0x07,0x15,0x14,0x16,0x37,0x21,0x32,0x36,0x13,0x11,0x14,0x06,0x07,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x37,0x21,0x32,0x16,0x02,0xca,0x14,0x0f,0xfe,0x0c,0x0f,0x14,0x01,0x16,0x0e,0x01,0xf4,0x0e,0x16,0x8e,0x5e,0x43,0xfd,0xe9,0x43,0x5e,0x5e,0x43,0x02,0x17,0x43,0x5e,0x01,0x3a,0x48,0x0e,0x16,0x01,0x14,0x0f,0x48, +0x0e,0x16,0x01,0x14,0x01,0x3f,0xfd,0xe8,0x42,0x5e,0x01,0x60,0x41,0x02,0x18,0x42,0x5e,0x01,0x60,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x07,0xb3,0xdb,0xee,0x5f,0x0f,0x3c,0xf5,0x00,0x0f,0x03,0xe8,0x00,0x00,0x00,0x00,0xe4,0x2d,0xc8,0x06,0x00,0x00,0x00,0x00,0xe4,0x2d,0xc8,0x07,0xff,0xf5,0xff,0x6a,0x04,0x78,0x03,0x53, +0x00,0x00,0x00,0x08,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x03,0x52,0xff,0x6a,0x00,0x00,0x04,0x76,0xff,0xf5,0xff,0xf5,0x04,0x78,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x80,0x00,0x00,0x03,0xe8,0x00,0x00, +0x04,0x2f,0xff,0xff,0x00,0xf0,0x00,0x00,0x04,0x76,0xff,0xff,0x03,0xe8,0xff,0xff,0x03,0xe8,0x00,0x00,0x02,0x44,0x00,0x00,0x02,0x44,0x00,0x00,0x03,0x59,0xff,0xfd,0x02,0x3b,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x11,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0xe8,0x00,0x00,0x00,0xdc,0x00,0x00,0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00, +0x02,0x3b,0xff,0xff,0x01,0x65,0x00,0x00,0x01,0x65,0x00,0x00,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x03,0xca,0x00,0x00,0x04,0x2f,0xff,0xff,0x03,0xa0,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xd4,0xff,0xf7,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xff,0x02,0x82,0x00,0x00, +0x02,0xda,0x00,0x00,0x04,0x2f,0xff,0xff,0x02,0xf8,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x59,0x00,0x00,0x03,0x59,0xff,0xff,0x02,0xda,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x02,0xf8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0xff,0xf5,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0x11,0x00,0x00, +0x03,0x11,0x00,0x00,0x02,0x82,0x00,0x00,0x03,0x42,0x00,0x00,0x04,0x2f,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xe7,0xff,0xfe,0x03,0x59,0x00,0x00,0x03,0x11,0x00,0x00,0x02,0x3b,0xff,0xff,0x03,0x98,0xff,0xfc,0x03,0x59,0x00,0x00,0x02,0x82,0x00,0x00,0x03,0xa0,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0xe8,0xff,0xff, +0x03,0x59,0xff,0xfd,0x02,0x82,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0xff,0xfe,0x02,0x82,0x00,0x00,0x03,0x59,0xff,0xfd,0x03,0x11,0x00,0x00,0x03,0xe8,0x00,0x00,0x03,0xac,0x00,0x00,0x03,0x59,0x00,0x00,0x03,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0xe0,0x01,0x76,0x01,0xf0, +0x02,0x46,0x02,0x9e,0x02,0xc4,0x03,0x10,0x03,0x46,0x03,0x68,0x03,0x8c,0x03,0xb8,0x04,0x42,0x05,0x04,0x05,0x60,0x05,0xf4,0x06,0x18,0x06,0x42,0x06,0x64,0x06,0x8e,0x06,0xc6,0x06,0xfe,0x07,0xa6,0x07,0xf8,0x08,0xa0,0x08,0xf2,0x09,0x20,0x09,0x42,0x09,0x8e,0x09,0xd6,0x0a,0x98,0x0b,0x82,0x0c,0x0e,0x0c,0xfa,0x0d,0x3e,0x0d,0x64, +0x0d,0xc6,0x0e,0x2a,0x0e,0x6c,0x0f,0x1e,0x0f,0xce,0x0f,0xf6,0x10,0x4a,0x11,0x7c,0x11,0x9a,0x11,0xd2,0x12,0x3c,0x12,0x98,0x12,0xf8,0x14,0x00,0x14,0x80,0x14,0xe0,0x15,0x1a,0x15,0xde,0x16,0x6a,0x16,0xc0,0x17,0xce,0x18,0x30,0x18,0x88,0x18,0xa6,0x18,0xe4,0x19,0x80,0x19,0xe8,0x1a,0x3c,0x1a,0xb8,0x1b,0x48,0x1b,0x7c,0x1b,0xd0, +0x1c,0x32,0x1c,0xc0,0x1d,0x04,0x1d,0x2e,0x1d,0x94,0x1d,0xca,0x1e,0x32,0x1e,0x80,0x1e,0xde,0x1f,0x9a,0x20,0x04,0x20,0x48,0x00,0x01,0x00,0x00,0x00,0x51,0x00,0x90,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x42,0x00,0x7b,0x00,0x8d,0x00,0x00,0x00,0xba,0x0e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0xde,0x00,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x00,0x35,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x07,0x00,0x3d,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x08,0x00,0x44,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x4c,0x00,0x01,0x00,0x00,0x00,0x00, +0x00,0x05,0x00,0x0b,0x00,0x54,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x08,0x00,0x5f,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x2b,0x00,0x67,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0x13,0x00,0x92,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x00,0x00,0x6a,0x00,0xa5,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x01,0x00,0x10, +0x01,0x0f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x02,0x00,0x0e,0x01,0x1f,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x03,0x00,0x10,0x01,0x2d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x04,0x00,0x10,0x01,0x3d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x05,0x00,0x16,0x01,0x4d,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x06,0x00,0x10,0x01,0x63,0x00,0x03, +0x00,0x01,0x04,0x09,0x00,0x0a,0x00,0x56,0x01,0x73,0x00,0x03,0x00,0x01,0x04,0x09,0x00,0x0b,0x00,0x26,0x01,0xc9,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x43,0x29,0x20,0x32,0x30,0x32,0x35,0x20,0x62,0x79,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x61,0x75,0x74,0x68,0x6f,0x72,0x73,0x20,0x40,0x20,0x66, +0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x30,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x47,0x65,0x6e, +0x65,0x72,0x61,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x73,0x76,0x67,0x32,0x74,0x74,0x66,0x20,0x66,0x72,0x6f,0x6d,0x20,0x46,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x20,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x66,0x6f,0x6e,0x74,0x65,0x6c,0x6c,0x6f,0x2e,0x63,0x6f,0x6d,0x00,0x43,0x00,0x6f,0x00, +0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00,0x20,0x00,0x28,0x00,0x43,0x00,0x29,0x00,0x20,0x00,0x32,0x00,0x30,0x00,0x32,0x00,0x35,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x6f,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x20,0x00,0x61,0x00,0x75,0x00,0x74,0x00, +0x68,0x00,0x6f,0x00,0x72,0x00,0x73,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00,0x63,0x00,0x6f,0x00,0x6d,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x52,0x00,0x65,0x00,0x67,0x00,0x75,0x00,0x6c,0x00, +0x61,0x00,0x72,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x31,0x00,0x2e,0x00,0x30,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00, +0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x47,0x00,0x65,0x00,0x6e,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x65,0x00,0x64,0x00,0x20,0x00,0x62,0x00,0x79,0x00,0x20,0x00,0x73,0x00,0x76,0x00,0x67,0x00,0x32,0x00,0x74,0x00,0x74,0x00,0x66,0x00,0x20,0x00,0x66,0x00,0x72,0x00,0x6f,0x00,0x6d,0x00,0x20,0x00,0x46,0x00, +0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x20,0x00,0x70,0x00,0x72,0x00,0x6f,0x00,0x6a,0x00,0x65,0x00,0x63,0x00,0x74,0x00,0x2e,0x00,0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,0x2f,0x00,0x66,0x00,0x6f,0x00,0x6e,0x00,0x74,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x2e,0x00, +0x63,0x00,0x6f,0x00,0x6d,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x01,0x02,0x01,0x03,0x01,0x04,0x01,0x05,0x01,0x06,0x01,0x07,0x01,0x08,0x01,0x09,0x01,0x0a,0x01,0x0b,0x01,0x0c, +0x01,0x0d,0x01,0x0e,0x01,0x0f,0x01,0x10,0x01,0x11,0x01,0x12,0x01,0x13,0x01,0x14,0x01,0x15,0x01,0x16,0x01,0x17,0x01,0x18,0x01,0x19,0x01,0x1a,0x01,0x1b,0x01,0x1c,0x01,0x1d,0x01,0x1e,0x01,0x1f,0x01,0x20,0x01,0x21,0x01,0x22,0x01,0x23,0x01,0x24,0x01,0x25,0x01,0x26,0x01,0x27,0x01,0x28,0x01,0x29,0x01,0x2a,0x01,0x2b,0x01,0x2c, +0x01,0x2d,0x01,0x2e,0x01,0x2f,0x01,0x30,0x01,0x31,0x01,0x32,0x01,0x33,0x01,0x34,0x01,0x35,0x01,0x36,0x01,0x37,0x01,0x38,0x01,0x39,0x01,0x3a,0x01,0x3b,0x01,0x3c,0x01,0x3d,0x01,0x3e,0x01,0x3f,0x01,0x40,0x01,0x41,0x01,0x42,0x01,0x43,0x01,0x44,0x01,0x45,0x01,0x46,0x01,0x47,0x01,0x48,0x01,0x49,0x01,0x4a,0x01,0x4b,0x01,0x4c, +0x01,0x4d,0x01,0x4e,0x01,0x4f,0x01,0x50,0x01,0x51,0x01,0x52,0x00,0x0b,0x63,0x68,0x65,0x63,0x6b,0x2d,0x65,0x6d,0x70,0x74,0x79,0x0d,0x66,0x6c,0x6f,0x77,0x2d,0x70,0x61,0x72,0x61,0x6c,0x6c,0x65,0x6c,0x04,0x64,0x6f,0x63,0x73,0x07,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x6c,0x69,0x6e,0x65,0x0e,0x77, +0x69,0x6e,0x64,0x6f,0x77,0x2d,0x72,0x65,0x73,0x74,0x6f,0x72,0x65,0x0f,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2d,0x6d,0x69,0x6e,0x69,0x6d,0x69,0x7a,0x65,0x04,0x63,0x75,0x62,0x65,0x04,0x70,0x6c,0x75,0x73,0x05,0x6d,0x69,0x6e,0x75,0x73,0x06,0x63,0x69,0x72,0x63,0x6c,0x65,0x08,0x64,0x6f,0x77,0x6e,0x2d,0x64,0x69,0x72,0x05,0x63,0x68, +0x65,0x63,0x6b,0x0b,0x74,0x72,0x61,0x73,0x68,0x2d,0x65,0x6d,0x70,0x74,0x79,0x04,0x75,0x73,0x65,0x72,0x09,0x62,0x72,0x69,0x65,0x66,0x63,0x61,0x73,0x65,0x03,0x64,0x6f,0x74,0x08,0x6c,0x65,0x66,0x74,0x2d,0x64,0x69,0x72,0x09,0x72,0x69,0x67,0x68,0x74,0x2d,0x64,0x69,0x72,0x06,0x75,0x70,0x2d,0x64,0x69,0x72,0x0a,0x61,0x6e,0x67, +0x6c,0x65,0x2d,0x6c,0x65,0x66,0x74,0x0b,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x72,0x69,0x67,0x68,0x74,0x0c,0x68,0x65,0x6c,0x70,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03,0x74,0x61,0x67,0x04,0x67,0x72,0x69,0x64,0x0b,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f,0x70,0x65,0x6e,0x06,0x66,0x6f,0x6c,0x64,0x65,0x72,0x09,0x64,0x6f,0x77, +0x6e,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x70,0x61,0x6c,0x65,0x74,0x74,0x65,0x07,0x64,0x6f,0x63,0x2d,0x69,0x6e,0x76,0x03,0x63,0x6f,0x67,0x02,0x74,0x68,0x0a,0x62,0x69,0x6e,0x6f,0x63,0x75,0x6c,0x61,0x72,0x73,0x04,0x6c,0x69,0x73,0x74,0x04,0x6c,0x6f,0x63,0x6b,0x09,0x6c,0x65,0x66,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x07,0x64,0x65,0x73, +0x6b,0x74,0x6f,0x70,0x06,0x73,0x65,0x61,0x72,0x63,0x68,0x0c,0x63,0x69,0x72,0x63,0x6c,0x65,0x2d,0x65,0x6d,0x70,0x74,0x79,0x06,0x70,0x65,0x6e,0x63,0x69,0x6c,0x03,0x68,0x64,0x64,0x0a,0x72,0x69,0x67,0x68,0x74,0x2d,0x62,0x6f,0x6c,0x64,0x0b,0x63,0x6c,0x6f,0x73,0x65,0x5f,0x70,0x61,0x6e,0x65,0x6c,0x08,0x73,0x74,0x65,0x70,0x69, +0x6e,0x74,0x6f,0x07,0x75,0x70,0x2d,0x62,0x6f,0x6c,0x64,0x02,0x6f,0x6b,0x09,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x10,0x68,0x6f,0x72,0x69,0x7a,0x6f,0x6e,0x74,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x0e,0x76,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x5f,0x73,0x70,0x6c,0x69,0x74,0x08,0x73,0x74,0x65,0x70,0x6f,0x76,0x65, +0x72,0x10,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x11,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x2d,0x61,0x6c,0x74,0x08,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x75,0x70,0x09,0x63,0x6c,0x69,0x70,0x62,0x6f,0x61,0x72,0x64,0x11,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x6f, +0x70,0x65,0x6e,0x2d,0x65,0x6d,0x70,0x74,0x79,0x0c,0x66,0x6f,0x6c,0x64,0x65,0x72,0x2d,0x65,0x6d,0x70,0x74,0x79,0x07,0x73,0x74,0x65,0x70,0x6f,0x75,0x74,0x07,0x67,0x6c,0x61,0x73,0x73,0x65,0x73,0x03,0x64,0x6f,0x63,0x04,0x70,0x6c,0x61,0x79,0x06,0x74,0x6f,0x2d,0x65,0x6e,0x64,0x0c,0x69,0x6e,0x66,0x6f,0x2d,0x63,0x69,0x72,0x63, +0x6c,0x65,0x64,0x03,0x63,0x63,0x77,0x0d,0x6c,0x6f,0x63,0x6b,0x2d,0x6f,0x70,0x65,0x6e,0x2d,0x61,0x6c,0x74,0x06,0x74,0x61,0x72,0x67,0x65,0x74,0x06,0x66,0x6c,0x6f,0x70,0x70,0x79,0x0f,0x77,0x69,0x6e,0x64,0x6f,0x77,0x2d,0x6d,0x61,0x78,0x69,0x6d,0x69,0x7a,0x65,0x0b,0x64,0x6f,0x74,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x03, +0x70,0x69,0x6e,0x09,0x61,0x72,0x72,0x6f,0x77,0x73,0x2d,0x63,0x77,0x05,0x70,0x61,0x75,0x73,0x65,0x04,0x73,0x74,0x6f,0x70,0x02,0x63,0x77,0x0a,0x61,0x6e,0x67,0x6c,0x65,0x2d,0x64,0x6f,0x77,0x6e,0x11,0x61,0x74,0x74,0x65,0x6e,0x74,0x69,0x6f,0x6e,0x2d,0x63,0x69,0x72,0x63,0x6c,0x65,0x64,0x06,0x63,0x61,0x6e,0x63,0x65,0x6c,0x03, +0x62,0x6f,0x78,0x09,0x66,0x6c,0x6f,0x77,0x2d,0x74,0x72,0x65,0x65,0x0c,0x70,0x6c,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x0d,0x6d,0x69,0x6e,0x75,0x73,0x2d,0x73,0x71,0x75,0x61,0x72,0x65,0x64,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0xff,0xff,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x01,0x1e,0x00,0x7d,0x00,0x7d,0x01,0x1e,0x03,0x18,0xff,0xb1,0x03,0x38,0x03,0x0b,0xff,0xb1,0xff,0xb1,0x03,0x18,0xff,0xb1,0x03,0x38,0x03,0x0b,0xff,0xb1,0xff,0xb1,0xb0,0x00,0x2c,0x20,0xb0,0x00,0x55,0x58,0x45,0x59,0x20,0x20,0x4b,0xb8,0x00,0x0e,0x51,0x4b,0xb0,0x06, +0x53,0x5a,0x58,0xb0,0x34,0x1b,0xb0,0x28,0x59,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x62,0x1b,0x21,0x21,0xb0,0x00,0x59,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x01,0x2c,0xb0,0x20,0x60,0x66,0x2d,0xb0,0x02,0x2c,0x23,0x21,0x23,0x21,0x2d,0xb0, +0x03,0x2c,0x20,0x64,0xb3,0x03,0x14,0x15,0x00,0x42,0x43,0xb0,0x13,0x43,0x20,0x60,0x60,0x42,0xb1,0x02,0x14,0x43,0x42,0xb1,0x25,0x03,0x43,0xb0,0x02,0x43,0x54,0x78,0x20,0xb0,0x0c,0x23,0xb0,0x02,0x43,0x43,0x61,0x64,0xb0,0x04,0x50,0x78,0xb2,0x02,0x02,0x02,0x43,0x60,0x42,0xb0,0x21,0x65,0x1c,0x21,0xb0,0x02,0x43,0x43,0xb2,0x0e, +0x15,0x01,0x42,0x1c,0x20,0xb0,0x02,0x43,0x23,0x42,0xb2,0x13,0x01,0x13,0x43,0x60,0x42,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb2,0x16,0x01,0x02,0x43,0x60,0x42,0x2d,0xb0,0x04,0x2c,0xb0,0x03,0x2b,0xb0,0x15,0x43,0x58,0x23,0x21,0x23,0x21,0xb0,0x16,0x43,0x43,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x1b,0x20,0x64,0x20,0xb0,0xc0,0x50, +0xb0,0x04,0x26,0x5a,0xb2,0x28,0x01,0x0d,0x43,0x45,0x63,0x45,0xb0,0x06,0x45,0x58,0x21,0xb0,0x03,0x25,0x59,0x52,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20,0xb0,0x38,0x50,0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb1,0x01,0x0d,0x43,0x45,0x63,0x45,0x61,0x64,0xb0,0x28,0x50,0x58, +0x21,0xb1,0x01,0x0d,0x43,0x45,0x63,0x45,0x20,0xb0,0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x0a,0x50,0x58,0x60,0x1b,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0a,0x60,0x1b,0x20,0xb0,0x36,0x50,0x58,0x21,0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x02,0x25, +0xb0,0x0c,0x43,0x63,0xb0,0x00,0x52,0x58,0xb0,0x00,0x4b,0xb0,0x0a,0x50,0x58,0x21,0xb0,0x0c,0x43,0x1b,0x4b,0xb0,0x1e,0x50,0x58,0x21,0xb0,0x1e,0x4b,0x61,0xb8,0x10,0x00,0x63,0xb0,0x0c,0x43,0x63,0xb8,0x05,0x00,0x62,0x59,0x59,0x64,0x61,0x59,0xb0,0x01,0x2b,0x59,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0x59,0x20,0x64,0xb0,0x16, +0x43,0x23,0x42,0x59,0x2d,0xb0,0x05,0x2c,0x20,0x45,0x20,0xb0,0x04,0x25,0x61,0x64,0x20,0xb0,0x07,0x43,0x50,0x58,0xb0,0x07,0x23,0x42,0xb0,0x08,0x23,0x42,0x1b,0x21,0x21,0x59,0xb0,0x01,0x60,0x2d,0xb0,0x06,0x2c,0x23,0x21,0x23,0x21,0xb0,0x03,0x2b,0x20,0x64,0xb1,0x07,0x62,0x42,0x20,0xb0,0x08,0x23,0x42,0xb0,0x06,0x45,0x58,0x1b, +0xb1,0x01,0x0d,0x43,0x45,0x63,0xb1,0x01,0x0d,0x43,0xb0,0x01,0x60,0x45,0x63,0xb0,0x05,0x2a,0x21,0x20,0xb0,0x08,0x43,0x20,0x8a,0x20,0x8a,0xb0,0x01,0x2b,0xb1,0x30,0x05,0x25,0xb0,0x04,0x26,0x51,0x58,0x60,0x50,0x1b,0x61,0x52,0x59,0x58,0x23,0x59,0x21,0x59,0x20,0xb0,0x40,0x53,0x58,0xb0,0x01,0x2b,0x1b,0x21,0xb0,0x40,0x59,0x23, +0xb0,0x00,0x50,0x58,0x65,0x59,0x2d,0xb0,0x07,0x2c,0xb0,0x09,0x43,0x2b,0xb2,0x00,0x02,0x00,0x43,0x60,0x42,0x2d,0xb0,0x08,0x2c,0xb0,0x09,0x23,0x42,0x23,0x20,0xb0,0x00,0x23,0x42,0x61,0xb0,0x02,0x62,0x66,0xb0,0x01,0x63,0xb0,0x01,0x60,0xb0,0x07,0x2a,0x2d,0xb0,0x09,0x2c,0x20,0x20,0x45,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00, +0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0a,0x2c,0xb2,0x09,0x0e,0x00,0x43,0x45,0x42,0x2a,0x21,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x0b,0x2c,0xb0,0x00,0x43,0x23,0x44,0xb2,0x00,0x01,0x00,0x43,0x60,0x42,0x2d,0xb0,0x0c,0x2c,0x20,0x20,0x45,0x20,0xb0, +0x01,0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x00,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0d,0x2c,0x20,0x20,0x45,0x20,0xb0,0x01, +0x2b,0x23,0xb0,0x00,0x43,0xb0,0x04,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64,0xb0,0x24,0x50,0x58,0xb0,0x00,0x1b,0xb0,0x40,0x59,0x23,0xb0,0x00,0x50,0x58,0x65,0x59,0xb0,0x03,0x25,0x23,0x61,0x44,0x44,0xb0,0x01,0x60,0x2d,0xb0,0x0e,0x2c,0x20,0xb0,0x00,0x23,0x42,0xb3,0x0d,0x0c,0x00,0x03,0x45,0x50,0x58,0x21,0x1b,0x23,0x21, +0x59,0x2a,0x21,0x2d,0xb0,0x0f,0x2c,0xb1,0x02,0x02,0x45,0xb0,0x64,0x61,0x44,0x2d,0xb0,0x10,0x2c,0xb0,0x01,0x60,0x20,0x20,0xb0,0x0f,0x43,0x4a,0xb0,0x00,0x50,0x58,0x20,0xb0,0x0f,0x23,0x42,0x59,0xb0,0x10,0x43,0x4a,0xb0,0x00,0x52,0x58,0x20,0xb0,0x10,0x23,0x42,0x59,0x2d,0xb0,0x11,0x2c,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63, +0x20,0xb8,0x04,0x00,0x63,0x8a,0x23,0x61,0xb0,0x11,0x43,0x60,0x20,0x8a,0x60,0x20,0xb0,0x11,0x23,0x42,0x23,0x2d,0xb0,0x12,0x2c,0x4b,0x54,0x58,0xb1,0x04,0x64,0x44,0x59,0x24,0xb0,0x0d,0x65,0x23,0x78,0x2d,0xb0,0x13,0x2c,0x4b,0x51,0x58,0x4b,0x53,0x58,0xb1,0x04,0x64,0x44,0x59,0x1b,0x21,0x59,0x24,0xb0,0x13,0x65,0x23,0x78,0x2d, +0xb0,0x14,0x2c,0xb1,0x00,0x12,0x43,0x55,0x58,0xb1,0x12,0x12,0x43,0xb0,0x01,0x61,0x42,0xb0,0x11,0x2b,0x59,0xb0,0x00,0x43,0xb0,0x02,0x25,0x42,0xb1,0x0f,0x02,0x25,0x42,0xb1,0x10,0x02,0x25,0x42,0xb0,0x01,0x16,0x23,0x20,0xb0,0x03,0x25,0x50,0x58,0xb1,0x01,0x00,0x43,0x60,0xb0,0x04,0x25,0x42,0x8a,0x8a,0x20,0x8a,0x23,0x61,0xb0, +0x10,0x2a,0x21,0x23,0xb0,0x01,0x61,0x20,0x8a,0x23,0x61,0xb0,0x10,0x2a,0x21,0x1b,0xb1,0x01,0x00,0x43,0x60,0xb0,0x02,0x25,0x42,0xb0,0x02,0x25,0x61,0xb0,0x10,0x2a,0x21,0x59,0xb0,0x0f,0x43,0x47,0xb0,0x10,0x43,0x47,0x60,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x20,0xb0,0x0e,0x43,0x63, +0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb1,0x00,0x00,0x13,0x23,0x44,0xb0,0x01,0x43,0xb0,0x00,0x3e,0xb2,0x01,0x01,0x01,0x43,0x60,0x42,0x2d,0xb0,0x15,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42,0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60, +0x42,0x20,0x60,0xb7,0x18,0x18,0x01,0x00,0x11,0x00,0x13,0x00,0x42,0x42,0x42,0x8a,0x60,0x20,0xb0,0x14,0x23,0x42,0xb0,0x01,0x61,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x16,0x2c,0xb1,0x00,0x15,0x2b,0x2d,0xb0,0x17,0x2c,0xb1,0x01,0x15,0x2b,0x2d,0xb0,0x18,0x2c,0xb1,0x02,0x15,0x2b,0x2d,0xb0,0x19,0x2c,0xb1, +0x03,0x15,0x2b,0x2d,0xb0,0x1a,0x2c,0xb1,0x04,0x15,0x2b,0x2d,0xb0,0x1b,0x2c,0xb1,0x05,0x15,0x2b,0x2d,0xb0,0x1c,0x2c,0xb1,0x06,0x15,0x2b,0x2d,0xb0,0x1d,0x2c,0xb1,0x07,0x15,0x2b,0x2d,0xb0,0x1e,0x2c,0xb1,0x08,0x15,0x2b,0x2d,0xb0,0x1f,0x2c,0xb1,0x09,0x15,0x2b,0x2d,0xb0,0x2b,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63, +0xb0,0x06,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x5d,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2c,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x16,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x01,0x71,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2d,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x01,0x63,0xb0,0x26,0x60,0x4b,0x54,0x58, +0x23,0x20,0x2e,0xb0,0x01,0x72,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x20,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02,0x45,0x54,0x58,0xb0,0x12,0x23,0x42,0x20,0x45,0xb0,0x0e,0x23,0x42,0xb0,0x0d,0x23,0xb0,0x01,0x60,0x42,0x20,0x60,0xb0,0x01,0x61,0xb5,0x18,0x18,0x01,0x00,0x11,0x00,0x42,0x42,0x8a,0x60,0xb1,0x14,0x08,0x2b,0xb0,0x8b,0x2b, +0x1b,0x22,0x59,0x2d,0xb0,0x21,0x2c,0xb1,0x00,0x20,0x2b,0x2d,0xb0,0x22,0x2c,0xb1,0x01,0x20,0x2b,0x2d,0xb0,0x23,0x2c,0xb1,0x02,0x20,0x2b,0x2d,0xb0,0x24,0x2c,0xb1,0x03,0x20,0x2b,0x2d,0xb0,0x25,0x2c,0xb1,0x04,0x20,0x2b,0x2d,0xb0,0x26,0x2c,0xb1,0x05,0x20,0x2b,0x2d,0xb0,0x27,0x2c,0xb1,0x06,0x20,0x2b,0x2d,0xb0,0x28,0x2c,0xb1, +0x07,0x20,0x2b,0x2d,0xb0,0x29,0x2c,0xb1,0x08,0x20,0x2b,0x2d,0xb0,0x2a,0x2c,0xb1,0x09,0x20,0x2b,0x2d,0xb0,0x2e,0x2c,0x20,0x3c,0xb0,0x01,0x60,0x2d,0xb0,0x2f,0x2c,0x20,0x60,0xb0,0x18,0x60,0x20,0x43,0x23,0xb0,0x01,0x60,0x43,0xb0,0x02,0x25,0x61,0xb0,0x01,0x60,0xb0,0x2e,0x2a,0x21,0x2d,0xb0,0x30,0x2c,0xb0,0x2f,0x2b,0xb0,0x2f, +0x2a,0x2d,0xb0,0x31,0x2c,0x20,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x61,0x38,0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01, +0x63,0x60,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x32,0x2c,0x00,0xb1,0x00,0x02,0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0,0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x33,0x2c,0x00,0xb0,0x0f,0x2b,0xb1,0x00,0x02,0x45,0x54,0x58,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x16,0xb0, +0x31,0x2a,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x34,0x2c,0x20,0x35,0xb0,0x01,0x60,0x2d,0xb0,0x35,0x2c,0x00,0xb1,0x0e,0x07,0x45,0x42,0xb0,0x01,0x45,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0xb0,0x01,0x2b,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62, +0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0xb0,0x01,0x2b,0xb0,0x00,0x16,0xb4,0x00,0x00,0x00,0x00,0x00,0x44,0x3e,0x23,0x38,0xb1,0x34,0x01,0x15,0x2a,0x21,0x2d,0xb0,0x36,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01, +0x63,0x60,0xb0,0x00,0x43,0x61,0x38,0x2d,0xb0,0x37,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x38,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0x0e,0x43,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0xb0,0x00,0x43,0x61,0xb0,0x01,0x43,0x63,0x38,0x2d,0xb0,0x39,0x2c,0xb1,0x02,0x00,0x16,0x25,0x20, +0x2e,0x20,0x47,0xb0,0x00,0x23,0x42,0xb0,0x02,0x25,0x49,0x8a,0x8a,0x47,0x23,0x47,0x23,0x61,0x20,0x58,0x62,0x1b,0x21,0x59,0xb0,0x01,0x23,0x42,0xb2,0x38,0x01,0x01,0x15,0x14,0x2a,0x2d,0xb0,0x3a,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25,0x47,0x23,0x47,0x23,0x61,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43, +0x2b,0x65,0x8a,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x3b,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3, +0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0xb0,0x0a,0x43,0x20,0x8a,0x23,0x47,0x23,0x47,0x23,0x61,0x23,0x46,0x60,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x04,0x43,0x60,0x64,0x23,0xb0,0x05,0x43,0x61,0x64,0x50, +0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x0a,0x43,0x46,0xb0,0x02,0x25,0xb0,0x0a,0x43,0x47,0x23,0x47,0x23,0x61,0x60,0x20,0xb0,0x06,0x43,0xb0, +0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x20,0xb0,0x01,0x2b,0x23,0xb0,0x06,0x43,0x60,0xb0,0x01,0x2b,0xb0,0x05,0x25,0x61,0xb0,0x05,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0xb0,0x04,0x26,0x61,0x20,0xb0,0x04,0x25,0x60,0x64,0x23,0xb0, +0x03,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0x20,0xb0,0x04,0x26,0x23,0x46,0x61,0x38,0x59,0x2d,0xb0,0x3c,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0x20,0x20,0xb0,0x05,0x26,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x23,0x3c,0x38,0x2d,0xb0,0x3d,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x23, +0x42,0x20,0x20,0x20,0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x2d,0xb0,0x3e,0x2c,0xb0,0x00,0x16,0xb0,0x17,0x23,0x42,0xb0,0x03,0x25,0xb0,0x02,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x00,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x02,0x25,0xb0,0x02,0x25,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x05,0x25,0xb0,0x04,0x25,0x47, +0x23,0x47,0x23,0x61,0xb0,0x06,0x25,0xb0,0x05,0x25,0x49,0xb0,0x02,0x25,0x61,0xb9,0x08,0x00,0x08,0x00,0x63,0x63,0x23,0x20,0x58,0x62,0x1b,0x21,0x59,0x63,0xb8,0x04,0x00,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x2d,0xb0,0x3f,0x2c,0xb0, +0x00,0x16,0xb0,0x17,0x23,0x42,0x20,0xb0,0x0a,0x43,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x40,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52, +0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x41,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x42,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c, +0x59,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x52,0x1b,0x50,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x43,0x2c,0xb0,0x3a,0x2b,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x44,0x2c, +0xb0,0x3b,0x2b,0x8a,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x02,0x25,0x46,0xb0,0x17,0x43,0x58,0x50,0x1b,0x52,0x59,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x45,0x2c,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x04,0x26,0x20,0x20,0x20,0x46,0x23, +0x47,0x61,0xb0,0x0c,0x23,0x42,0x2e,0x47,0x23,0x47,0x23,0x61,0xb0,0x0b,0x43,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x46,0x2c,0xb1,0x0a,0x04,0x25,0x42,0xb0,0x00,0x16,0xb0,0x04,0x25,0xb0,0x04,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x06,0x23,0x42,0xb1,0x0c,0x00,0x42,0xb0,0x0b, +0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x04,0x20,0x05,0x20,0x1b,0xb3,0x04,0x26,0x05,0x1a,0x59,0x42,0x42,0x23,0x20,0x47,0xb0,0x06,0x43,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x60,0x20,0xb0,0x01,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x04,0x43,0x60,0x64,0x23, +0xb0,0x05,0x43,0x61,0x64,0x50,0x58,0xb0,0x04,0x43,0x61,0x1b,0xb0,0x05,0x43,0x60,0x59,0xb0,0x03,0x25,0xb0,0x02,0x62,0x20,0xb0,0x00,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x01,0x63,0x61,0xb0,0x02,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0x20,0x46,0x23,0x47,0xb0,0x01,0x2b,0x23,0x61,0x38,0x21,0x59,0xb1, +0x30,0x01,0x14,0x2b,0x2d,0xb0,0x47,0x2c,0xb1,0x00,0x3a,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x48,0x2c,0xb1,0x00,0x3b,0x2b,0x21,0x23,0x20,0x20,0x3c,0xb0,0x06,0x23,0x42,0x23,0x38,0xb1,0x30,0x01,0x14,0x2b,0xb0,0x06,0x43,0x2e,0xb0,0x30,0x2b,0x2d,0xb0,0x49,0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00, +0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4a,0x2c,0xb0,0x00,0x15,0x20,0x47,0xb0,0x00,0x23,0x42,0xb2,0x00,0x01,0x01,0x15,0x14,0x13,0x2e,0xb0,0x36,0x2a,0x2d,0xb0,0x4b,0x2c,0xb1,0x00,0x01,0x14,0x13,0xb0,0x37,0x2a,0x2d,0xb0,0x4c,0x2c,0xb0,0x39,0x2a,0x2d,0xb0,0x4d,0x2c,0xb0,0x00,0x16,0x45,0x23,0x20,0x2e,0x20, +0x46,0x8a,0x23,0x61,0x38,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x4e,0x2c,0xb0,0x0a,0x23,0x42,0xb0,0x4d,0x2b,0x2d,0xb0,0x4f,0x2c,0xb2,0x00,0x00,0x46,0x2b,0x2d,0xb0,0x50,0x2c,0xb2,0x00,0x01,0x46,0x2b,0x2d,0xb0,0x51,0x2c,0xb2,0x01,0x00,0x46,0x2b,0x2d,0xb0,0x52,0x2c,0xb2,0x01,0x01,0x46,0x2b,0x2d,0xb0,0x53,0x2c,0xb2,0x00,0x00, +0x47,0x2b,0x2d,0xb0,0x54,0x2c,0xb2,0x00,0x01,0x47,0x2b,0x2d,0xb0,0x55,0x2c,0xb2,0x01,0x00,0x47,0x2b,0x2d,0xb0,0x56,0x2c,0xb2,0x01,0x01,0x47,0x2b,0x2d,0xb0,0x57,0x2c,0xb3,0x00,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x58,0x2c,0xb3,0x00,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x59,0x2c,0xb3,0x01,0x00,0x00,0x43,0x2b,0x2d,0xb0,0x5a,0x2c,0xb3, +0x01,0x01,0x00,0x43,0x2b,0x2d,0xb0,0x5b,0x2c,0xb3,0x00,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5c,0x2c,0xb3,0x00,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5d,0x2c,0xb3,0x01,0x00,0x01,0x43,0x2b,0x2d,0xb0,0x5e,0x2c,0xb3,0x01,0x01,0x01,0x43,0x2b,0x2d,0xb0,0x5f,0x2c,0xb2,0x00,0x00,0x45,0x2b,0x2d,0xb0,0x60,0x2c,0xb2,0x00,0x01,0x45,0x2b,0x2d, +0xb0,0x61,0x2c,0xb2,0x01,0x00,0x45,0x2b,0x2d,0xb0,0x62,0x2c,0xb2,0x01,0x01,0x45,0x2b,0x2d,0xb0,0x63,0x2c,0xb2,0x00,0x00,0x48,0x2b,0x2d,0xb0,0x64,0x2c,0xb2,0x00,0x01,0x48,0x2b,0x2d,0xb0,0x65,0x2c,0xb2,0x01,0x00,0x48,0x2b,0x2d,0xb0,0x66,0x2c,0xb2,0x01,0x01,0x48,0x2b,0x2d,0xb0,0x67,0x2c,0xb3,0x00,0x00,0x00,0x44,0x2b,0x2d, +0xb0,0x68,0x2c,0xb3,0x00,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x69,0x2c,0xb3,0x01,0x00,0x00,0x44,0x2b,0x2d,0xb0,0x6a,0x2c,0xb3,0x01,0x01,0x00,0x44,0x2b,0x2d,0xb0,0x6b,0x2c,0xb3,0x00,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6c,0x2c,0xb3,0x00,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6d,0x2c,0xb3,0x01,0x00,0x01,0x44,0x2b,0x2d,0xb0,0x6e,0x2c,0xb3, +0x01,0x01,0x01,0x44,0x2b,0x2d,0xb0,0x6f,0x2c,0xb1,0x00,0x3c,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x70,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x71,0x2c,0xb1,0x00,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x72,0x2c,0xb0,0x00,0x16,0xb1,0x00,0x3c,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x73,0x2c,0xb1,0x01,0x3c,0x2b,0xb0, +0x40,0x2b,0x2d,0xb0,0x74,0x2c,0xb1,0x01,0x3c,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x75,0x2c,0xb0,0x00,0x16,0xb1,0x01,0x3c,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x76,0x2c,0xb1,0x00,0x3d,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x77,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x78,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x41,0x2b,0x2d, +0xb0,0x79,0x2c,0xb1,0x00,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7a,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7b,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x7c,0x2c,0xb1,0x01,0x3d,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x7d,0x2c,0xb1,0x00,0x3e,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x7e,0x2c,0xb1,0x00,0x3e, +0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x7f,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x80,0x2c,0xb1,0x00,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x81,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x82,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x83,0x2c,0xb1,0x01,0x3e,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x84,0x2c,0xb1, +0x00,0x3f,0x2b,0x2e,0xb1,0x30,0x01,0x14,0x2b,0x2d,0xb0,0x85,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x86,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x41,0x2b,0x2d,0xb0,0x87,0x2c,0xb1,0x00,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x88,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x89,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x41,0x2b, +0x2d,0xb0,0x8a,0x2c,0xb1,0x01,0x3f,0x2b,0xb0,0x42,0x2b,0x2d,0xb0,0x8b,0x2c,0xb2,0x0b,0x00,0x03,0x45,0x50,0x58,0xb0,0x06,0x1b,0xb2,0x04,0x02,0x03,0x45,0x58,0x23,0x21,0x1b,0x21,0x59,0x59,0x42,0x2b,0xb0,0x08,0x65,0xb0,0x03,0x24,0x50,0x78,0xb1,0x05,0x01,0x15,0x45,0x58,0x30,0x59,0x2d,0x00,0x4b,0xb8,0x00,0xc8,0x52,0x58,0xb1, +0x01,0x01,0x8e,0x59,0xb0,0x01,0xb9,0x08,0x00,0x08,0x00,0x63,0x70,0xb1,0x00,0x07,0x42,0xb2,0x19,0x01,0x00,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x0d,0x09,0x01,0x0a,0x2a,0xb1,0x00,0x07,0x42,0xb3,0x16,0x06,0x01,0x0a,0x2a,0xb1,0x00,0x08,0x42,0xba,0x03,0x80,0x00,0x01,0x00,0x0b,0x2a,0xb1,0x00,0x09,0x42,0xba,0x00,0x80,0x00,0x01,0x00, +0x0b,0x2a,0xb9,0x00,0x03,0x00,0x00,0x44,0xb1,0x24,0x01,0x88,0x51,0x58,0xb0,0x40,0x88,0x58,0xb9,0x00,0x03,0x00,0x64,0x44,0xb1,0x28,0x01,0x88,0x51,0x58,0xb8,0x08,0x00,0x88,0x58,0xb9,0x00,0x03,0x00,0x00,0x44,0x59,0x1b,0xb1,0x27,0x01,0x88,0x51,0x58,0xba,0x08,0x80,0x00,0x01,0x04,0x40,0x88,0x63,0x54,0x58,0xb9,0x00,0x03,0x00, +0x00,0x44,0x59,0x59,0x59,0x59,0x59,0xb3,0x10,0x06,0x01,0x0e,0x2a,0xb8,0x01,0xff,0x85,0xb0,0x04,0x8d,0xb1,0x02,0x00,0x44,0xb3,0x05,0x64,0x06,0x00,0x44,0x44,0x00, }; read_only global String8 rd_icon_font_bytes = {rd_icon_font_bytes__data, sizeof(rd_icon_font_bytes__data)}; diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index de4675fc..0f70fa7b 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -6,142 +6,683 @@ @embed_file rd_icon_font_bytes: "../data/icons.ttf" @embed_file rd_default_main_font_bytes: "../data/Roboto-Regular.ttf" +//@embed_file rd_default_main_font_bytes: "../data/seguisb.ttf" @embed_file rd_default_code_font_bytes: "../data/liberation-mono.ttf" //@embed_file rd_default_code_font_bytes: "../data/Inconsolata-Regular.ttf" @embed_file rd_icon_file_bytes: "../data/logo.ico" //////////////////////////////// -//~ rjf: Config Sources +//~ rjf: Fixed Tab Tables -@table(string, name, load_cmd, write_cmd, apply_cmd) -RD_CfgSrcTable: +@table(name display_name name_lower is_query icon description) +RD_WatchTabFastPathTable: { - {"user" User OpenUser WriteUserData ApplyUserData } - {"project" Project OpenProject WriteProjectData ApplyProjectData } - {"command_line" CommandLine Null Null Null } - {"transient" Transient Null Null Null } + {Watch "Watch" watches 0 Binoculars "An editable table interface for entering one or many expressions to evaluate, and visualizing and exploring their values."} + {Locals "Locals" locals 1 Binoculars "Like the Watch tab, but not editable, and displays the set of local variables found at the selected thread's current location."} + {Registers "Registers" registers 1 Binoculars "Like the Watch tab, but not editable, and displays the set of registers for the selected thread."} + {Globals "Globals" globals 1 Binoculars "Like the Watch tab, but not editable, and displays all global variables from all loaded modules."} + {ThreadLocals "Thread Locals" thread_locals 1 Binoculars "Like the Watch tab, but not editable, and displays all thread-local variables from all loaded modules."} + {Types "Types" types 1 Binoculars "Like the Watch tab, but not editable, and displays all types from all loaded modules."} + {Procedures "Procedures" procedures 1 Binoculars "Like the Watch tab, but not editable, and displays all procedures from all loaded modules."} + {CallStack "Call Stack" call_stack 1 Thread "Displays the currently selected thread's call stack, and allows selecting a frame in the call stack, which will unwind the selected thread's registers and evaluate expressions within that frame's context."} + {Targets "Targets" targets 1 Target "Displays, and allows editing of, the list of all targets."} + {Breakpoints "Breakpoints" breakpoints 1 CircleFilled "Displays, and allows editing of, the list of all breakpoints."} + {WatchPins "Watch Pins" watch_pins 1 Pin "Displays, and allows editing of, the list of all watch pins."} + {Threads "Threads" threads 1 Threads "Displays the list of all threads in all processes to which the debugger is attached."} + {Processes "Processes" processes 1 Scheduler "Displays the list of all processes to which the debugger is attached."} + {Machines "Machines" machines 1 Machine "Displays the list of all machines to which the debugger is connected."} + {Modules "Modules" modules 1 Module "Displays the list of all modules in all processes to which the debugger is attached."} + {FilePathMaps "File Path Map" file_path_maps 1 FileOutline "Displays, and allows editing of, the list of all file path maps. This allows remapping source code paths referenced by debug information to other paths on your local machine."} + {TypeViews "Type Views" type_views 1 Binoculars "Displays, and allows editing of, the list of all type views, which allow automatically adjusting the visualizations for evaluations of a certain type."} } -@enum RD_CfgSrc: +@table(name display_name name_lower view query icon) +RD_ViewTabFastPathTable: { - @expand(RD_CfgSrcTable a) `$(a.name)`, - COUNT, + {Output "Output" output text "query:output" List } + {Text "Text" text text "" FileOutline } + {Disasm "Disassembly" disasm disasm "" Glasses } + {Memory "Memory" memory memory "" Grid } + {Bitmap "Bitmap" bitmap bitmap "" Bitmap } + {Color "Color" color color "" Palette } + {Geo3D "Geometry (3D)" geo3d geo3d "" Cube } } -@data(String8) rd_cfg_src_string_table: +@table(name display_name name_lower icon) +RD_FixedTabTable: { - @expand(RD_CfgSrcTable a) `str8_lit_comp("$(a.string)")`, + {GettingStarted "Getting Started" getting_started "getting_started" QuestionMark } } -@data(RD_CmdKind) rd_cfg_src_load_cmd_kind_table: +@gen { - @expand(RD_CfgSrcTable a) `RD_CmdKind_$(a.load_cmd)`, + `#define RD_FixedTabXList \\`; + @expand(RD_WatchTabFastPathTable a) `$(a.is_query -> 'X(' .. a.name_lower .. ')') $(a.is_query == 0 -> 'Y(' .. a.name_lower .. ', watch, ""' .. ')')\\`; + @expand(RD_ViewTabFastPathTable a) `Y($(a.name_lower), $(a.view), "$(a.query)")\\`; + @expand(RD_FixedTabTable a) `Z($(a.name_lower))\\`; + ``; } -@data(RD_CmdKind) rd_cfg_src_write_cmd_kind_table: +@data(String8) rd_tab_fast_path_view_name_table: { - @expand(RD_CfgSrcTable a) `RD_CmdKind_$(a.write_cmd)`, + @expand(RD_WatchTabFastPathTable a) `str8_lit_comp("watch")`, + @expand(RD_ViewTabFastPathTable a) `str8_lit_comp("$(a.view)")`, } -@data(RD_CmdKind) rd_cfg_src_apply_cmd_kind_table: +@data(String8) rd_tab_fast_path_query_name_table: { - @expand(RD_CfgSrcTable a) `RD_CmdKind_$(a.apply_cmd)`; + @expand(RD_WatchTabFastPathTable a) `str8_lit_comp("$(a.is_query -> 'query:' .. a.name_lower)")`, + @expand(RD_ViewTabFastPathTable a) `str8_lit_comp("$(a.query)")`, } //////////////////////////////// -//~ rjf: Entity Kind Tables +//~ rjf: Vocabulary Map -@table(name name_lower name_lower_plural op_delete op_freeze op_edit op_rename op_enable op_cond op_dup name_is_code name_is_path user_lifetime is_serialized name_label icon_kind display_string) -// | | -// | _____________________________________________________________________________________________________________________________________/ -// | / -// operations________ names lt sz -// /..................\ /...\ | | -// dl fz ed rn en cn dp nc np ul iz -RD_EntityKindTable: +@table(code_name code_name_plural display_name display_name_plural icon_kind) +RD_VocabTable: +// NOTE(rjf): the _ character is used as a fastpath for default rules. when +// pluralizing, you just append an `s`, and so on. { - {Nil nil nils 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Nil" } - {Root root roots 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Root" } + {type_view _ "Type View" _ Binoculars } + {file_path_map _ "File Path Map" _ FileOutline } + {watch_pin _ "Watch Pin" _ Pin } + {watch watches "Watch" "Watches" Binoculars } + {view _ "View" _ Binoculars } + {breakpoint _ "Breakpoint" _ CircleFilled } + {condition _ "Condition" _ Null } + {location _ "Location" _ Null } + {source_location _ "Source Location" _ Null } + {address_location _ "Address Location" _ Null } + {target _ "Target" _ Target } + {color _ "Color" _ Palette } + {theme_color _ "Theme Color" _ Palette } + {executable _ "Executable" _ Module } + {arguments arguments "Arguments" "Arguments" Null } + {exe exes "Executable" _ Module } + {dbg dbgs "Debug Info Path" _ Module } + {vaddr_range _ "Virtual Address Range" _ Null } + {min _ "Minimum" _ Null } + {max _ "Maximum" _ Null } + {working_directory working_directories "Working Directory" "Working Directories" FolderClosedFilled } + {entry_point _ "Entry Point" _ Null } + {stdout_path _ "Standard Output Path" _ Null } + {stderr_path _ "Standard Error Path" _ Null } + {stdin_path _ "Standard Input Path" _ Null } + {window _ "Window" _ Window } + {panel _ "Panel" _ Null } + {tab _ "Tab" _ Null } + {recent_project _ "Recent Project" _ Briefcase } + {recent_file _ "Recent File" _ FileOutline } + {src _ "Source" _ Null } + {dst _ "Destination" _ Null } + {source _ "Source" _ Null } + {dest _ "Destination" _ Null } + {conversion_task _ "Conversion Task" _ Null } + {conversion_fail _ "Conversion Fail" _ Null } + {lang _ "Language" _ Null } + {arch _ "Architecture" _ Null } + {expr _ "Expression" _ Null } + {expression _ "Expression" _ Null } + {size _ "Size" _ Null } + {count _ "Count" _ Null } + {bool _ "Boolean" _ Null } + {w _ "Width" _ Null } + {h _ "Height" _ Null } + {fmt _ "Format" _ Null } + {addresses addresses "Addresses" "Addresses" Null } + {code_bytes code_bytes "Code Bytes" "Code Bytes" Null } + {vtx _ "Vertex Buffer" _ Null } + {vtx_size _ "Vertex Buffer Size" _ Null } + {label _ "Label" _ Null } + {thread _ "Thread" _ Thread } + {threads "" "Threads" "" Threads } + {process processes "Process" "Processes" Scheduler } + {processes "" "Processes" "" Scheduler } + {machine _ "Machine" _ Machine } + {module _ "Module" _ Module } + {getting_started "" "Getting Started" "" QuestionMark } + {disasm "" "Disassembly" "" Glasses } + {text "" "Text" "" FileOutline } + {type _ "Type" _ Null } + {procedure _ "Procedure" _ Null } + {global_variable _ "Global Variable" _ Null } + {global _ "Global" _ Null } + {thread_variable _ "Thread Variable" _ Null } + {thread_local _ "Thread Local" _ Null } + {call_stack _ "Call Stack" _ Thread } + {output _ "Output" _ List } + {scheduler _ "Scheduler" _ Scheduler } + {register _ "Register" _ Null } + {local _ "Local" _ Null } + {memory memories "Memory" "Memories" Grid } + {hit_count hit_counts "Hit Count" "Hit Counts" Null } + {enabled "" "Enabled" "Enabled" Null } + {disabled "" "Disabled" "Disabled" Null } + {debug_subprocesses "" "Debug Subprocesses" "" Null } + {environment _ "Environment" _ Null } + {frozen "" "Frozen" "" Null } + {id _ "ID" _ Null } + {last_modified_time _ "Last Modified Time" _ Null } + {creation_time _ "Creation Time" _ Null } + {data _ "Data" _ Null } + {unattached_processes "" "Unattached Processes" "" Scheduler } + {user _ "User" _ Person } + {project _ "Project" _ Briefcase } + {recent_project _ "Recent Project" _ Briefcase } + {recent_file _ "Recent File" _ FileOutline } + {show_addresses "" "Show Addresses" "" Null } + {show_code_bytes "" "Show Code Bytes" "" Null } + {show_source_lines "" "Show Source Lines" "" Null } + {show_symbol_names "" "Show Symbol Names" "" Null } + {show_line_numbers "" "Show Line Numbers" "" Null } + {syntax syntaxes "Syntax" "Syntaxes" Null } + {num_columns "" "Number of Columns" "" Null } + {bytes_per_cell "" "Bytes Per Cell" "" Null } + {bitmap _ "Bitmap" _ Bitmap } + {geo3d "" "Geometry (3D)" "" Cube } + {address_range_size _ "Address Range Size" _ Null } + {break_on_read "" "Break On Read" "" Null } + {break_on_write "" "Break On Write" "" Null } + {break_on_execute "" "Break On Execution" "" Null } + {yaw "" "Yaw" "" Null } + {pitch "" "Pitch" "" Null } + {zoom "" "Zoom" "" Null } + {font_size "" "Font Size" "" Null } + {row_height "" "Row Height" "" Null } + {tab_height "" "Tab Height" "" Null } + {rgba "" "RGBA" "" Palette } +} + +@struct RD_VocabInfo: +{ + `String8 code_name`; + `String8 code_name_plural`; + `String8 display_name`; + `String8 display_name_plural`; + `RD_IconKind icon_kind`; +} + +@data(RD_VocabInfo) rd_vocab_info_table: +{ + @expand(RD_VocabTable a) `{str8_lit_comp("$(a.code_name)"), str8_lit_comp("$(a.code_name_plural == _ -> a.code_name .. 's')$(a.code_name_plural != _ -> a.code_name_plural)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.display_name_plural == _ -> a.display_name .. 's')$(a.display_name_plural != _ -> a.display_name_plural)"), RD_IconKind_$(a.icon_kind)}`; + @expand(D_CmdTable a) `{str8_lit_comp("$(a.string)"), str8_lit_comp(""), str8_lit_comp("$(a.display_name)"), str8_lit_comp(""), RD_IconKind_$(a.canonical_icon)}`; + @expand(RD_CmdTable a) `{str8_lit_comp("$(a.string)"), str8_lit_comp(""), str8_lit_comp("$(a.display_name)"), str8_lit_comp(""), RD_IconKind_$(a.canonical_icon)}`; + @expand(RD_WatchTabFastPathTable a) `{str8_lit_comp("$(a.name_lower)"), str8_lit_comp(""), str8_lit_comp("$(a.display_name)"), str8_lit_comp(""), RD_IconKind_$(a.icon)}`; + @expand(RD_ViewTabFastPathTable a) `{str8_lit_comp("$(a.name_lower)"), str8_lit_comp(""), str8_lit_comp("$(a.display_name)"), str8_lit_comp(""), RD_IconKind_$(a.icon)}`; +} + +//////////////////////////////// +//~ rjf: Schemas + +@table(name schema) RD_SchemaTable: +{ + //- rjf: users / projects + { + user + ``` + @expand_commands(edit_user_theme) x: + { + //- rjf: animations + @display_name('Animations') @description("Enables animations.") + @default(1) 'animations': bool, + @display_name('Scrolling Animations') @description("Enables scrolling animations.") + @expand_if("$.animations") @default(1) 'scrolling_animations': bool, + @display_name('Tooltip Animations') @description("Enables tooltip animations.") + @expand_if("$.animations") @default(1) 'tooltip_animations': bool, + @display_name('Menu Animations') @description("Enables menu animations.") + @expand_if("$.animations") @default(1) 'menu_animations': bool, + + //- rjf: fonts + @display_name('UI Font') @description("The name of, or path to, the font used when displaying non-code UI elements.") + @default('') 'main_font': string, + @display_name('Code Font') @description("The name of, or path to, the font used when displaying code.") + @default('') 'code_font': string, + + //- rjf: theme + @default("Default (Dark)") @display_name('User Theme') + @description("The user's theme, which describes all colors used throughout the UI.") + 'theme': string, + @no_expand @display_name('User Theme') + 'theme_colors': query, + + //- rjf: autocompletion + @display_name('Autocompletion Lister') @description("Enables the autocompletion lister while typing expressions.") @default(1) + 'autocompletion_lister': bool, + @display_name('View Call Argument Helper') @description("Enables the view call argument helper, which shows view arguments and documentation, while typing expressions.") @default(1) + 'view_call_argument_helper': bool, + + //- rjf: thread & breakpoint decorations + @default(1) @display_name('Thread Lines') @description("Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.") + 'thread_lines': bool, + @default(1) @display_name('Thread Glow') @description("Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.") + 'thread_glow': bool, + @default(1) @display_name('Breakpoint Lines') @description("Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.") + 'breakpoint_lines': bool, + @default(1) @display_name('Breakpoint Glow') @description("Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.") + 'breakpoint_glow': bool, + + //- rjf: occluding background settings + @default(0) @display_name('Opaque Backgrounds') @description("Controls whether or not all floating background colors are forced to be fully opaque.") + 'opaque_backgrounds': bool, + @default(1) @display_name('Background Blur') @description("Controls whether or not occluded regions behind floating elements are blurred.") + 'background_blur': bool, + + //- rjf: appearance settings + @default(1) @display_name('Drop Shadows') @description("Controls whether or not drop shadows are drawn.") + 'drop_shadows': bool, + @default(1.f) @display_name('Rounded Corner Amount') @description("Controls the degree to which UI corners are rounded.") + 'rounded_corner_amount': @range[0, 1] f32, + + //- rjf: code formatting settings + @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64, + + //- rjf: windows style menu bar + @default(1) @display_name('Focus Menu Bar With Alt') @description("Mimics standard Windows behavior of focusing the menu bar using the Alt key.") + 'focus_menu_bar_with_alt': bool, + + //- rjf: native filesystem dialogues + @default(0) @display_name('Use Native File System Dialog') @description("Uses the operating system's file system dialog box, rather than the debugger's built-in UI.") + 'use_native_file_system_dialog': bool, + } + ``` + } - //- rjf: auto view rules - {AutoViewRule auto_view_rule auto_view_rules 1 0 0 0 0 0 0 0 0 1 1 "Label" Binoculars "Auto View Rule" } + // TODO(rjf): the control codes could be fed from the CTRL_ExceptionCodeKindTable, but + // we do not support that in this generator - we'd need a way to form a table-generated + // string and put it into a table cell... + { + project + ``` + @expand_commands(edit_project_theme) x: + { + @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64, + + //- rjf: visualizers + @display_name('Use Default C++ STL Type Visualizers') @description("Enables the built-in type views for C++ STL types.") + @default(1) use_default_stl_type_views: bool, + // @display_name('Use Default Unreal Engine Type Visualizers') @description("Enables the built-in type views for Unreal Engine types.") + // @default(1) use_default_ue_type_views: bool, + + //- rjf: theme + @default("None") @display_name('Project Theme') @description("The project's theme, which describes all colors used throughout the UI, and can override the user's theme.") + 'theme': string, + @no_expand @display_name('Project Theme') @description("The project's theme, which describes all colors used throughout the UI, and can override the user's theme.") + 'theme_colors': query, + + //- rjf: exception settings + @default(1) @display_name("Break On Win32 Control-C Exceptions") @description("Code: 0x40010005") + win32_ctrl_c: bool; + @default(1) @display_name("Break On Win32 Control-Break Exceptions") @description("Code: 0x40010008") + win32_ctrl_break: bool; + @default(0) @display_name("Break On Win32 WinRT Originate Error Exceptions") @description("Code: 0x40080201") + win32_win_rt_originate_error: bool; + @default(0) @display_name("Break On Win32 WinRT Transform Error Exceptions") @description("Code: 0x40080202") + win32_win_rt_transform_error: bool; + @default(0) @display_name("Break On Win32 RPC Call Cancelled Exceptions") @description("Code: 0x0000071a") + win32_rpc_call_cancelled: bool; + @default(0) @display_name("Break On Win32 Data Type Misalignment Exceptions") @description("Code: 0x80000002") + win32_datatype_misalignment: bool; + @default(1) @display_name("Break On Win32 Access Violation Exceptions") @description("Code: 0xc0000005") + win32_access_violation: bool; + @default(0) @display_name("Break On Win32 In Page Error Exceptions") @description("Code: 0xc0000006") + win32_in_page_error: bool; + @default(1) @display_name("Break On Win32 Invalid Handle Specified Exceptions") @description("Code: 0xc0000008") + win32_invalid_handle: bool; + @default(0) @display_name("Break On Win32 Not Enough Quota Exceptions") @description("Code: 0xc0000017") + win32_not_enough_quota: bool; + @default(0) @display_name("Break On Win32 Illegal Instruction Exceptions") @description("Code: 0xc000001d") + win32_illegal_instruction: bool; + @default(0) @display_name("Break On Win32 Cannot Continue From Exception Exceptions") @description("Code: 0xc0000025") + win32_cannot_continue_exception: bool; + @default(0) @display_name("Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions") @description("Code: 0xc0000026") + win32_invalid_exception_disposition: bool; + @default(0) @display_name("Break On Win32 Array Bounds Exceeded Exceptions") @description("Code: 0xc000008c") + win32_array_bounds_exceeded: bool; + @default(0) @display_name("Break On Win32 Floating-Point Denormal Operand Exceptions") @description("Code: 0xc000008d") + win32_floating_point_denormal_operand: bool; + @default(0) @display_name("Break On Win32 Floating-Point Division By Zero Exceptions") @description("Code: 0xc000008e") + win32_floating_point_division_by_zero: bool; + @default(0) @display_name("Break On Win32 Floating-Point Inexact Result Exceptions") @description("Code: 0xc000008f") + win32_floating_point_inexact_result: bool; + @default(0) @display_name("Break On Win32 Floating-Point Invalid Operation Exceptions") @description("Code: 0xc0000090") + win32_floating_point_invalid_operation: bool; + @default(0) @display_name("Break On Win32 Floating-Point Overflow Exceptions") @description("Code: 0xc0000091") + win32_floating_point_overflow: bool; + @default(0) @display_name("Break On Win32 Floating-Point Stack Check Exceptions") @description("Code: 0xc0000092") + win32_floating_point_stack_check: bool; + @default(0) @display_name("Break On Win32 Floating-Point Underflow Exceptions") @description("Code: 0xc0000093") + win32_floating_point_underflow: bool; + @default(0) @display_name("Break On Win32 Integer Division By Zero Exceptions") @description("Code: 0xc0000094") + win32_integer_division_by_zero: bool; + @default(0) @display_name("Break On Win32 Integer Overflow Exceptions") @description("Code: 0xc0000095") + win32_integer_overflow: bool; + @default(0) @display_name("Break On Win32 Privileged Instruction Exceptions") @description("Code: 0xc0000096") + win32_privileged_instruction: bool; + @default(0) @display_name("Break On Win32 Stack Overflow Exceptions") @description("Code: 0xc00000fd") + win32_stack_overflow: bool; + @default(0) @display_name("Break On Win32 Unable To Locate DLL Exceptions") @description("Code: 0xc0000135") + win32_unable_to_locate_dll: bool; + @default(0) @display_name("Break On Win32 Ordinal Not Found Exceptions") @description("Code: 0xc0000138") + win32_ordinal_not_found: bool; + @default(0) @display_name("Break On Win32 Entry Point Not Found Exceptions") @description("Code: 0xc0000139") + win32_entry_point_not_found: bool; + @default(0) @display_name("Break On Win32 DLL Initialization Failed Exceptions") @description("Code: 0xc0000142") + win32_dll_initialization_failed: bool; + @default(0) @display_name("Break On Win32 Floating Point SSE Multiple Faults Exceptions") @description("Code: 0xc00002b4") + win32_floating_point_sse_multiple_faults: bool; + @default(0) @display_name("Break On Win32 Floating Point SSE Multiple Traps Exceptions") @description("Code: 0xc00002b5") + win32_floating_point_sse_multiple_traps: bool; + @default(1) @display_name("Break On Win32 Assertion Failed Exceptions") @description("Code: 0xc0000420") + win32_assertion_failed: bool; + @default(0) @display_name("Break On Win32 Module Not Found Exceptions") @description("Code: 0xc06d007e") + win32_module_not_found: bool; + @default(0) @display_name("Break On Win32 Procedure Not Found Exceptions") @description("Code: 0xc06d007f") + win32_procedure_not_found: bool; + @default(1) @display_name("Break On Win32 Sanitizer Error Detected Exceptions") @description("Code: 0xe073616e") + win32_sanitizer_error_detected: bool; + @default(0) @display_name("Break On Win32 Sanitizer Raw Access Violation Exceptions") @description("Code: 0xe0736171") + win32_sanitizer_raw_access_violation: bool; + @default(1) @display_name("Break On Win32 DirectX Debug Layer Exceptions") @description("Code: 0x0000087a") + win32_directx_debug_layer: bool; + } + ``` + } - //- rjf: file path maps - {FilePathMap file_path_map file_path_maps 1 0 0 0 0 0 0 0 0 0 1 "Label" FileOutline "File Path Map" } + //- rjf: theme colors + { + theme_color, + ``` + @collection_commands(add_theme_color, fork_theme, save_theme, save_and_set_theme) + @row_commands(duplicate_cfg, remove_cfg) + x: + { + @display_name('Tags') tags: string, + @display_name('Value') value: @color @hex u32, + } + ``` + } - //- rjf: watch pins - {WatchPin watch_pin watch_pins 1 0 0 1 0 0 1 1 0 1 1 "Expression" Pin "Watch Pin" } + //- rjf: windows + { + window, + ``` + x: + { + //- rjf: text rasterization settings + @default(1) @display_name('Smooth UI Text') @description("Controls whether or not UI text is fully anti-aliased, for a smoother appearance.") + 'smooth_ui_text': bool, + @default(1) @display_name('Hint UI Text') @description("Controls whether or not UI text is hinted, for better text readability at small sizes.") + 'hint_ui_text': bool, + @default(0) @display_name('Smooth Code Text') @description("Controls whether or not code text is fully anti-aliased, for a smoother appearance.") + 'smooth_code_text': bool, + @default(1) @display_name('Hint Code Text') @description("Controls whether or not code text is hinted, for better text readability at small sizes.") + 'hint_code_text': bool, + @default(11) @display_name('Window Font Size') @description("Controls the window's default font size. Does not apply to tabs with their own font size set.") + 'font_size': @range[6, 72] u64, + + //- rjf: size settings + @default(3.f) @display_name('Window Row Height') @description("Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.") + 'row_height': @range[1.75f, 5.f] f32, + @default(3.f) @description("Controls the height of tabs, in multiples of the font size.") + 'tab_height': @range[1.75f, 5.f] f32, + + //- rjf: theme settings + @default(1) @display_name('Use Project Theme') @description("Prefer using the project theme for this window, if any. If off, only the user's theme settings will be used.") + 'use_project_theme': bool, + } + ``` + } - //- rjf: watches - {Watch watch watches 1 0 0 1 1 0 1 1 0 1 1 "Expression" Binoculars "Watch" } - {ViewRule view_rule view_rules 1 0 0 1 1 0 1 1 0 1 0 "Expression" Binoculars "View Rule" } + //- rjf: tabs + { + tab, + ``` + @row_commands(@file copy_tab_full_path, @file show_file_in_explorer, duplicate_tab, close_tab) + x: + { + @override @display_name('Tab Font Size') @description("Controls the tab's font size.") @no_callee_helper + 'font_size': @range[6, 72] u64, + } + ``` + } - //- rjf: breakpoints - {Breakpoint breakpoint breakpoints 1 0 0 1 1 1 1 1 0 1 1 "Label" CircleFilled "Breakpoint" } - {Condition condition conditions 0 0 0 0 0 0 0 1 0 1 0 "Expression" CircleFilled "Condition" } + //- rjf: views + { + watch, + ``` + @inherit(tab) x: + { + @override @display_name('Tab Row Height') @description("Controls the tab's row height, in multiples of the font size.") + 'row_height': @range[1.75f, 5.f] f32, + 'label': code_string, + @description("The root expression which is evaluated to produce the watch window.") + 'expression': expr_string, + @no_expand 'watches': query, + } + ``` + } + { + text, + ``` + @inherit(tab) x: + { + @description("An expression to describe data which should be viewed as text or code.") + 'expression': expr_string, + @description("The language that the text should be interpreted as being within. Used for syntax highlighting and other parsing features.") + 'lang': code_string, + @default(1) @description("Controls whether or not line numbers are shown.") + 'show_line_numbers':bool, + @no_callee_helper @default(0) @display_name('Scroll To Bottom On Change') @description("Scrolls to the bottom if the text is changed.") + 'scroll_to_bottom_on_change':bool, + @no_callee_helper @no_revert @default(0) @display_name('Transient') @description("Controls whether or not this tab will be automatically replaced by the debugger when it snaps to new source code locations.") + 'auto': bool, + } + ``` + } + { + disasm, + ``` + @inherit(tab) x: + { + @description("An expression to describe the base address or offset of the disassembly.") + 'expression': expr_string, + 'arch': code_string, + 'syntax': code_string, + 'size': expr_string, + @no_callee_helper @default(1) @description("Controls whether or not addresses are shown in the disassembly text.") + 'show_addresses': bool, + @no_callee_helper @default(0) @description("Controls whether or not code bytes are shown in the disassembly text.") + 'show_code_bytes': bool, + @no_callee_helper @default(1) @description("Controls whether or not source lines, corresponding to disassembly instruction ranges, are shown in the disassembly text.") + 'show_source_lines': bool, + @no_callee_helper @default(1) @description("Controls whether or not disassembly text is decorated with symbol names.") + 'show_symbol_names': bool, + @no_callee_helper @default(1) @description("Controls whether or not line numbers are shown.") + 'show_line_numbers': bool, + } + ``` + } + { + memory, + ``` + @inherit(tab) x: + { + @description("An expression which refers to the data which should be viewed as memory.") + 'expression': expr_string, + @display_name("Address Range Size") @description("The number of bytes of the viewed memory range.") + 'size': expr_string, + @display_name("Cursor Address") @description("The address of the cursor.") + 'cursor': expr_string, + @display_name("Cursor Size") @description("The size, in bytes, of the cursor.") + 'cursor_size': @range[1, 16] u64, + @default(16) @description("The number of columns to build before building new rows.") + 'num_columns': @range[1, 64] u64, + } + ``` + } + { + bitmap, + ``` + @inherit(tab) x: + { + @description("An expression which refers to the data which should be viewed as a bitmap.") + 'expression': expr_string, + @description("An expression describing the width of the bitmap, in pixels.") @order(0) 'w': u64, + @description("An expression describing the height of the bitmap, in pixels.") @order(1) 'h': u64, + @display_name("Bitmap Format") @description("The pixel format that the bitmap data should be interpreted as being within.") + 'fmt': code_string, + } + ``` + } + { + color, + ``` + @inherit(tab) x: + { + @display_name("Value") @description("An expression to describe the value or location of the color.") + 'expression': expr_string, + } + ``` + } + { + geo3d, + ``` + @inherit(tab) x: + { + @display_name("Expression") @description("An expression to describe the base address of the index buffer.") + 'expression': expr_string, + 'count': expr_string, + 'vtx': expr_string, + 'vtx_size': expr_string, + 'yaw': @range[0, 1] f32, + 'pitch': @range[-0.5, 0] f32, + 'zoom': @range[0, 100] f32, + } + ``` + } - //- rjf: user-controlled locations (source, addresses, symbol names) - {Location location locations 0 0 0 0 0 0 0 1 1 1 0 "Location" Null "Location" } + //- rjf: getting started + { + getting_started, + ``` + @inherit(tab) x: + { + } + ``` + } //- rjf: targets - {Target target targets 1 0 1 1 1 0 1 0 0 1 1 "Label" Target "Target" } - {Executable executable executables 0 0 0 0 0 0 0 0 1 1 0 "Executable" Null "Executable" } - {Arguments arguments argumentses 0 0 0 0 0 0 0 0 0 1 0 "Arguments" Null "Arguments" } - {WorkingDirectory working_directory working_directories 0 0 0 0 0 0 0 0 1 1 0 "Path" Null "Working Directory" } - {EntryPoint entry_point entry_points 0 0 0 0 0 0 0 0 0 1 0 "Symbol Name" Null "Entry Point" } - {StdoutPath stdout_path stdout_paths 0 0 0 0 0 0 0 0 1 1 0 "Path" Null "Standard Output Path" } - {StderrPath stderr_path stderr_paths 0 0 0 0 0 0 0 0 1 1 0 "Path" Null "Standard Error Path" } - {StdinPath stdin_path stdin_paths 0 0 0 0 0 0 0 0 1 1 0 "Path" Null "Standard Input Path" } + { + target, + ``` + @row_commands(@cmd_line save_cfg_to_project, enable_cfg, launch_and_run, launch_and_step_into, duplicate_cfg, remove_cfg) + @collection_commands(add_target) + x: + { + 'label': code_string, + 'executable': path, + 'arguments': string, + 'working_directory': path, + 'entry_point': expr_string, + 'stdout_path': @no_relativize path, + 'stderr_path': @no_relativize path, + 'stdin_path': @no_relativize path, + 'environment': query, + 'debug_subprocesses': bool, + @no_revert @no_expand @default(0) 'enabled': bool, + } + ```, + } - //- rjf: frontend containers (windows, panels, views) - {Window window windows 1 0 0 0 0 0 1 0 0 1 1 "Label" Window "Window" } - {Panel panel panels 1 0 0 0 0 0 1 0 0 1 1 "Label" XSplit "Panel" } - {View view views 1 0 0 0 0 0 1 0 0 1 1 "Label" Null "View" } + //- rjf: breakpoints + { + breakpoint, + ``` + @row_commands(enable_cfg, duplicate_cfg, remove_cfg) + @collection_commands(toggle_breakpoint, add_breakpoint, add_address_breakpoint, add_function_breakpoint, clear_breakpoints) + x: + { + 'label': code_string, + 'condition': expr_string, + 'source_location': path_pt, + 'address_location': expr_string, + 'hit_count': u64, + 'address_range_size': @or(0, 1, 2, 4, 8) u64, + 'break_on_write': bool, + 'break_on_read': bool, + 'break_on_execute': bool, + @no_revert @no_expand @default(1) 'enabled': bool, + } + ```, + } + + //- rjf: watch pins + { + watch_pin, + ``` + @row_commands(duplicate_cfg, remove_cfg) + @collection_commands(add_watch_pin, toggle_watch_pin) + x: + { + 'expression': expr_string, + 'source_location': path_pt, + 'address_location': expr_string, + } + ```, + } + + //- rjf: file path maps + { + file_path_map, + ```@collection_commands(add_file_path_map) @row_commands(remove_cfg) x:{'source': @no_relativize path, 'dest': @no_relativize path}```, + } + + //- rjf: type views + { + type_view, + ```@collection_commands(add_type_view) @row_commands(remove_cfg) x:{'type':expr_string, 'expr':expr_string}```, + } //- rjf: recent projects - {RecentProject recent_project recent_projects 0 0 0 0 0 0 0 0 1 0 1 "Path" Briefcase "Recent Project" } + { + recent_project, + ```x:{'path':path}```, + } //- rjf: recent files - {RecentFile recent_file recent_files 0 0 0 0 0 0 0 0 1 0 1 "Path" FileOutline "Recent File" } + { + recent_file, + ```x:{'path':path}```, + } - //- rjf: src -> dst mapping - {Source source sources 0 0 0 0 0 0 0 0 0 0 0 "Path" Null "Source" } - {Dest dest dests 0 0 0 0 0 0 0 0 0 0 0 "Path" Null "Destination" } - - //- rjf: parser task entities - {ConversionTask conversion_task conversion_tasks 0 0 0 1 0 0 0 0 0 0 0 "Label" Null "Conversion Task" } - {ConversionFail conversion_fail conversion_fails 0 0 0 1 0 0 0 0 0 0 0 "Label" Null "Conversion Failure" } + //- rjf: control entities + { + machine, + ```x:{'label':code_string, @no_expand 'active':bool, 'unattached_processes':query, 'processes':query}```, + } + { + process, + ```x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'modules':query, 'threads':query}```, + } + { + module, + ```x:{'exe':path, 'dbg':path, 'vaddr_range':vaddr_range}```, + } + { + thread, + ```x:{'label':code_string, 'id':u64, @no_expand 'active':bool, 'call_stack':query}```, + } } -@enum RD_EntityKind: +@struct RD_NameSchemaInfo: { - @expand(RD_EntityKindTable a) `$(a.name)`, - COUNT, + `String8 name`; + `String8 schema`; } -@data(String8) d_entity_kind_display_string_table: +@data(RD_NameSchemaInfo) rd_name_schema_info_table: { - @expand(RD_EntityKindTable a) `str8_lit_comp("$(a.display_string)")`, -} - -@data(String8) d_entity_kind_name_lower_table: -{ - @expand(RD_EntityKindTable a) `str8_lit_comp("$(a.name_lower)")`, -} - -@data(String8) d_entity_kind_name_lower_plural_table: -{ - @expand(RD_EntityKindTable a) `str8_lit_comp("$(a.name_lower_plural)")`, -} - -@data(String8) d_entity_kind_name_label_table: -{ - @expand(RD_EntityKindTable a) `str8_lit_comp("$(a.name_label)")`, -} - -@data(RD_EntityKindFlags) rd_entity_kind_flags_table: -{ - @expand(RD_EntityKindTable a) `($(a.op_delete)*RD_EntityKindFlag_CanDelete) | ($(a.op_freeze)*RD_EntityKindFlag_CanFreeze) | ($(a.op_edit)*RD_EntityKindFlag_CanEdit) | ($(a.op_rename)*RD_EntityKindFlag_CanRename) | ($(a.op_enable)*RD_EntityKindFlag_CanEnable) | ($(a.op_cond)*RD_EntityKindFlag_CanCondition) | ($(a.op_dup)*RD_EntityKindFlag_CanDuplicate) | ($(a.name_is_code)*RD_EntityKindFlag_NameIsCode) | ($(a.name_is_path)*RD_EntityKindFlag_NameIsPath) | ($(a.user_lifetime)*RD_EntityKindFlag_UserDefinedLifetime) | ($(a.is_serialized)*RD_EntityKindFlag_IsSerializedToConfig)`, + @expand(RD_SchemaTable a) `{str8_lit_comp("$(a.name)"), str8_lit_comp("$(a.schema)")}` } //////////////////////////////// @@ -150,46 +691,62 @@ RD_EntityKindTable: @table(c_type name_lower name) RD_RegTable: { - // rjf: entity slots + // rjf: ctrl entities {CTRL_Handle machine Machine } {CTRL_Handle module Module } {CTRL_Handle process Process } {CTRL_Handle thread Thread } {CTRL_Handle ctrl_entity CtrlEntity } - {RD_Handle window Window } - {RD_Handle panel Panel } - {RD_Handle view View } - {RD_Handle prev_view PrevView } - {RD_Handle dst_panel DstPanel } - {RD_Handle entity Entity } - {RD_HandleList entity_list EntityList } + + // rjf: cfgs + {RD_CfgID window Window } + {RD_CfgID panel Panel } + {RD_CfgID tab Tab } + {RD_CfgID view View } + {RD_CfgID prev_tab PrevTab } + {RD_CfgID dst_panel DstPanel } + {RD_CfgID cfg Cfg } + {RD_CfgIDList cfg_list CfgList } // rjf: frame selection - {U64 unwind_count UnwindCount } - {U64 inline_depth InlineDepth } + {U64 unwind_count UnwindCount } + {U64 inline_depth InlineDepth } // rjf: code / address location info - {String8 file_path FilePath } - {TxtPt cursor Cursor } - {TxtPt mark Mark } - {U128 text_key TextKey } - {TXT_LangKind lang_kind LangKind } - {D_LineList lines Lines } - {DI_Key dbgi_key DbgiKey } - {U64 vaddr Vaddr } - {U64 voff Voff } - {Rng1U64 vaddr_range VaddrRange } - {Rng1U64 voff_range VoffRange } + {String8 file_path FilePath } + {TxtPt cursor Cursor } + {TxtPt mark Mark } + {HS_Key text_key TextKey } + {TXT_LangKind lang_kind LangKind } + {D_LineList lines Lines } + {DI_Key dbgi_key DbgiKey } + {U64 vaddr Vaddr } + {U64 voff Voff } + {Rng1U64 vaddr_range VaddrRange } + {Rng1U64 voff_range VoffRange } + + // rjf: evaluation + {String8 expr Expr } + + // rjf: ui context + {UI_Key ui_key UIKey } + {Vec2F32 off_px OffPx } + {RD_RegSlot reg_slot RegSlot } // rjf: general parameters - {U32 pid PID } - {B32 force_confirm ForceConfirm } - {B32 prefer_disasm PreferDisasm } - {Dir2 dir2 Dir2 } - {String8 string String } - {String8 cmd_name CmdName } - {`MD_Node *` params_tree ParamsTree } - {`OS_Event *` os_event OSEvent } + {U32 pid PID } + {B32 force_confirm ForceConfirm } + {B32 force_focus ForceFocus } + {B32 prefer_disasm PreferDisasm } + {B32 no_rich_tooltip NoRichTooltip } + {B32 do_implicit_root DoImplicitRoot} + {B32 do_lister DoLister } + {B32 do_big_rows DoBigRows } + {Dir2 dir2 Dir2 } + {String8 string String } + {String8 cmd_name CmdName } + {`MD_Node *` params_tree ParamsTree } + {`OS_Event *` os_event OSEvent } } @enum RD_RegSlot: @@ -220,269 +777,275 @@ RD_RegTable: //////////////////////////////// //~ rjf: Command Table -@table(name ui_vis ipc_docs_vis q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_required canonical_icon string display_name desc search_tags ) -// / | | | \___ _____________________________________________________/ | | | | | -// / | | | \ / | | | | | -RD_CmdTable: // | | | | | | | | | | +@table(name ui_vis ipc_docs_vis text_pt_vis text_rng_vis q_expr q_slot q_view q_ent_kind q_ctrl_ent_kind q_allow_files q_allow_folders q_keep_oi q_select_oi q_is_code q_floating q_required canonical_icon string display_name desc search_tags ctx_filter) +// / | | | | | \___ __________________________/ | | | | | | +// / | | | | | \ / | | | | | | +RD_CmdTable: // | | | | | | | | | | | | | { //- rjf: exiting - {Exit 1 1 Null null Nil Null 0 0 0 0 0 0 X "exit" "Exit" "Exits the debugger." "quit,close,abort" } + {Exit 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 X "exit" "Exit" "Exits the debugger." "quit,close,abort" "" } + + //- rjf: palette + {OpenPalette 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 List "open_palette" "Open Palette" "Opens the palette." "help,cmd,lister" "" } //- rjf: command runner - {RunCommand 1 1 CmdName commands Nil Null 0 0 0 0 0 1 Null "run_command" "Run Command" "Runs a command from the command palette." "help,cmd" } + {RunCommand 1 1 0 0 "query:commands" CmdName commands Nil Null 0 0 0 0 0 1 1 Null "run_command" "Run Command" "Runs a command from the command palette." "help,cmd" "" } //- rjf: os event passthrough - {OSEvent 0 0 Null null Nil Null 0 0 0 0 0 0 Null "os_event" "OS Event" "" "" } + {OSEvent 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "os_event" "OS Event" "" "" "" } //- rjf: thread/frame selection - {SelectThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Null "select_thread" "Select Thread" "Selects a thread." "" } - {SelectUnwind 0 1 Null null Nil Null 0 0 0 0 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" } - {UpOneFrame 1 1 Null null Nil Null 0 0 0 0 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the call stack frame above the currently selected." "" } - {DownOneFrame 1 1 Null null Nil Null 0 0 0 0 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the call stack frame below the currently selected." "callstack,unwind" } + {SelectThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Thread "select_thread" "Select Thread" "Selects a thread." "" "" } + {SelectUnwind 0 1 0 0 "query:call_stack" Null null Nil Null 0 0 0 0 0 0 0 Null "select_unwind" "Select Unwind" "Selects an unwind frame number for the selected thread." "" "" } + {UpOneFrame 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 UpArrow "up_one_frame" "Up One Frame" "Selects the call stack frame above the currently selected." "" "" } + {DownOneFrame 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 DownArrow "down_one_frame" "Down One Frame" "Selects the call stack frame below the currently selected." "callstack,unwind" "" } + {SelectEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RadioHollow "select_entity" "Select" "Selects a control entity." "" "" } + {DeselectEntity 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RadioFilled "deselect_entity" "Deselect" "Deselects a control entity." "" "" } //- rjf: font sizes - {IncUIFontScale 1 1 Null null Nil Null 0 0 0 0 0 0 Null "inc_ui_font_scale" "Increase UI Font Scale" "Increases the font size used for UI." "" } - {DecUIFontScale 1 1 Null null Nil Null 0 0 0 0 0 0 Null "dec_ui_font_scale" "Decrease UI Font Scale" "Decreases the font size used for UI." "" } - {IncCodeFontScale 1 1 Null null Nil Null 0 0 0 0 0 0 Null "inc_code_font_scale" "Increase Code Font Scale" "Increases the font size used for code." "" } - {DecCodeFontScale 1 1 Null null Nil Null 0 0 0 0 0 0 Null "dec_code_font_scale" "Decrease Code Font Scale" "Decreases the font size used for code." "" } + {IncWindowFontSize 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "inc_window_font_size" "Increase Window Font Size" "Increases the window's font size by one point." "" "" } + {DecWindowFontSize 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "dec_window_font_size" "Decrease Window Font Size" "Decreases the window's font size by one point." "" "" } + {IncViewFontSize 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "inc_view_font_size" "Increase View Font Size" "Increases the view's font size by one point." "" "" } + {DecViewFontSize 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "dec_view_font_size" "Decrease View Font Size" "Decreases the view's font size by one point." "" "" } //- rjf: windows - {OpenWindow 1 1 Null null Nil Null 0 0 0 0 0 0 Window "open_window" "Open New Window" "Opens a new window." "" } - {CloseWindow 1 1 Null null Nil Null 0 0 0 0 0 0 Window "close_window" "Close Window" "Closes an opened window." "" } - {ToggleFullscreen 1 1 Null null Nil Null 0 0 0 0 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" } - {BringToFront 0 1 Null null Nil Null 0 0 0 0 0 0 Window "bring_to_front" "Bring To Front" "Brings all windows to the front, and focuses the most recently focused window." "top" } + {OpenWindow 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "open_window" "Open New Window" "Opens a new window." "" "" } + {WindowSettings 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Gear "window_settings" "Window Settings" "Opens settings for a window." "" "" } + {CloseWindow 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "close_window" "Close Window" "Closes an opened window." "" "" } + {ToggleFullscreen 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "toggle_fullscreen" "Toggle Fullscreen" "Toggles fullscreen view on the active window." "" "" } + {BringToFront 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "bring_to_front" "Bring To Front" "Brings all windows to the front, and focuses the most recently focused window." "top" "" } //- rjf: popups - {PopupAccept 0 1 Null null Nil Null 0 0 0 0 0 0 Null "popup_accept" "Popup Accept" "Accepts the active popup prompt." "" } - {PopupCancel 0 1 Null null Nil Null 0 0 0 0 0 0 Null "popup_cancel" "Popup Cancel" "Cancels the active popup prompt." "" } + {PopupAccept 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "popup_accept" "Popup Accept" "Accepts the active popup prompt." "" "" } + {PopupCancel 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "popup_cancel" "Popup Cancel" "Cancels the active popup prompt." "" "" } + + //- rjf: keybindings + {ResetToDefaultBindings 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "reset_to_default_bindings" "Reset To Default Bindings" "Resets all keybindings to their defaults." "" "" } //- rjf: panel splitting - {ResetToDefaultPanels 1 1 Null null Nil Null 0 0 0 0 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" } - {ResetToCompactPanels 1 1 Null null Nil Null 0 0 0 0 0 0 Window "reset_to_compact_panels" "Reset To Compact Panel Layout" "Resets the window to the compact panel layout." "panel" } - {NewPanelLeft 1 1 Null null Nil Null 0 0 0 0 0 0 XSplit "new_panel_left" "Split Panel Left" "Creates a new panel to the left of the active panel." "panel" } - {NewPanelUp 1 1 Null null Nil Null 0 0 0 0 0 0 YSplit "new_panel_up" "Split Panel Up" "Creates a new panel at the top of the active panel." "panel" } - {NewPanelRight 1 1 Null null Nil Null 0 0 0 0 0 0 XSplit "new_panel_right" "Split Panel Right" "Creates a new panel to the right of the active panel." "panel" } - {NewPanelDown 1 1 Null null Nil Null 0 0 0 0 0 0 YSplit "new_panel_down" "Split Panel Down" "Creates a new panel at the bottom of the active panel." "panel" } - {SplitPanel 0 0 Null null Nil Null 0 0 0 0 0 0 Null "split_panel" "Split Panel" "Creates a new panel in a given direction, and moves a tab to it, if specified." "" } + {ResetToDefaultPanels 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "reset_to_default_panels" "Reset To Default Panel Layout" "Resets the window to the default panel layout." "panel" "" } + {ResetToCompactPanels 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "reset_to_compact_panels" "Reset To Compact Panel Layout" "Resets the window to the compact panel layout." "panel" "" } + {ResetToSimplePanels 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Window "reset_to_simple_panels" "Reset To Simple Panel Layout" "Resets the window to the simple panel layout." "panel" "" } + {NewPanelLeft 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 XSplit "new_panel_left" "Split Panel Left" "Creates a new panel to the left of the active panel." "panel" "" } + {NewPanelUp 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 YSplit "new_panel_up" "Split Panel Up" "Creates a new panel at the top of the active panel." "panel" "" } + {NewPanelRight 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 XSplit "new_panel_right" "Split Panel Right" "Creates a new panel to the right of the active panel." "panel" "" } + {NewPanelDown 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 YSplit "new_panel_down" "Split Panel Down" "Creates a new panel at the bottom of the active panel." "panel" "" } + {SplitPanel 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "split_panel" "Split Panel" "Creates a new panel in a given direction, and moves a tab to it, if specified." "" "" } //- rjf: panel rotation - {RotatePanelColumns 1 1 Null null Nil Null 0 0 0 0 0 0 Null "rotate_panel_columns" "Rotate Panel Columns" "Rotates all panels at the closest column level of the panel hierarchy." "" } + {RotatePanelColumns 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "rotate_panel_columns" "Rotate Panel Columns" "Rotates all panels at the closest column level of the panel hierarchy." "" "" } //- rjf: focused panel changing - {NextPanel 1 1 Null null Nil Null 0 0 0 0 0 0 RightArrow "next_panel" "Focus Next Panel" "Cycles the active panel forward." "" } - {PrevPanel 1 1 Null null Nil Null 0 0 0 0 0 0 LeftArrow "prev_panel" "Focus Previous Panel" "Cycles the active panel backwards." "" } - {FocusPanel 0 0 Null null Nil Null 0 0 0 0 0 0 Null "focus_panel" "Focus Panel" "Focuses a new panel." "" } - {FocusPanelRight 1 1 Null null Nil Null 0 0 0 0 0 0 RightArrow "focus_panel_right" "Focus Panel Right" "Focuses a panel rightward of the currently focused panel." "" } - {FocusPanelLeft 1 1 Null null Nil Null 0 0 0 0 0 0 LeftArrow "focus_panel_left" "Focus Panel Left" "Focuses a panel leftward of the currently focused panel." "" } - {FocusPanelUp 1 1 Null null Nil Null 0 0 0 0 0 0 UpArrow "focus_panel_up" "Focus Panel Up" "Focuses a panel upward of the currently focused panel." "" } - {FocusPanelDown 1 1 Null null Nil Null 0 0 0 0 0 0 DownArrow "focus_panel_down" "Focus Panel Down" "Focuses a panel downward of the currently focused panel." "" } + {NextPanel 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "next_panel" "Focus Next Panel" "Cycles the active panel forward." "" "" } + {PrevPanel 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 LeftArrow "prev_panel" "Focus Previous Panel" "Cycles the active panel backwards." "" "" } + {FocusPanel 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "focus_panel" "Focus Panel" "Focuses a new panel." "" "" } + {FocusPanelRight 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "focus_panel_right" "Focus Panel Right" "Focuses a panel rightward of the currently focused panel." "" "" } + {FocusPanelLeft 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 LeftArrow "focus_panel_left" "Focus Panel Left" "Focuses a panel leftward of the currently focused panel." "" "" } + {FocusPanelUp 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 UpArrow "focus_panel_up" "Focus Panel Up" "Focuses a panel upward of the currently focused panel." "" "" } + {FocusPanelDown 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 DownArrow "focus_panel_down" "Focus Panel Down" "Focuses a panel downward of the currently focused panel." "" "" } //- rjf: undo/redo - {Undo 0 0 Null null Nil Null 0 0 0 0 0 0 Undo "undo" "Undo" "Undoes the previous action." "" } - {Redo 0 0 Null null Nil Null 0 0 0 0 0 0 Redo "redo" "Redo" "Redoes the first previously undone action." "" } + {Undo 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Undo "undo" "Undo" "Undoes the previous action." "" "" } + {Redo 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Redo "redo" "Redo" "Redoes the first previously undone action." "" "" } //- rjf: focus history - {GoBack 0 0 Null null Nil Null 0 0 0 0 0 0 LeftArrow "go_back" "Go Back" "Returns to the previously selected panel and tab in recorded history." "" } - {GoForward 0 0 Null null Nil Null 0 0 0 0 0 0 RightArrow "go_forward" "Go Forward" "Returns to the next selected panel and tab in recorded history." "" } + {GoBack 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 LeftArrow "go_back" "Go Back" "Returns to the previously selected panel and tab in recorded history." "" "" } + {GoForward 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "go_forward" "Go Forward" "Returns to the next selected panel and tab in recorded history." "" "" } //- rjf: panel removal - {ClosePanel 1 1 Null null Nil Null 0 0 0 0 0 0 ClosePanel "close_panel" "Close Panel" "Closes the currently active panel." "" } + {ClosePanel 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 ClosePanel "close_panel" "Close Panel" "Closes the currently active panel." "" "" } //- rjf: panel tab - {NextTab 1 1 Null null Nil Null 0 0 0 0 0 0 RightArrow "next_tab" "Focus Next Tab" "Focuses the next tab on the active panel." "" } - {PrevTab 1 1 Null null Nil Null 0 0 0 0 0 0 LeftArrow "prev_tab" "Focus Previous Tab" "Focuses the previous tab on the active panel." "" } - {MoveTabRight 1 1 Null null Nil Null 0 0 0 0 0 0 RightArrow "move_tab_right" "Move Tab Right" "Moves the selected tab right one slot." "" } - {MoveTabLeft 1 1 Null null Nil Null 0 0 0 0 0 0 LeftArrow "move_tab_left" "Move Tab Left" "Moves the selected tab left one slot." "" } - {OpenTab 0 0 Null null Nil Null 0 0 0 0 0 0 Null "open_tab" "Open Tab" "Opens a new tab with the parameterized view specification." "" } - {CloseTab 1 1 Null null Nil Null 0 0 0 0 0 0 X "close_tab" "Close Tab" "Closes the currently opened tab." "" } - {MoveTab 0 0 Null null Nil Null 0 0 0 0 0 0 Null "move_tab" "Move Tab" "Moves a tab to a new panel." "" } - {TabBarTop 1 1 Null null Nil Null 0 0 0 0 0 0 UpArrow "tab_bar_top" "Anchor Tab Bar To Top" "Anchors a panel's tab bar to the top of the panel." "" } - {TabBarBottom 1 1 Null null Nil Null 0 0 0 0 0 0 DownArrow "tab_bar_bottom" "Anchor Tab Bar To Bottom" "Anchors a panel's tab bar to the bottom of the panel." "" } + {FocusTab 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "focus_tab" "Focus Tab" "Focuses the passed tab within its containing panel." "" "" } + {NextTab 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "next_tab" "Focus Next Tab" "Focuses the next tab on the active panel." "" "" } + {PrevTab 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 LeftArrow "prev_tab" "Focus Previous Tab" "Focuses the previous tab on the active panel." "" "" } + {MoveTabRight 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "move_tab_right" "Move Tab Right" "Moves the selected tab right one slot." "" "$tab," } + {MoveTabLeft 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 LeftArrow "move_tab_left" "Move Tab Left" "Moves the selected tab left one slot." "" "$tab," } + {OpenTab 1 1 0 0 "query:tab_commands" CmdName commands Nil Null 0 0 0 0 0 1 1 Null "open_tab" "Open New Tab" "Opens a new tab." "" "" } + {BuildTab 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "build_tab" "Build Tab" "Opens a new tab with the parameterized view specification." "" "" } + {DuplicateTab 1 1 0 0 "" Tab null Nil Null 0 0 0 0 0 0 0 Duplicate "duplicate_tab" "Duplicate Tab" "Duplicates a tab." "" "$tab," } + {CopyTabFullPath 0 0 0 0 "" Tab null Nil Null 0 0 0 0 0 0 0 Clipboard "copy_tab_full_path" "Copy Full Path" "Copies the full path of the file being viewed by this tab." "" "$tab," } + {CloseTab 1 1 0 0 "" Tab null Nil Null 0 0 0 0 0 0 0 X "close_tab" "Close Tab" "Closes the currently opened tab." "" "$tab," } + {MoveView 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_view" "Move View" "Moves a view to a new panel." "" "" } + {TabBarTop 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 UpArrow "tab_bar_top" "Anchor Tab Bar To Top" "Anchors a panel's tab bar to the top of the panel." "" "$tab," } + {TabBarBottom 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 DownArrow "tab_bar_bottom" "Anchor Tab Bar To Bottom" "Anchors a panel's tab bar to the bottom of the panel." "" "$tab," } + {TabSettings 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Gear "tab_settings" "Tab Settings" "Opens settings for a tab." "" "" } //- rjf: files - {SetCurrentPath 0 1 Null null Nil Null 0 0 0 0 0 0 FileOutline "set_current_path" "Set Current Path" "Sets the debugger's current path, which is used as a starting point when browsing for files." "" } - {Open 1 1 FilePath null Nil Null 1 0 0 0 0 1 FileOutline "open" "Open" "Opens a file." "code,source,file" } - {Switch 1 1 Entity null RecentFile Null 0 0 0 0 0 1 FileOutline "switch" "Switch" "Switches to a recent file." "code,source,file" } - {SwitchToPartnerFile 1 1 Null null Nil Null 0 0 0 0 0 0 FileOutline "switch_to_partner_file" "Switch To Partner File" "Switches to the focused file's partner; or from header to implementation or vice versa." "code,source,file" } - {RecordFileInProject 0 0 Null null Nil Null 0 0 0 0 0 0 FileOutline "record_file_in_project" "Record File In Project" "Records the passed file path as a recent file in the currently loaded project." "" } + {SetCurrentPath 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FileOutline "set_current_path" "Set Current Path" "Sets the debugger's current path, which is used as a starting point when browsing for files." "" "" } + {Open 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 FileOutline "open" "Open" "Opens a file." "code,source,file" "" } + {Switch 1 0 0 0 "query:recent_files" Cfg null RecentFile Null 0 0 0 0 0 1 1 FileOutline "switch" "Switch" "Switches to a recent file." "code,source,file" "" } + {SwitchToPartnerFile 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FileOutline "switch_to_partner_file" "Switch To Partner File" "Switches to the focused file's partner; or from header to implementation or vice versa." "code,source,file" "" } + {RecordFileInProject 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FileOutline "record_file_in_project" "Record File In Project" "Records the passed file path as a recent file in the currently loaded project." "" "" } + {ShowFileInExplorer 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FolderClosedFilled "show_file_in_explorer" "Show File In Explorer" "Opens the operating system's file explorer and shows the selected file." "" "$file," } //- rjf: source <-> disasm - {GoToDisassembly 1 1 Null null Nil Null 0 0 0 0 0 0 Glasses "go_to_disassembly" "Go To Disassembly" "Goes to the disassembly, if any, for a given source code line." "code,source,disassembly,disasm" } - {GoToSource 1 1 Null null Nil Null 0 0 0 0 0 0 FileOutline "go_to_source" "Go To Source" "Goes to the source code, if any, for a given disassembly line." "code,source,disassembly,disasm" } + {GoToDisassembly 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Glasses "go_to_disassembly" "Go To Disassembly" "Goes to the disassembly, if any, for a given source code line." "code,source,disassembly,disasm" "$text_pt," } + {GoToSource 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FileOutline "go_to_source" "Go To Source" "Goes to the source code, if any, for a given disassembly line." "code,source,disassembly,disasm" "" } //- rjf: override file links - {SetFileReplacementPath 0 0 Null null Nil Null 0 0 0 0 0 0 Null "set_file_replacement_path" "Set File Replacement Path" "Sets the path which should be used as the replacement for the passed file." "" } + {SetFileReplacementPath 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "set_file_replacement_path" "Set File Replacement Path" "Sets the path which should be used as the replacement for the passed file." "" "" } //- rjf: setting config paths - {OpenUser 1 1 FilePath null Nil Null 1 0 0 0 0 1 Person "open_user" "Open User" "Opens a user file path, immediately loading it, and begins autosaving to it." "load,user,project,layout" } - {OpenProject 1 1 FilePath null Nil Null 1 0 0 0 0 1 Briefcase "open_project" "Open Project" "Opens a project file path, immediately loading it, and begins autosaving to it." "project,project,session" } - {OpenRecentProject 1 1 Entity null RecentProject Null 0 0 0 0 0 1 Briefcase "open_recent_project" "Open Recent Project" "Opens a recently used project file." "project,project,session" } - - //- rjf: loading/applying stateful config changes - {ApplyUserData 0 0 Null null Nil Null 0 0 0 0 0 0 Null "apply_user_data" "Apply User Data" "Applies user data from the active user file." "" } - {ApplyProjectData 0 0 Null null Nil Null 0 0 0 0 0 0 Null "apply_project_data" "Apply Project Data" "Applies project data from the active project file." "" } + {NewUser 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Add "new_user" "New User" "Creates a new user file, and sets the current user path as that file's path." "new,user,project,layout" "" } + {NewProject 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Add "new_project" "New Project" "Creates a new project file, and sets the current project path as that file's path." "new,user,project,layout" "" } + {OpenUser 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Person "open_user" "Open User" "Opens a user file path, immediately loading it, and begins autosaving to it." "load,user,project,layout" "" } + {OpenProject 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Briefcase "open_project" "Open Project" "Opens a project file path, immediately loading it, and begins autosaving to it." "project,project,session" "" } + {OpenRecentProject 1 1 0 0 "query:recent_projects" Cfg null RecentProject Null 0 0 0 0 0 1 1 Briefcase "open_recent_project" "Open Recent Project" "Opens a recently used project file." "project,project,session" "" } + {SaveUser 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Save "save_user" "Save User" "Saves user data to a file, and sets the current user path as that path." "load,user,project,layout" "" } + {SaveProject 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Save "save_project" "Save Project" "Saves project data to a file, and sets the current project path as that path." "project,project,session" "" } //- rjf: writing config changes - {WriteUserData 0 1 Null null Nil Null 0 0 0 0 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" } - {WriteProjectData 0 1 Null null Nil Null 0 0 0 0 0 0 Null "write_project_data" "Write Project Data" "Writes project data to the active project file." "" } + {WriteUserData 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "write_user_data" "Write User Data" "Writes user data to the active user file." "" "" } + {WriteProjectData 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "write_project_data" "Write Project Data" "Writes project data to the active project file." "" "" } + + //- rjf: opening user/project settings + {UserSettings 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Gear "user_settings" "User Settings" "Opens user settings." "" "" } + {ProjectSettings 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Gear "project_settings" "Project Settings" "Opens project settings." "" "" } //- rjf: meta controls - {Edit 1 1 Null null Nil Null 0 0 0 0 0 0 Pencil "edit" "Edit" "Edits the current selection." "" } - {Accept 1 1 Null null Nil Null 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" } - {Cancel 1 1 Null null Nil Null 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" } + {Edit 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Pencil "edit" "Edit" "Edits the current selection." "" "" } + {Accept 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 CheckFilled "accept" "Accept" "Accepts current changes, or answers prompts in the affirmative." "" "" } + {Cancel 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 X "cancel" "Cancel" "Rejects current changes, exits temporary menus, or answers prompts in the negative." "" "" } //- rjf: directional movement & text controls - {MoveLeft 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" } - {MoveRight 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" } - {MoveUp 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up" "Move Up" "Moves the cursor or selection up." "" } - {MoveDown 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down" "Move Down" "Moves the cursor or selection down." "" } - {MoveLeftSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_left_select" "Move Left Select" "Moves the cursor or selection left, while selecting." "" } - {MoveRightSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_right_select" "Move Right Select" "Moves the cursor or selection right, while selecting." "" } - {MoveUpSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_select" "Move Up Select" "Moves the cursor or selection up, while selecting." "" } - {MoveDownSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_select" "Move Down Select" "Moves the cursor or selection down, while selecting." "" } - {MoveLeftChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_left_chunk" "Move Left Select" "Moves the cursor or selection left one chunk." "" } - {MoveRightChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_right_chunk" "Move Right Select" "Moves the cursor or selection right one chunk." "" } - {MoveUpChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_chunk" "Move Up Chunk" "Moves the cursor or selection up one chunk." "" } - {MoveDownChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_chunk" "Move Down Chunk" "Moves the cursor or selection down one chunk." "" } - {MoveUpPage 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_page" "Move Up Page" "Moves the cursor or selection up one page." "" } - {MoveDownPage 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_page" "Move Down Page" "Moves the cursor or selection down one page." "" } - {MoveUpWhole 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_whole" "Move Up Whole" "Moves the cursor or selection to the beginning of the relevant content." "" } - {MoveDownWhole 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_whole" "Move Down Whole" "Moves the cursor or selection to the end of the relevant content." "" } - {MoveLeftChunkSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_left_chunk_select" "Move Left Chunk Select" "Moves the cursor or selection left one chunk." "" } - {MoveRightChunkSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_right_chunk_select" "Move Right Chunk Select" "Moves the cursor or selection right one chunk." "" } - {MoveUpChunkSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_chunk_select" "Move Up Chunk Select" "Moves the cursor or selection up one chunk." "" } - {MoveDownChunkSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_chunk_select" "Move Down Chunk Select" "Moves the cursor or selection down one chunk." "" } - {MoveUpPageSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_page_select" "Move Up Page Select" "Moves the cursor or selection up one page, while selecting." "" } - {MoveDownPageSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" } - {MoveUpWholeSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" } - {MoveDownWholeSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" } - {MoveUpReorder 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_up_reorder" "Move Up Reorder" "Moves the cursor or selection up, while swapping the currently selected element with that upward." "" } - {MoveDownReorder 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_down_reorder" "Move Down Reorder" "Moves the cursor or selection down, while swapping the currently selected element with that downward." "" } - {MoveHome 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" } - {MoveEnd 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" } - {MoveHomeSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" } - {MoveEndSelect 1 1 Null null Nil Null 0 0 0 0 0 0 Null "move_end_select" "Move End Select" "Moves the cursor to the end of the line, while selecting." "" } - {SelectAll 1 1 Null null Nil Null 0 0 0 0 0 0 Null "select_all" "Select All" "Selects everything possible." "" } - {DeleteSingle 1 1 Null null Nil Null 0 0 0 0 0 0 Null "delete_single" "Delete Single" "Deletes a single element to the right of the cursor, or the active selection." "" } - {DeleteChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "delete_chunk" "Delete Chunk" "Deletes a chunk to the right of the cursor, or the active selection." "" } - {BackspaceSingle 1 1 Null null Nil Null 0 0 0 0 0 0 Null "backspace_single" "Backspace Single" "Deletes a single element to the left of the cursor, or the active selection." "" } - {BackspaceChunk 1 1 Null null Nil Null 0 0 0 0 0 0 Null "backspace_chunk" "Backspace Chunk" "Deletes a chunk to the left of the cursor, or the active selection." "" } - {Copy 1 1 Null null Nil Null 0 0 0 0 0 0 Clipboard "copy" "Copy" "Copies the active selection to the clipboard." "" } - {Cut 1 1 Null null Nil Null 0 0 0 0 0 0 Clipboard "cut" "Cut" "Copies the active selection to the clipboard, then deletes it." "" } - {Paste 1 1 Null null Nil Null 0 0 0 0 0 0 Clipboard "paste" "Paste" "Pastes the current contents of the clipboard." "" } - {InsertText 0 1 Null null Nil Null 0 0 0 0 0 0 Null "insert_text" "Insert Text" "Inserts the text that was used to cause this command." "" } + {MoveLeft 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_left" "Move Left" "Moves the cursor or selection left." "" "" } + {MoveRight 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_right" "Move Right" "Moves the cursor or selection right." "" "" } + {MoveUp 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up" "Move Up" "Moves the cursor or selection up." "" "" } + {MoveDown 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down" "Move Down" "Moves the cursor or selection down." "" "" } + {MoveLeftSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_left_select" "Move Left Select" "Moves the cursor or selection left, while selecting." "" "" } + {MoveRightSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_right_select" "Move Right Select" "Moves the cursor or selection right, while selecting." "" "" } + {MoveUpSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_select" "Move Up Select" "Moves the cursor or selection up, while selecting." "" "" } + {MoveDownSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_select" "Move Down Select" "Moves the cursor or selection down, while selecting." "" "" } + {MoveLeftChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_left_chunk" "Move Left Chunk" "Moves the cursor or selection left one chunk." "" "" } + {MoveRightChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_right_chunk" "Move Right Chunk" "Moves the cursor or selection right one chunk." "" "" } + {MoveUpChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_chunk" "Move Up Chunk" "Moves the cursor or selection up one chunk." "" "" } + {MoveDownChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_chunk" "Move Down Chunk" "Moves the cursor or selection down one chunk." "" "" } + {MoveUpPage 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_page" "Move Up Page" "Moves the cursor or selection up one page." "" "" } + {MoveDownPage 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_page" "Move Down Page" "Moves the cursor or selection down one page." "" "" } + {MoveUpWhole 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_whole" "Move Up Whole" "Moves the cursor or selection to the beginning of the relevant content." "" "" } + {MoveDownWhole 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_whole" "Move Down Whole" "Moves the cursor or selection to the end of the relevant content." "" "" } + {MoveLeftChunkSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_left_chunk_select" "Move Left Chunk Select" "Moves the cursor or selection left one chunk." "" "" } + {MoveRightChunkSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_right_chunk_select" "Move Right Chunk Select" "Moves the cursor or selection right one chunk." "" "" } + {MoveUpChunkSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_chunk_select" "Move Up Chunk Select" "Moves the cursor or selection up one chunk." "" "" } + {MoveDownChunkSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_chunk_select" "Move Down Chunk Select" "Moves the cursor or selection down one chunk." "" "" } + {MoveUpPageSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_page_select" "Move Up Page Select" "Moves the cursor or selection up one page, while selecting." "" "" } + {MoveDownPageSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_page_select" "Move Down Page Select" "Moves the cursor or selection down one page, while selecting." "" "" } + {MoveUpWholeSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_whole_select" "Move Up Whole Select" "Moves the cursor or selection to the beginning of the relevant content, while selecting." "" "" } + {MoveDownWholeSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_whole_select" "Move Down Whole Select" "Moves the cursor or selection to the end of the relevant content, while selecting." "" "" } + {MoveUpReorder 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_up_reorder" "Move Up Reorder" "Moves the cursor or selection up, while swapping the currently selected element with that upward." "" "" } + {MoveDownReorder 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_down_reorder" "Move Down Reorder" "Moves the cursor or selection down, while swapping the currently selected element with that downward." "" "" } + {MoveHome 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_home" "Move Home" "Moves the cursor to the beginning of the line." "" "" } + {MoveEnd 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_end" "Move End" "Moves the cursor to the end of the line." "" "" } + {MoveHomeSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_home_select" "Move Home Select" "Moves the cursor to the beginning of the line, while selecting." "" "" } + {MoveEndSelect 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_end_select" "Move End Select" "Moves the cursor to the end of the line, while selecting." "" "" } + {SelectAll 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "select_all" "Select All" "Selects everything possible." "" "" } + {DeleteSingle 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "delete_single" "Delete Single" "Deletes a single element to the right of the cursor, or the active selection." "" "" } + {DeleteChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "delete_chunk" "Delete Chunk" "Deletes a chunk to the right of the cursor, or the active selection." "" "" } + {BackspaceSingle 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "backspace_single" "Backspace Single" "Deletes a single element to the left of the cursor, or the active selection." "" "" } + {BackspaceChunk 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "backspace_chunk" "Backspace Chunk" "Deletes a chunk to the left of the cursor, or the active selection." "" "" } + {Copy 1 1 0 1 "" Null null Nil Null 0 0 0 0 0 0 0 Clipboard "copy" "Copy" "Copies the active selection to the clipboard." "" "$text_rng," } + {Cut 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Clipboard "cut" "Cut" "Copies the active selection to the clipboard, then deletes it." "" "" } + {Paste 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Clipboard "paste" "Paste" "Pastes the current contents of the clipboard." "" "" } + {InsertText 0 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "insert_text" "Insert Text" "Inserts the text that was used to cause this command." "" "" } + + //- rjf: directionless navigation + {MoveNext 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_next" "Move Next" "Moves the cursor or selection to the next element." "" "" } + {MovePrev 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "move_prev" "Move Previous" "Moves the cursor or selection to the previous element." "" "" } //- rjf: code navigation - {GoToLine 1 1 Cursor null Nil Null 0 0 0 0 1 1 Null "goto_line" "Go To Line" "Jumps to a line number in the current code file." "" } - {GoToAddress 1 1 Vaddr null Nil Null 0 0 0 0 1 1 Null "goto_address" "Go To Address" "Jumps to an address in the current memory or disassembly view." "" } - {CenterCursor 1 1 Null null Nil Null 0 0 0 0 0 0 Null "center_cursor" "Center Cursor" "Snaps the current code view to center the cursor." "" } - {ContainCursor 1 1 Null null Nil Null 0 0 0 0 0 0 Null "contain_cursor" "Contain Cursor" "Snaps the current code view to contain the cursor." "" } - {FindTextForward 1 1 String null Nil Null 0 0 1 1 1 1 Find "find_text_forward" "Find Text (Forward)" "Searches the current code file forward (from the cursor) for a string." "" } - {FindTextBackward 1 1 String null Nil Null 0 0 1 1 1 1 Find "find_text_backward" "Find Text (Backwards)" "Searches the current code file backwards (from the cursor) for a string." "" } - {FindNext 1 1 Null null Nil Null 0 0 1 0 0 0 Find "find_next" "Find Next" "Searches the current code file forward (from the cursor) for the last searched string." "" } - {FindPrev 1 1 Null null Nil Null 0 0 1 0 0 0 Find "find_prev" "Find Previous" "Searches the current code file backwards (from the cursor) for the last searched string." "" } + {GoToLine 1 1 0 0 "" Cursor null Nil Null 0 0 0 0 1 0 1 Null "goto_line" "Go To Line" "Jumps to a line number in the current code file." "" "" } + {GoToAddress 1 1 0 0 "" Vaddr null Nil Null 0 0 0 0 1 0 1 Null "goto_address" "Go To Address" "Jumps to an address in the current memory or disassembly view." "" "" } + {CenterCursor 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "center_cursor" "Center Cursor" "Snaps the current code view to center the cursor." "" "" } + {ContainCursor 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "contain_cursor" "Contain Cursor" "Snaps the current code view to contain the cursor." "" "" } + {FindNext 1 1 0 0 "" Null null Nil Null 0 0 1 0 0 0 0 Find "find_next" "Find Next" "Searches the current code file forward (from the cursor) for the last searched string." "" "" } + {FindPrev 1 1 0 0 "" Null null Nil Null 0 0 1 0 0 0 0 Find "find_prev" "Find Previous" "Searches the current code file backwards (from the cursor) for the last searched string." "" "" } //- rjf: thread finding - {FindThread 1 1 Thread null Nil Thread 0 0 0 0 0 1 Find "find_thread" "Find Thread" "Jumps to the passed thread in either source code, disassembly, or both if they're already open." "" } - {FindSelectedThread 1 1 Null null Nil Null 0 0 0 0 0 0 Find "find_selected_thread" "Find Selected Thread" "Jumps to the selected thread in either source code, disassembly, or both if they're already open." "" } + {FindThread 1 1 0 0 "query:threads" Thread null Nil Thread 0 0 0 0 0 1 1 Find "find_thread" "Find Thread" "Jumps to the passed thread in either source code, disassembly, or both if they're already open." "" "" } + {FindSelectedThread 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Find "find_selected_thread" "Find Selected Thread" "Jumps to the selected thread in either source code, disassembly, or both if they're already open." "" "" } //- rjf: name finding - {GoToName 1 1 String symbol_lister Nil Null 0 0 0 0 1 1 Null "goto_name" "Go To Name" "Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible." "" } - {GoToNameAtCursor 1 1 Null null Nil Null 0 0 0 0 0 0 Null "goto_name_at_cursor" "Go To Name At Cursor" "Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible." "" } + {GoToName 1 1 0 0 "query:procedures" String symbol_lister Nil Null 0 0 0 0 1 1 1 Null "goto_name" "Go To Name" "Searches for the passed string as a file, a symbol in debug info, and more, then jumps to it if possible." "" "$text_pt," } + {GoToNameAtCursor 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "goto_name_at_cursor" "Go To Name At Cursor" "Searches for the text at the cursor as a file, a symbol in debug info, and more, then jumps to it if possible." "" "" } //- rjf: watch expressions - {ToggleWatchExpression 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "toggle_watch_expr" "Toggle Watch Expression" "Adds or removes an expression to an opened watch view." "" } - {ToggleWatchExpressionAtCursor 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_cursor" "Toggle Watch Expression At Cursor" "Adds or removes the expression that the cursor or selection is currently over to an opened watch view." "" } - {ToggleWatchExpressionAtMouse 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_mouse" "Toggle Watch Expression At Mouse" "Adds or removes the expression that the mouse is currently over to an opened watch view." "" } + {ToggleWatchExpression 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr" "Toggle Watch Expression" "Adds or removes an expression to an opened watch view." "" "$text_pt," } + {ToggleWatchExpressionAtCursor 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_cursor" "Toggle Watch Expression At Cursor" "Adds or removes the expression that the cursor or selection is currently over to an opened watch view." "" "" } + {ToggleWatchExpressionAtMouse 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Binoculars "toggle_watch_expr_at_mouse" "Toggle Watch Expression At Mouse" "Adds or removes the expression that the mouse is currently over to an opened watch view." "" "" } - //- rjf: memory view parameterization - {SetColumns 1 1 Null null Nil Null 0 0 0 0 1 1 Thumbnails "set_columns" "Set Columns" "Sets the number of columns for a memory view." "" } - - //- rjf: disassembly view parameterization - {ToggleAddressVisibility 1 1 Null null Nil Null 0 0 0 0 0 0 Thumbnails "toggle_address_visibility" "Toggle Address Visibility" "Toggles the visibility of addresses in a disassembly view." "" } - {ToggleCodeBytesVisibility 1 1 Null null Nil Null 0 0 0 0 0 0 Thumbnails "toggle_code_bytes_visibility""Toggle Code Bytes Visibility" "Toggles the visibility of machine code bytes in a disassembly view." "" } - - //- rjf: general entity operations - {EnableEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "enable_entity" "Enable Entity" "Enables an entity." "" } - {DisableEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "disable_entity" "Disable Entity" "Disables an entity." "" } - {SelectEntity 0 0 Null null Nil Null 0 0 0 0 0 0 CheckHollow "select_entity" "Select Entity" "Selects an entity, disabling all others of the same kind." "" } - {RemoveEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Trash "remove_entity" "Remove Entity" "Removes an entity." "" } - {NameEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "name_entity" "Name Entity" "Equips an entity with a name." "" } - {ConditionEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "condition_entity" "Condition Entity" "Equips an entity with a condition string." "" } - {DuplicateEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "duplicate_entity" "Duplicate Entity" "Duplicates an entity." "" } - {RelocateEntity 0 0 Null null Nil Null 0 0 0 0 0 0 Null "relocate_entity" "Relocate Entity" "Relocates an entity." "" } + //- rjf: general config operations + {EnableCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 CheckHollow "enable_cfg" "Enable" "Enables a config tree." "" "" } + {DisableCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 CheckFilled "disable_cfg" "Disable" "Disables a config tree." "" "" } + {SelectCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RadioHollow "select_cfg" "Select" "Selects a config tree, disabling all others of the same kind." "" "" } + {DeselectCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 RadioFilled "deselect_cfg" "Deselect" "Deselects a config tree." "" "" } + {RemoveCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Trash "remove_cfg" "Remove" "Removes a config tree." "" "" } + {NameCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "name_cfg" "Name" "Equips a config tree with a label." "" "" } + {ConditionCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "condition_cfg" "Condition" "Equips a config tree with a condition string." "" "" } + {DuplicateCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Duplicate "duplicate_cfg" "Duplicate" "Duplicates a config tree." "" "" } + {RelocateCfg 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "relocate_cfg" "Relocate" "Relocates a config tree." "" "" } + {SaveToProject 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Briefcase "save_cfg_to_project" "Save To Project" "Saves the config tree to the project." "" "" } //- rjf: breakpoints - {AddBreakpoint 1 1 Null null Nil Null 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" } - {AddAddressBreakpoint 1 0 Vaddr null Nil Null 0 0 0 0 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" } - {AddFunctionBreakpoint 1 0 String symbol_lister Nil Null 0 0 0 0 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address(es) of the specified function." "" } - {ToggleBreakpoint 1 1 Null null Nil Null 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" } - {EnableBreakpoint 1 1 Entity null Breakpoint Null 0 0 0 0 0 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" } - {DisableBreakpoint 1 1 Entity null Breakpoint Null 0 0 0 0 0 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" } + {AddBreakpoint 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "add_breakpoint" "Add Line Breakpoint" "Places a breakpoint at a given location (file path and line number, address, or symbol name)." "" "" } + {AddAddressBreakpoint 1 0 0 0 "" Expr null Nil Null 0 0 0 0 1 1 1 CircleFilled "add_address_breakpoint" "Add Address Breakpoint" "Places a breakpoint on the specified address." "" "$breakpoints," } + {AddFunctionBreakpoint 1 0 0 0 "query:procedures" String null Nil Null 0 0 0 0 1 1 1 CircleFilled "add_function_breakpoint" "Add Function Breakpoint" "Places a breakpoint on the first address of the specified function." "" "$breakpoints," } + {ToggleBreakpoint 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 CircleFilled "toggle_breakpoint" "Toggle Line Breakpoint" "Places or removes a breakpoint at a given location (file path and line number, address, or symbol name)." "" "$text_pt," } + {EnableBreakpoint 1 1 0 0 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 1 1 1 CheckFilled "enable_breakpoint" "Enable Breakpoint" "Enables a breakpoint." "" "" } + {DisableBreakpoint 1 1 0 0 "query:breakpoints" Cfg null Breakpoint Null 0 0 0 0 1 1 1 CheckHollow "disable_breakpoint" "Disable Breakpoint" "Disables a breakpoint." "" "" } + {ClearBreakpoints 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Trash "clear_breakpoints" "Clear Breakpoints" "Removes all breakpoints." "" "" } //- rjf: watch pins - {AddWatchPin 1 1 String null Nil Null 0 0 0 0 1 1 Pin "add_watch_pin" "Add Watch Pin" "Places a watch pin at a given location (file path and line number or address)." "" } - {ToggleWatchPin 1 0 String null Nil Null 0 0 0 0 1 1 Binoculars "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin at a given location (file path and line number or address)." "" } + {AddWatchPin 1 1 0 0 "" Expr null Nil Null 0 0 0 0 1 1 1 Pin "add_watch_pin" "Add Watch Pin" "Places a watch pin at a given location (file path and line number or address)." "" "$watch_pins," } + {ToggleWatchPin 1 0 0 0 "" Expr null Nil Null 0 0 0 0 1 1 1 Pin "toggle_watch_pin" "Toggle Watch Pin" "Places or removes a watch pin at a given location (file path and line number or address)." "" "" } - //- rjf: cursor operations - {RunToCursor 1 1 Null null Nil Null 0 0 0 0 0 0 Play "run_to_cursor" "Run To Cursor" "Runs the selected thread to the current cursor." "line" } - {SetNextStatement 1 1 Null null Nil Null 0 0 0 0 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" } + //- rjf: type views + {AddTypeView 0 0 0 0 "" String null Nil Null 0 0 0 0 0 0 0 Binoculars "add_type_view" "Add Type View" "Adds a new type view." "" "" } + + //- rjf: file path maps + {AddFilePathMap 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 FileOutline "add_file_path_map" "Add File Path Map" "Adds a new file path map." "" "" } + + //- rjf: themes + {EditUserTheme 0 0 0 0 "query:themes" String null Nil Null 0 0 0 0 0 0 0 Palette "edit_user_theme" "Edit User Theme" "Edits the current user's theme." "color" "" } + {EditProjectTheme 0 0 0 0 "query:themes" String null Nil Null 0 0 0 0 0 0 0 Palette "edit_project_theme" "Edit Project Theme" "Edits the current project's theme." "color" "" } + {AddThemeColor 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Palette "add_theme_color" "Add Theme Color" "Adds a new theme color." "" "" } + {ForkTheme 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Palette "fork_theme" "Fork Theme" "Imports all colors from the current theme so they can be individually edited." "" "" } + {SaveTheme 0 0 0 0 "" String null Nil Null 1 0 0 0 0 1 1 Save "save_theme" "Save Theme" "Saves all theme colors to a new theme file." "" "" } + {SaveAndSetTheme 0 0 0 0 "" String null Nil Null 1 0 0 0 0 1 1 Save "save_and_set_theme" "Save And Set Theme" "Saves all theme colors to a new theme file, and then sets that theme as the selected theme." "" "" } + + //- rjf: line operations + {SetNextStatement 1 1 1 0 "" Null null Nil Null 0 0 0 0 0 0 0 RightArrow "set_next_statement" "Set Next Statement" "Sets the selected thread's instruction pointer to the cursor's position." "" "$text_pt," } //- rjf: targets - {AddTarget 1 1 FilePath null Nil Null 1 0 0 0 0 1 Target "add_target" "Add Target" "Adds a new target." "application,executable,debug" } - {SelectTarget 1 1 Entity null Target Null 0 0 0 0 0 1 Target "select_target" "Select Target" "Selects a target." "" } - {EnableTarget 1 1 Entity null Target Null 0 0 0 0 0 1 CheckFilled "enable_target" "Enable Target" "Enables a target, in addition to all targets currently enabled." "" } - {DisableTarget 1 1 Entity null Target Null 0 0 0 0 0 1 CheckHollow "disable_target" "Disable Target" "Disables a target." "" } + {AddTarget 1 1 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 Target "add_target" "Add Target" "Adds a new target." "application,executable,debug" "$targets," } + {SelectTarget 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 Target "select_target" "Select Target" "Selects a target." "" "" } + {EnableTarget 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 CheckFilled "enable_target" "Enable Target" "Enables a target, in addition to all targets currently enabled." "" "" } + {DisableTarget 1 1 0 0 "query:targets" Cfg null Target Null 0 0 0 0 0 1 1 CheckHollow "disable_target" "Disable Target" "Disables a target." "" "" } //- rjf: attaching - {RegisterAsJITDebugger 1 1 Null null Nil Null 0 0 0 0 0 0 Null "register_as_jit_debugger" "Register As Just-In-Time (JIT) Debugger" "Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system." "" } + {RegisterAsJITDebugger 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "register_as_jit_debugger" "Register As Just-In-Time (JIT) Debugger" "Registers the RAD debugger as the just-in-time (JIT) debugger used by the operating system." "" "" } //- rjf: snap-to-code-location - {FindCodeLocation 0 1 FilePath null Nil Null 0 0 0 0 0 1 FileOutline "find_code_location" "Find Code Location" "Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary." "" } + {FindCodeLocation 0 1 0 0 "" FilePath null Nil Null 0 0 0 0 0 1 1 FileOutline "find_code_location" "Find Code Location" "Finds a specific source code location given file, line, and column coordinates. Opens the file if necessary." "" "" } - //- rjf: general-purpose view filtering - {Filter 1 1 Null null Nil Null 0 0 0 0 0 0 Find "filter" "Filter" "Begins filtering the active view." "sort,search,filter,find" } - {ApplyFilter 1 1 Null null Nil Null 0 0 0 0 0 0 Find "apply_filter" "Apply Filter" "Applies the typed filter to the active view." "sort,search,filter,find,apply" } - {ClearFilter 1 1 Null null Nil Null 0 0 0 0 0 0 Find "clear_filter" "Clear Filter" "Clears the filter applied to the active view." "sort,search,filter,find,clear" } - - //- rjf: view drivers - {GettingStarted 1 1 Null null Nil Null 0 0 0 0 0 0 QuestionMark "getting_started" "Getting Started" "Opens the menu for information on getting started." "tutorial,help" } - {Commands 0 0 Null null Nil Null 0 0 0 0 0 0 List "commands" "Commands" "Opens the list of all commands." "" } - {Target 0 0 Null null Nil Null 0 0 0 0 0 0 Target "target" "Target" "Opens the editor for a target." "" } - {Targets 1 1 Null null Nil Null 0 0 0 0 0 0 Target "targets" "Targets" "Opens the list of all targets." "" } - {FilePathMap 1 1 Null null Nil Null 0 0 0 0 0 0 FileOutline "file_path_map" "File Path Map" "Opens the file path mapping editor." "" } - {AutoViewRules 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "auto_view_rules" "Auto View Rules" "Opens the auto view rule editor." "" } - {Breakpoints 1 1 Null null Nil Null 0 0 0 0 0 0 CircleFilled "breakpoints" "Breakpoints" "Opens the breakpoints view." "" } - {WatchPins 1 1 Null null Nil Null 0 0 0 0 0 0 Pin "watch_pins" "Watch Pins" "Opens the watch pins view." "" } - {Scheduler 1 1 Null null Nil Null 0 0 0 0 0 0 Scheduler "scheduler" "Scheduler" "Opens the scheduler view, for process and thread controls." "threads,processes,targets" } - {CallStack 1 1 Null null Nil Null 0 0 0 0 0 0 Thread "call_stack" "Call Stack" "Opens the call stack view." "callstack,thread,unwind" } - {Modules 1 1 Null null Nil Null 0 0 0 0 0 0 Module "modules" "Modules" "Opens the modules view." "" } - {Watch 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "watch" "Watch" "Opens a watch view." "" } - {Locals 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "locals" "Locals" "Opens a locals view." "" } - {Registers 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "registers" "Registers" "Opens a registers view." "" } - {Globals 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "globals" "Globals" "Opens a globals view." "" } - {ThreadLocals 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "thread_locals" "Thread Locals" "Opens a thread locals view." "" } - {Types 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "types" "Types" "Opens a types view." "" } - {Procedures 1 1 Null null Nil Null 0 0 0 0 0 0 Binoculars "procedures" "Procedures" "Opens a procedures view." "" } - {PendingFile 0 0 Null null Nil Null 0 0 0 0 0 0 FileOutline "pending_file" "Pending File" "Opens a view which asynchronously analyzes the file path parameter, then picks an appropriate viewer for it." "" } - {Disassembly 1 1 Null null Nil Null 0 0 0 0 0 0 Glasses "disasm" "Disassembly" "Opens the disassembly view." "disasm" } - {Output 1 1 Null null Nil Null 0 0 0 0 0 0 List "output" "Output" "Opens an output view." "" } - {Memory 1 1 Null null Nil Null 0 0 0 0 0 0 Grid "memory" "Memory" "Opens a memory view." "" } - {ExceptionFilters 1 1 Null null Nil Null 0 0 0 0 0 0 Gear "exception_filters" "Exception Filters" "Opens the exception filters view." "exceptions,filters" } - {Settings 1 1 Null null Nil Null 0 0 0 0 0 0 Gear "settings" "Settings" "Opens the settings view." "theme,color,scheme,options" } + //- rjf: searching + {Search 1 1 0 0 "" String null Nil Null 0 0 1 1 1 0 1 Find "search" "Search" "Begins searching within the active interface." "sort,search,filter,find" "" } + {SearchBackwards 1 1 0 0 "" String null Nil Null 0 0 1 1 1 0 1 Find "search_backwards" "Search Backwards" "Begins searching backwards within the active interface." "sort,search,filter,find" "" } //- rjf: queries - {PickFile 0 0 FilePath null Nil Null 1 0 0 0 0 1 FileOutline "pick_file" "Pick File" "Opens the file browser to pick a file." "" } - {PickFolder 0 0 FilePath null Nil Null 0 1 0 0 0 1 FolderOpenFilled "pick_folder" "Pick Folder" "Opens the file browser to pick a folder." "" } - {PickFileOrFolder 0 0 FilePath null Nil Null 1 1 0 0 0 1 FileOutline "pick_file_or_folder" "Pick File/Folder" "Opens the file browser to pick a file or folder." "" } + {PickFile 0 0 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 0 0 0 0 1 1 FileOutline "pick_file" "Pick File" "Opens the file browser to pick a file." "" "" } + {PickFolder 0 0 0 0 `folder:\\"$input\\"` FilePath null Nil Null 0 1 0 0 0 1 1 FolderOpenFilled "pick_folder" "Pick Folder" "Opens the file browser to pick a folder." "" "" } + {PickFileOrFolder 0 0 0 0 `folder:\\"$input\\"` FilePath null Nil Null 1 1 0 0 0 1 1 FileOutline "pick_file_or_folder" "Pick File/Folder" "Opens the file browser to pick a file or folder." "" "" } - //- rjf: query completion - {CompleteQuery 0 0 Null null Nil Null 0 0 0 0 0 0 Null "complete_query" "Complete Query" "Completes a query." "" } - {CancelQuery 0 0 Null null Nil Null 0 0 0 0 0 0 Null "cancel_query" "Cancel Query" "Cancels a query." "" } + //- rjf: query stack + {PushQuery 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "push_query" "Push Query" "Opens a new temporary query interface." "" "" } + {CompleteQuery 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "complete_query" "Complete Query" "Completes and closes a query." "" "" } + {CancelQuery 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "cancel_query" "Cancel Query" "Closes a query." "" "" } + {UpdateQuery 0 0 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "update_query" "Update Query" "Updates a query input." "" "" } //- rjf: developer commands - {ToggleDevMenu 1 1 Null null Nil Null 0 0 0 0 0 0 Null "toggle_dev_menu" "Toggle Developer Menu" "Opens and closes the developer menu." "" } - {LogMarker 1 1 Null null Nil Null 0 0 0 0 0 0 Null "log_marker" "Log Marker" "Logs a marker in the application log, to denote specific points in time within the log." "" } + {ToggleDevMenu 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "toggle_dev_menu" "Toggle Developer Menu" "Opens and closes the developer menu." "" "" } + {LogMarker 1 1 0 0 "" Null null Nil Null 0 0 0 0 0 0 0 Null "log_marker" "Log Marker" "Logs a marker in the application log, to denote specific points in time within the log." "" "" } } @enum RD_CmdKind: @@ -490,15 +1053,19 @@ RD_CmdTable: // | | | | `Null`, @expand(D_CmdTable a) `$(a.name)`, @expand(RD_CmdTable, a) `$(a.name)`, + @expand(RD_WatchTabFastPathTable, a) `Open$(a.name)`, + @expand(RD_ViewTabFastPathTable, a) `Open$(a.name)`, COUNT, + + `FirstTabFastPathCmd = RD_CmdKind_OpenWatch`, } @struct RD_Query: { `RD_QueryFlags flags`; `RD_RegSlot slot`; + `String8 expr`; `String8 view_name`; - `RD_EntityKind entity_kind`; `CTRL_EntityKind ctrl_entity_kind`; } @@ -507,8 +1074,7 @@ RD_CmdTable: // | | | | `String8 string`; `String8 description`; `String8 search_tags`; - `String8 display_name`; - `RD_IconKind icon_kind`; + `String8 ctx_filter`; `RD_CmdKindFlags flags`; `RD_Query query`; }; @@ -517,9 +1083,13 @@ RD_CmdTable: // | | | | { `{0}`, @expand(D_CmdTable, a) - ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.display_name)"), RD_IconKind_$(a.canonical_icon), (RD_CmdKindFlag_ListInUI*$(a.ui_vis))|(RD_CmdKindFlag_ListInIPCDocs*$(a.ipc_docs_vis)), {(RD_QueryFlag_AllowFiles*$(a.q_allow_files))|(RD_QueryFlag_AllowFolders*$(a.q_allow_folders))|(RD_QueryFlag_CodeInput*$(a.q_is_code))|(RD_QueryFlag_KeepOldInput*$(a.q_keep_oi))|(RD_QueryFlag_SelectOldInput*$(a.q_select_oi))|(RD_QueryFlag_Required*$(a.q_required)), RD_RegSlot_$(a.q_slot), str8_lit_comp("$(a.q_view != 'null' -> a.q_view)"), RD_EntityKind_$(a.q_ent_kind), CTRL_EntityKind_$(a.q_ctrl_ent_kind)}}```; + ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.ctx_filter)"), (RD_CmdKindFlag_ListInUI*$(a.ui_vis))|(RD_CmdKindFlag_ListInIPCDocs*$(a.ipc_docs_vis))|(RD_CmdKindFlag_ListInTextPt*$(a.text_pt_vis))|(RD_CmdKindFlag_ListInTextRng*$(a.text_rng_vis)), {(RD_QueryFlag_AllowFiles*$(a.q_allow_files))|(RD_QueryFlag_AllowFolders*$(a.q_allow_folders))|(RD_QueryFlag_CodeInput*$(a.q_is_code))|(RD_QueryFlag_KeepOldInput*$(a.q_keep_oi))|(RD_QueryFlag_SelectOldInput*$(a.q_select_oi))|(RD_QueryFlag_Floating*$(a.q_floating))|(RD_QueryFlag_Required*$(a.q_required)), RD_RegSlot_$(a.q_slot), str8_lit_comp("$(a.q_expr)"), str8_lit_comp("$(a.q_view != 'null' -> a.q_view)"), CTRL_EntityKind_$(a.q_ctrl_ent_kind)}}```; @expand(RD_CmdTable, a) - ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.display_name)"), RD_IconKind_$(a.canonical_icon), (RD_CmdKindFlag_ListInUI*$(a.ui_vis))|(RD_CmdKindFlag_ListInIPCDocs*$(a.ipc_docs_vis)), {(RD_QueryFlag_AllowFiles*$(a.q_allow_files))|(RD_QueryFlag_AllowFolders*$(a.q_allow_folders))|(RD_QueryFlag_CodeInput*$(a.q_is_code))|(RD_QueryFlag_KeepOldInput*$(a.q_keep_oi))|(RD_QueryFlag_SelectOldInput*$(a.q_select_oi))|(RD_QueryFlag_Required*$(a.q_required)), RD_RegSlot_$(a.q_slot), str8_lit_comp("$(a.q_view != 'null' -> a.q_view)"), RD_EntityKind_$(a.q_ent_kind), CTRL_EntityKind_$(a.q_ctrl_ent_kind)}}```; + ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.ctx_filter)"), (RD_CmdKindFlag_ListInUI*$(a.ui_vis))|(RD_CmdKindFlag_ListInIPCDocs*$(a.ipc_docs_vis))|(RD_CmdKindFlag_ListInTextPt*$(a.text_pt_vis))|(RD_CmdKindFlag_ListInTextRng*$(a.text_rng_vis)), {(RD_QueryFlag_AllowFiles*$(a.q_allow_files))|(RD_QueryFlag_AllowFolders*$(a.q_allow_folders))|(RD_QueryFlag_CodeInput*$(a.q_is_code))|(RD_QueryFlag_KeepOldInput*$(a.q_keep_oi))|(RD_QueryFlag_SelectOldInput*$(a.q_select_oi))|(RD_QueryFlag_Floating*$(a.q_floating))|(RD_QueryFlag_Required*$(a.q_required)), RD_RegSlot_$(a.q_slot), str8_lit_comp("$(a.q_expr)"), str8_lit_comp("$(a.q_view != 'null' -> a.q_view)"), CTRL_EntityKind_$(a.q_ctrl_ent_kind)}}```; + @expand(RD_WatchTabFastPathTable, a) + ```{ str8_lit_comp("$(a.name_lower)"), str8_lit_comp("Opens a $(a.display_name) tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}```; + @expand(RD_ViewTabFastPathTable, a) + ```{ str8_lit_comp("$(a.name_lower)"), str8_lit_comp("Opens a $(a.display_name) tab."), {0}, {0}, RD_CmdKindFlag_ListInUI|RD_CmdKindFlag_ListInIPCDocs|RD_CmdKindFlag_ListInTab}```; } //////////////////////////////// @@ -535,21 +1105,18 @@ RD_DefaultBindingTable: { "step_out" F11 0 shift 0 } { "halt" X ctrl shift 0 } { "halt" Pause 0 0 0 } - { "soft_halt_refresh" R 0 0 alt } //- rjf: high-level composite target control operations { "run" F5 0 0 0 } { "restart" F5 ctrl shift 0 } { "step_into" F11 0 0 0 } { "step_over" F10 0 0 0 } - { "run_to_cursor" F10 ctrl 0 0 } + { "run_to_line" F10 ctrl 0 0 } { "set_next_statement" F10 ctrl shift 0 } //- rjf: font sizes - { "inc_ui_font_scale" Equal 0 0 alt } - { "dec_ui_font_scale" Minus 0 0 alt } - { "inc_code_font_scale" Equal 0 shift alt } - { "dec_code_font_scale" Minus 0 shift alt } + { "inc_window_font_size" Equal 0 0 alt } + { "dec_window_font_size" Minus 0 0 alt } //- rjf: windows { "window" N ctrl shift 0 } @@ -591,20 +1158,25 @@ RD_DefaultBindingTable: { "close_tab" W ctrl 0 0 } { "tab_bar_top" Up ctrl shift alt } { "tab_bar_bottom" Down ctrl shift alt } + { "open_tab" T ctrl 0 0 } //- rjf: files { "open" O ctrl 0 0 } - { "reload_active" R ctrl shift 0 } { "switch" I ctrl 0 0 } { "switch_to_partner_file" O 0 0 alt } //- rjf: setting config paths + { "open_user" N ctrl shift alt } + { "open_project" N ctrl 0 alt } { "open_user" O ctrl shift alt } { "open_project" O ctrl 0 alt } + { "save_user" S ctrl shift alt } + { "save_project" S ctrl shift 0 } //- rjf: meta controls { "edit" F2 0 0 0 } { "accept" Return 0 0 0 } + { "accept" Space 0 0 0 } { "cancel" Esc 0 0 0 } //- rjf: directional movement & text controls @@ -650,11 +1222,15 @@ RD_DefaultBindingTable: { "paste" Insert 0 shift 0 } { "insert_text" Null 0 0 0 } + //- rjf: secondary navigation + { "move_next" Tab 0 0 0 } + { "move_prev" Tab 0 shift 0 } + //- rjf: code navigation { "goto_line" G ctrl 0 0 } { "goto_address" G 0 0 alt } - { "find_text_forward" F ctrl 0 0 } - { "find_text_backward" R ctrl 0 0 } + { "search" F ctrl 0 0 } + { "search_backwards" R ctrl 0 0 } { "find_next" F3 0 0 0 } { "find_prev" F3 shift 0 0 } @@ -672,24 +1248,22 @@ RD_DefaultBindingTable: //- rjf: breakpoints { "toggle_breakpoint" F9 0 0 0 } - - //- rjf: targets - { "add_target" T ctrl 0 0 } + { "add_address_breakpoint" F9 0 shift 0 } + { "add_function_breakpoint" F9 ctrl shift 0 } //- rjf: attaching { "attach" F6 0 shift 0 } - //- rjf: filtering - { "filter" Slash ctrl 0 0 } - //- rjf: command lister - { "run_command" F1 0 0 0 } + { "open_palette" F1 0 0 0 } + { "open_palette" P ctrl shift 0 } //- rjf: developer commands { "log_marker" M ctrl shift alt } + { "toggle_dev_menu" D ctrl shift alt } } -@data(RD_StringBindingPair) rd_default_binding_table: +@data(`struct {String8 string; RD_Binding binding;}`) @c_file rd_default_binding_table: { @expand(RD_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_Modifier_Ctrl`) $(a.shift != 0 -> `|OS_Modifier_Shift`) $(a.alt != 0 -> `|OS_Modifier_Alt`)}}```; } @@ -755,6 +1329,7 @@ RD_IconTable: (RadioFilled "o") (CheckHollow "!") (CheckFilled "1") + (Check "V") (LeftCaret "<") (RightCaret ">") (UpCaret "^") @@ -795,7 +1370,12 @@ RD_IconTable: (QuestionMark "?") (Person "4") (Briefcase "5") - (Dot "c") + (Dot "6") + (Bitmap "&") + (Cube "*") + (WindowRestore "(") + (WindowMinimize ")") + (Duplicate "#") } @enum RD_IconKind: @@ -810,321 +1390,912 @@ RD_IconTable: } //////////////////////////////// -//~ rjf: Collections +//~ rjf: Theme Tables -@table(name entity_kind ctrl_entity_kind id_space) -RD_CollectionTable: +@table(name_upper name_lower display_string cfg) +RD_ThemePresetTable: { - //- rjf: frontend entity groups - {watches Watch Null x} - {targets Target Null x} - {breakpoints Breakpoint Null x} - {watch_pins WatchPin Null x} - {file_path_maps FilePathMap Null x} - {auto_view_rules AutoViewRule Null x} + //- rjf: default dark theme + { + DefaultDark default_dark "Default (Dark)", + ```theme: + { + theme_color: {tags:"background", value: 0x1b1b1bff } + theme_color: {tags:"alt background", value: 0x222222ff } + theme_color: {tags:"pop background", value: 0x355b6eff } + theme_color: {tags:"fresh background", value: 0x31393dff } + theme_color: {tags:"match background", value: 0x31393dff } + theme_color: {tags:"border", value: 0x404040ff } + theme_color: {tags:"text", value: 0xe5e5e5ff } + theme_color: {tags:"weak text", value: 0xa4a4a4ff } + theme_color: {tags:"good text", value: 0x32a852ff } + theme_color: {tags:"neutral text", value: 0x3a90bbff } + theme_color: {tags:"bad text", value: 0xcf5242ff } + theme_color: {tags:"hover", value: 0xffffffff } + theme_color: {tags:"focus overlay", value: 0xfda20012 } + theme_color: {tags:"focus border", value: 0xfda200ff } + theme_color: {tags:"cursor", value: 0x8aff00ff } + theme_color: {tags:"selection", value: 0x99ccff0f } + theme_color: {tags:"inactive background", value: 0x0000002f } + theme_color: {tags:"drop_shadow", value: 0x0000007f } + theme_color: {tags:"good_pop background", value: 0x2c5b36ff } + theme_color: {tags:"good_pop border", value: 0x568761ff } + theme_color: {tags:"good_pop hover", value: 0xe3f5d3ff } + theme_color: {tags:"good_pop weak text", value: 0xe3f5d3ff } + theme_color: {tags:"bad_pop background", value: 0x803425ff } + theme_color: {tags:"bad_pop hover", value: 0xff825cff } + theme_color: {tags:"code_default", value: 0xcbcbcbff } + theme_color: {tags:"code_symbol", value: 0x42a2cfff } + theme_color: {tags:"code_type", value: 0xfec746ff } + theme_color: {tags:"code_local", value: 0x98bc80ff } + theme_color: {tags:"code_register", value: 0xb7afd5ff } + theme_color: {tags:"code_keyword", value: 0xb38d4cff } + theme_color: {tags:"code_delimiter_or_operator", value: 0x767676ff } + theme_color: {tags:"code_numeric", value: 0x98abb1ff } + theme_color: {tags:"code_numeric_alt_digit_group", value: 0x738287ff } + theme_color: {tags:"code_string", value: 0x98abb1ff } + theme_color: {tags:"code_meta", value: 0xd96759ff } + theme_color: {tags:"code_comment", value: 0x717171ff } + theme_color: {tags:"line_info_0", value: 0x4f3022ff } + theme_color: {tags:"line_info_1", value: 0x4f3e15ff } + theme_color: {tags:"line_info_2", value: 0x434e2aff } + theme_color: {tags:"line_info_3", value: 0x36241fff } + theme_color: {tags:"line_info_4", value: 0x4f3022ff } + theme_color: {tags:"line_info_5", value: 0x4f3e15ff } + theme_color: {tags:"line_info_6", value: 0x434e2aff } + theme_color: {tags:"line_info_7", value: 0x36241fff } + theme_color: {tags:"thread_0", value: 0xffcb7fff } + theme_color: {tags:"thread_1", value: 0xb2ff65ff } + theme_color: {tags:"thread_2", value: 0xff99e5ff } + theme_color: {tags:"thread_3", value: 0x6598ffff } + theme_color: {tags:"thread_4", value: 0x65ffcbff } + theme_color: {tags:"thread_5", value: 0xff9819ff } + theme_color: {tags:"thread_6", value: 0x9932ffff } + theme_color: {tags:"thread_7", value: 0x65ff4cff } + theme_color: {tags:"thread_unwound", value: 0xb2ccd8ff } + theme_color: {tags:"thread_error", value: 0xb23219ff } + theme_color: {tags:"breakpoint", value: 0xa72911ff } + theme_color: {tags:"floating background", value: 0x1b1b1baf } + theme_color: {tags:"floating background alt", value: 0x0000005f } + theme_color: {tags:"floating background fresh", value: 0x31393d5f } + theme_color: {tags:"floating border", value: 0xbfbfbf1f } + theme_color: {tags:"floating scroll_bar background", value: 0x3b3b3b5f } + theme_color: {tags:"floating scroll_bar border", value: 0x5f5f5f5f } + theme_color: {tags:"menu_bar background", value: 0x2b3740ff } + theme_color: {tags:"menu_bar border", value: 0x3e4c57ff } + theme_color: {tags:"scroll_bar background", value: 0x2b2b2bff } + theme_color: {tags:"scroll_bar border", value: 0x3f3f3fff } + theme_color: {tags:"implicit background", value: 0x00000000 } + theme_color: {tags:"implicit border", value: 0x00000000 } + theme_color: {tags:"hollow background", value: 0x00000000 } + theme_color: {tags:"hollow border", value: 0xffffff1f } + theme_color: {tags:"tab background", value: 0x6f5135ff } + theme_color: {tags:"tab border", value: 0x8a6e54ff } + theme_color: {tags:"tab inactive background", value: 0x2b3740ff } + theme_color: {tags:"tab inactive border", value: 0x3e4c57ff } + theme_color: {tags:"tab auto background", value: 0x693847ff } + theme_color: {tags:"tab auto border", value: 0x9e6274ff } + theme_color: {tags:"tab auto inactive background", value: 0x2f2633ff } + theme_color: {tags:"tab auto inactive border", value: 0x685073ff } + theme_color: {tags:"drop_site background", value: 0xffffff05 } + theme_color: {tags:"drop_site border", value: 0xffffff0f } + } + ``` + } - //- rjf: control entity groups - {machines Nil Machine x} - {processes Nil Process x} - {threads Nil Thread x} - {modules Nil Module x} + //- rjf: default light theme + { DefaultLight default_light "Default (Light)", + ```theme: + { + theme_color:{ tags: background , value: 0xffffffff } + theme_color:{ tags: "alt background" , value: 0xf8f8f8ff } + theme_color:{ tags: "pop background" , value: 0xcbe4f2ff } + theme_color:{ tags: "menu_bar pop background" , value: 0x5aabd9ff } + theme_color:{ tags: "fresh background" , value: 0xeaddceff } + theme_color:{ tags: "match background" , value: 0xc1e9c4ff } + theme_color:{ tags: border , value: 0xcbcbcbff } + theme_color:{ tags: text , value: 0xff } + theme_color:{ tags: "weak text" , value: 0x727272ff } + theme_color:{ tags: "good text" , value: 0x217538ff } + theme_color:{ tags: "neutral text" , value: 0x1a5b7cff } + theme_color:{ tags: "bad text" , value: 0x972717ff } + theme_color:{ tags: hover , value: 0xff } + theme_color:{ tags: "focus overlay" , value: 0x67ff4b } + theme_color:{ tags: "focus border" , value: 0x67ffff } + theme_color:{ tags: cursor , value: 0xff } + theme_color:{ tags: selection , value: 0x283d5166 } + theme_color:{ tags: "inactive background" , value: 0x8 } + theme_color:{ tags: drop_shadow , value: 0xb } + theme_color:{ tags: "good_pop background" , value: 0x90c09aff } + theme_color:{ tags: "good_pop border" , value: 0x1e7231ff } + theme_color:{ tags: "good_pop hover" , value: 0xe3f5d3ff } + theme_color:{ tags: "good_pop weak text" , value: 0xe3f5d3ff } + theme_color:{ tags: "good_pop text" , value: 0xe3f5d3ff } + theme_color:{ tags: "bad_pop background" , value: 0xa93620ff } + theme_color:{ tags: "bad_pop text" , value: 0xffffffff } + theme_color:{ tags: "bad_pop text weak" , value: 0xffffffff } + theme_color:{ tags: "menu_bar bad_pop background" , value: 0xff2a00ff } + theme_color:{ tags: "menu_bar bad_pop text" , value: 0xffffffff } + theme_color:{ tags: "bad_pop hover" , value: 0xff825cff } + theme_color:{ tags: code_default , value: 0x80808ff } + theme_color:{ tags: code_symbol , value: 0x4ac3ff } + theme_color:{ tags: code_type , value: 0xf46200ff } + theme_color:{ tags: code_local , value: 0x317c00ff } + theme_color:{ tags: code_register , value: 0x9a00ffff } + theme_color:{ tags: code_keyword , value: 0xff0600ff } + theme_color:{ tags: code_delimiter_or_operator , value: 0x8a8a8aff } + theme_color:{ tags: code_numeric , value: 0x7d49ff } + theme_color:{ tags: code_numeric_alt_digit_group , value: 0xb56aff } + theme_color:{ tags: code_string , value: 0x63549fff } + theme_color:{ tags: code_meta , value: 0xd96759ff } + theme_color:{ tags: code_comment , value: 0x717171ff } + theme_color:{ tags: line_info_0 , value: 0xe6d5cdff } + theme_color:{ tags: line_info_1 , value: 0xdbcfb2ff } + theme_color:{ tags: line_info_2 , value: 0xddeac1ff } + theme_color:{ tags: line_info_3 , value: 0xddc4bdff } + theme_color:{ tags: line_info_4 , value: 0xba917eff } + theme_color:{ tags: thread_0 , value: 0xffa700ff } + theme_color:{ tags: thread_1 , value: 0xb41fff } + theme_color:{ tags: thread_2 , value: 0xff99e5ff } + theme_color:{ tags: thread_3 , value: 0x6598ffff } + theme_color:{ tags: thread_4 , value: 0x65ffcbff } + theme_color:{ tags: thread_5 , value: 0xff9819ff } + theme_color:{ tags: thread_6 , value: 0x9932ffff } + theme_color:{ tags: thread_7 , value: 0x65ff4cff } + theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff } + theme_color:{ tags: thread_error , value: 0xb23219ff } + theme_color:{ tags: breakpoint , value: 0xff2800ff } + theme_color:{ tags: "floating background" , value: 0xffffffc7 } + theme_color:{ tags: "floating background alt" , value: 0x23 } + theme_color:{ tags: "floating background fresh" , value: 0xeaddceff } + theme_color:{ tags: "floating border" , value: 0x88888884 } + theme_color:{ tags: "scroll_bar background" , value: 0xe9e9e9ff } + theme_color:{ tags: "scroll_bar border" , value: 0x5f5f5f5f } + theme_color:{ tags: "floating scroll_bar background" , value: 0xe9e9e9ff } + theme_color:{ tags: "floating scroll_bar border" , value: 0x5f5f5f5f } + theme_color:{ tags: "menu_bar background" , value: 0x2b6b9aff } + theme_color:{ tags: "menu_bar border" , value: 0x4d } + theme_color:{ tags: "menu_bar text" , value: 0xffffffff } + theme_color:{ tags: "menu_bar text weak" , value: 0xffffffff } + theme_color:{ tags: "good menu_bar text" , value: 0x70db8dff } + theme_color:{ tags: "bad menu_bar text" , value: 0xffa79bff } + theme_color:{ tags: "neutral menu_bar text" , value: 0xc4dbe7ff } + theme_color:{ tags: "implicit background" , value: 0x00000000 } + theme_color:{ tags: "implicit border" , value: 0x00000000 } + theme_color:{ tags: "hollow background" , value: 0x00000000 } + theme_color:{ tags: "hollow border" , value: 0xffffff1f } + theme_color:{ tags: "tab text" , value: 0xffffffff } + theme_color:{ tags: "tab text weak" , value: 0xffffffff } + theme_color:{ tags: "tab background" , value: 0xb67e48ff } + theme_color:{ tags: "tab border" , value: 0x875b31ff } + theme_color:{ tags: "tab inactive background" , value: 0xcacacaff } + theme_color:{ tags: "tab inactive border" , value: 0xb5b5b5ff } + theme_color:{ tags: "tab auto background" , value: 0xc41c69ff } + theme_color:{ tags: "tab auto border" , value: 0x981039ff } + theme_color:{ tags: "tab auto inactive background" , value: 0x9b88a3ff } + theme_color:{ tags: "tab auto inactive border" , value: 0x373737ff } + theme_color:{ tags: "drop_site background" , value: 0xffffff05 } + theme_color:{ tags: "drop_site border" , value: 0xffffff0f } + } + ``` + } - //- rjf: scheduling control entity hierarchies - {scheduler_machine Nil Null x} - {scheduler_process Nil Null x} + //- rjf: vs dark theme + { + VSDark vs_dark "VS (Dark)", + ```theme: + { + theme_color:{ tags: background , value: 0x1f1f1fff } + theme_color:{ tags: "alt background" , value: 0x222222ff } + theme_color:{ tags: "pop background" , value: 0x383167ff } + theme_color:{ tags: "fresh background" , value: 0x31393dff } + theme_color:{ tags: "match background" , value: 0x31393dff } + theme_color:{ tags: border , value: 0x404040ff } + theme_color:{ tags: text , value: 0xe5e5e5ff } + theme_color:{ tags: "weak text" , value: 0xa4a4a4ff } + theme_color:{ tags: "good text" , value: 0x32a852ff } + theme_color:{ tags: "neutral text" , value: 0x3a90bbff } + theme_color:{ tags: "bad text" , value: 0xcf5242ff } + theme_color:{ tags: hover , value: 0xffffffff } + theme_color:{ tags: "focus overlay" , value: 0x7160e81e } + theme_color:{ tags: "focus border" , value: 0x7160e8ff } + theme_color:{ tags: cursor , value: 0x8aff00ff } + theme_color:{ tags: selection , value: 0x99ccff0f } + theme_color:{ tags: "inactive background" , value: 0x0000002f } + theme_color:{ tags: drop_shadow , value: 0x0000007f } + theme_color:{ tags: "good_pop background" , value: 0x2c5b36ff } + theme_color:{ tags: "good_pop border" , value: 0x568761ff } + theme_color:{ tags: "good_pop hover" , value: 0xe3f5d3ff } + theme_color:{ tags: "good_pop weak text" , value: 0xe3f5d3ff } + theme_color:{ tags: "bad_pop background" , value: 0x803425ff } + theme_color:{ tags: "bad_pop hover" , value: 0xff825cff } + theme_color:{ tags: code_default , value: 0xe0e0e0ff } + theme_color:{ tags: code_symbol , value: 0xdcdcaaff } + theme_color:{ tags: code_type , value: 0x4ec9b0ff } + theme_color:{ tags: code_local , value: 0x9cdcfeff } + theme_color:{ tags: code_register , value: 0xb7afd5ff } + theme_color:{ tags: code_keyword , value: 0x569cd6ff } + theme_color:{ tags: code_delimiter_or_operator , value: 0x767676ff } + theme_color:{ tags: code_numeric , value: 0xb5cea8ff } + theme_color:{ tags: code_numeric_alt_digit_group , value: 0x7c986dff } + theme_color:{ tags: code_string , value: 0xd69d85ff } + theme_color:{ tags: code_meta , value: 0x9b9b9bff } + theme_color:{ tags: code_comment , value: 0x51a644ff } + theme_color:{ tags: line_info_0 , value: 0x4f3022ff } + theme_color:{ tags: line_info_1 , value: 0x4f3e15ff } + theme_color:{ tags: line_info_2 , value: 0x434e2aff } + theme_color:{ tags: line_info_3 , value: 0x36241fff } + theme_color:{ tags: line_info_4 , value: 0x4f3022ff } + theme_color:{ tags: line_info_5 , value: 0x4f3e15ff } + theme_color:{ tags: line_info_6 , value: 0x434e2aff } + theme_color:{ tags: line_info_7 , value: 0x36241fff } + theme_color:{ tags: thread_0 , value: 0xffdc48ff } + theme_color:{ tags: thread_1 , value: 0xb2ff65ff } + theme_color:{ tags: thread_2 , value: 0xff99e5ff } + theme_color:{ tags: thread_3 , value: 0x6598ffff } + theme_color:{ tags: thread_4 , value: 0x65ffcbff } + theme_color:{ tags: thread_5 , value: 0xff9819ff } + theme_color:{ tags: thread_6 , value: 0x9932ffff } + theme_color:{ tags: thread_7 , value: 0x65ff4cff } + theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff } + theme_color:{ tags: thread_error , value: 0xb23219ff } + theme_color:{ tags: breakpoint , value: 0xa72911ff } + theme_color:{ tags: "floating background" , value: 0x1b1b1baf } + theme_color:{ tags: "floating background alt" , value: 0x0000005f } + theme_color:{ tags: "floating background fresh" , value: 0x31393d5f } + theme_color:{ tags: "floating border" , value: 0xbfbfbf1f } + theme_color:{ tags: "floating scroll_bar background" , value: 0x3b3b3b5f } + theme_color:{ tags: "floating scroll_bar border" , value: 0x5f5f5f5f } + theme_color:{ tags: "scroll_bar background" , value: 0x2b2b2bff } + theme_color:{ tags: "scroll_bar border" , value: 0x3f3f3fff } + theme_color:{ tags: "implicit background" , value: 0x00000000 } + theme_color:{ tags: "implicit border" , value: 0x00000000 } + theme_color:{ tags: "hollow background" , value: 0x00000000 } + theme_color:{ tags: "hollow border" , value: 0xffffff1f } + theme_color:{ tags: "tab background" , value: 0x333333ff } + theme_color:{ tags: "tab border" , value: 0x7160e8ff } + theme_color:{ tags: "tab inactive background" , value: 0x171717ff } + theme_color:{ tags: "tab inactive border" , value: 0x3e4c57ff } + theme_color:{ tags: "tab auto background" , value: 0x3f386dff } + theme_color:{ tags: "tab auto border" , value: 0x7160e8ff } + theme_color:{ tags: "tab auto inactive background" , value: 0x2f2633ff } + theme_color:{ tags: "tab auto inactive border" , value: 0x685073ff } + theme_color:{ tags: "drop_site background" , value: 0xffffff05 } + theme_color:{ tags: "drop_site border" , value: 0xffffff0f } + } + ``` + } - //- rjf: debug info / architecture watch tables - {locals Nil Null -} - {registers Nil Null -} - {globals Nil Null x} - {thread_locals Nil Null x} - {types Nil Null x} - {procedures Nil Null x} + //- rjf: to-do + { VSLight vs_light "VS (Light)", + ```theme: + { + theme_color:{tags: background, value: 0xffffffff} + theme_color:{tags: "alt background", value: 0xefefefff} + theme_color:{tags: "pop background", value: 0xe3eaf2ff} + theme_color:{tags: "fresh background", value: 0xeccbbeff} + theme_color:{tags: "match background", value: 0xedcbf9ff} + theme_color:{tags: border, value: 0xe7e7e7ff} + theme_color:{tags: text, value: 0xff} + theme_color:{tags: "weak text", value: 0x353535ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: hover, value: 0xa7ffff} + theme_color:{tags: "focus overlay", value: 0x8eff3f} + theme_color:{tags: "focus border", value: 0x8effff} + theme_color:{tags: cursor, value: 0xff} + theme_color:{tags: selection, value: 0x56aaff77} + theme_color:{tags: "inactive background", value: 0x17} + theme_color:{tags: drop_shadow, value: 0xe7b27} + theme_color:{tags: "good_pop background", value: 0x21a43dff} + theme_color:{tags: "good_pop border", value: 0x21a43dff} + theme_color:{tags: "good_pop hover", value: 0xe3f5d3ff} + theme_color:{tags: "good_pop weak text", value: 0xe3f5d3ff} + theme_color:{tags: "good_pop text", value: 0xe3f5d3ff} + theme_color:{tags: "bad_pop background", value: 0xcb3f23ff} + theme_color:{tags: "bad_pop text", value: 0xffcdc4ff} + theme_color:{tags: "bad_pop text weak", value: 0xffcdc4ff} + theme_color:{tags: "bad_pop hover", value: 0xff825cff} + theme_color:{tags: code_default, value: 0x000000ff} + theme_color:{tags: code_symbol, value: 0x74531fff} + theme_color:{tags: code_type, value: 0x2b91afff} + theme_color:{tags: code_local, value: 0x1f377fff} + theme_color:{tags: code_register, value: 0x8a1bffff} + theme_color:{tags: code_keyword, value: 0x0000ffff} + theme_color:{tags: code_delimiter_or_operator, value: 0x767676ff} + theme_color:{tags: code_numeric, value: 0xff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x1d1d1dff} + theme_color:{tags: code_string, value: 0xa61515ff} + theme_color:{tags: code_meta, value: 0x808080ff} + theme_color:{tags: code_comment, value: 0x008000ff} + theme_color:{tags: line_info_0, value: 0xb5d9c8ff} + theme_color:{tags: line_info_1, value: 0xa9c1d0ff} + theme_color:{tags: line_info_2, value: 0x99abc5ff} + theme_color:{tags: line_info_3, value: 0xc6bcd5ff} + theme_color:{tags: thread_0, value: 0xffb141ff} + theme_color:{tags: thread_1, value: 0x66c407ff} + theme_color:{tags: thread_unwound, value: 0x67b3d7ff} + theme_color:{tags: thread_error, value: 0xff2900ff} + theme_color:{tags: breakpoint, value: 0xff2800ff} + theme_color:{tags: "floating background", value: 0xffffffff} + theme_color:{tags: "floating background alt", value: 0x11} + theme_color:{tags: "floating background fresh", value: 0xa0c2d318} + theme_color:{tags: "floating border", value: 0x50} + theme_color:{tags: "floating scroll_bar background", value: 0x3b3b3b5f} + theme_color:{tags: "floating scroll_bar border", value: 0x5f5f5f5f} + theme_color:{tags: "menu_bar background", value: 0xccd5f0ff} + theme_color:{tags: "menu_bar border", value: 0xbabdc3ff} + theme_color:{tags: "scroll_bar background", value: 0xe4e4e4ff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0xf5cc84ff} + theme_color:{tags: "tab border", value: 0xae7718ff} + theme_color:{tags: "tab inactive background", value: 0x3b4f81ff} + theme_color:{tags: "tab inactive text", value: 0xffffffff} + theme_color:{tags: "tab inactive border", value: 0x3b4f81ff} + theme_color:{tags: "tab auto background", value: 0xe99595ff} + theme_color:{tags: "tab auto border", value: 0xff6262ff} + theme_color:{tags: "tab auto inactive background", value: 0xac6060ff} + theme_color:{tags: "tab auto inactive border", value: 0xff6262ff} + theme_color:{tags: "drop_site background", value: 0xffffff05} + theme_color:{tags: "drop_site border", value: 0xa7ffff} + } + ``` + } + + //- rjf: solarized (dark) theme + { SolarizedDark solarized_dark "Solarized (Dark)", + ```theme: + { + theme_color:{tags: background, value: 0x002a35ff} + theme_color:{tags: "alt background", value: 0x053542ff} + theme_color:{tags: "pop background", value: 0x355b6eff} + theme_color:{tags: "fresh background", value: 0x31393dff} + theme_color:{tags: "match background", value: 0x31393dff} + theme_color:{tags: border, value: 0x65166ff} + theme_color:{tags: text, value: 0xeee8d5ff} + theme_color:{tags: "weak text", value: 0x93a1a1ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: hover, value: 0xca4b16ff} + theme_color:{tags: "focus overlay", value: 0xca4b151f} + theme_color:{tags: "focus border", value: 0xca4b16ff} + theme_color:{tags: cursor, value: 0xca4b16ff} + theme_color:{tags: selection, value: 0x99ccff0f} + theme_color:{tags: "inactive background", value: 0x0000002f} + theme_color:{tags: drop_shadow, value: 0x0000007f} + theme_color:{tags: "good_pop background", value: 0x5f8700ff} + theme_color:{tags: "good_pop border", value: 0x5f8700ff} + theme_color:{tags: "bad_pop background", value: 0x810000ff} + theme_color:{tags: code_default, value: 0x839496ff} + theme_color:{tags: code_symbol, value: 0xb3880eff} + theme_color:{tags: code_type, value: 0xb3880eff} + theme_color:{tags: code_local, value: 0xeee8d5ff} + theme_color:{tags: code_register, value: 0xeee8d5ff} + theme_color:{tags: code_keyword, value: 0x849804ff} + theme_color:{tags: code_delimiter_or_operator, value: 0x839496ff} + theme_color:{tags: code_numeric, value: 0x2aa198ff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x19766bff} + theme_color:{tags: code_string, value: 0x2aa198ff} + theme_color:{tags: code_meta, value: 0xca4b16ff} + theme_color:{tags: code_comment, value: 0x586e75ff} + theme_color:{tags: line_info_0, value: 0x4f3022ff} + theme_color:{tags: line_info_1, value: 0x4f3e15ff} + theme_color:{tags: line_info_2, value: 0x434e2aff} + theme_color:{tags: line_info_3, value: 0x36241fff} + theme_color:{tags: thread_0, value: 0xffcb7fff} + theme_color:{tags: thread_1, value: 0xb2ff65ff} + theme_color:{tags: thread_unwound, value: 0xb2ccd8ff} + theme_color:{tags: thread_error, value: 0xb23219ff} + theme_color:{tags: breakpoint, value: 0xa72911ff} + theme_color:{tags: "floating background", value: 0x2a3574} + theme_color:{tags: "floating background alt", value: 0x4f} + theme_color:{tags: "floating background fresh", value: 0x31393d5f} + theme_color:{tags: "floating scroll_bar background", value: 0x53542ff} + theme_color:{tags: "scroll_bar background", value: 0x53542ff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0x586e75ff} + theme_color:{tags: "tab border", value: 0x90abb3ff} + theme_color:{tags: "tab inactive background", value: 0x0} + theme_color:{tags: "tab inactive border", value: 0x33494fff} + theme_color:{tags: "tab auto background", value: 0x565ed2ff} + theme_color:{tags: "tab auto border", value: 0xa2a6dfff} + theme_color:{tags: "tab auto inactive background", value: 0} + theme_color:{tags: "tab auto inactive border", value: 0x595fbcff} + theme_color:{tags: "drop_site background", value: 0xffffff05} + theme_color:{tags: "drop_site border", value: 0xffffff0f} + } + ``` + } + + //- rjf: solarized light + { SolarizedLight solarized_light "Solarized (Light)", + ```theme: + { + theme_color:{tags: background, value: 0xfdf6e3ff} + theme_color:{tags: "alt background", value: 0xeee8d5ff} + theme_color:{tags: "pop background", value: 0x29a19890} + theme_color:{tags: "fresh background", value: 0xf7d38dff} + theme_color:{tags: "match background", value: 0xdcddddff} + theme_color:{tags: border, value: 0xd1ccbdff} + theme_color:{tags: "weak text", value: 0x93a1a1ff} + theme_color:{tags: text, value: 0x657b83ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: hover, value: 0xca4b16ff} + theme_color:{tags: "focus overlay", value: 0xca4b1454} + theme_color:{tags: "focus border", value: 0xca4b16ff} + theme_color:{tags: cursor, value: 0xca4b16ff} + theme_color:{tags: selection, value: 0x8594a264} + theme_color:{tags: "inactive background", value: 0x14} + theme_color:{tags: drop_shadow, value: 0x3a} + theme_color:{tags: "good_pop background", value: 0xd1e99aff} + theme_color:{tags: "good_pop border", value: 0xd1e99aff} + theme_color:{tags: "bad_pop background", value: 0xd26c6cff} + theme_color:{tags: "bad_pop border", value: 0xd26c6cff} + theme_color:{tags: "bad_pop weak text", value: 0xffffffff} + theme_color:{tags: "bad_pop text", value: 0xffffffff} + theme_color:{tags: code_default, value: 0x839496ff} + theme_color:{tags: code_symbol, value: 0xb3880eff} + theme_color:{tags: code_type, value: 0xb3880eff} + theme_color:{tags: code_local, value: 0x657b83ff} + theme_color:{tags: code_register, value: 0x947298ff} + theme_color:{tags: code_keyword, value: 0x849804ff} + theme_color:{tags: code_delimiter_or_operator, value: 0x839496ff} + theme_color:{tags: code_numeric, value: 0x2aa198ff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x19766bff} + theme_color:{tags: code_string, value: 0x2aa198ff} + theme_color:{tags: code_meta, value: 0xca4b16ff} + theme_color:{tags: code_comment, value: 0x586e75ff} + theme_color:{tags: line_info_0, value: 0xeee1dbff} + theme_color:{tags: line_info_1, value: 0xe5d5b1ff} + theme_color:{tags: line_info_2, value: 0xd9e8b6ff} + theme_color:{tags: line_info_3, value: 0xf5d5ccff} + theme_color:{tags: thread_0, value: 0xffa100ff} + theme_color:{tags: thread_1, value: 0x6edd00ff} + theme_color:{tags: thread_unwound, value: 0x708f9eff} + theme_color:{tags: thread_error, value: 0xff5231ff} + theme_color:{tags: breakpoint, value: 0xff411dff} + theme_color:{tags: "floating background", value: 0xfdf6e3b1} + theme_color:{tags: "floating background alt", value: 0x22} + theme_color:{tags: "floating background fresh", value: 0xf7d38dff} + theme_color:{tags: "scroll_bar background", value: 0xeee6d0ff} + theme_color:{tags: "scroll_bar floating background", value: 0xd5ccb5ff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0xfdf6e3ff} + theme_color:{tags: "tab inactive background", value: 0xe0d6bbff} + theme_color:{tags: "tab auto background", value: 0xf5cfe1ff} + theme_color:{tags: "tab auto border", value: 0xa2a6dfff} + theme_color:{tags: "tab auto inactive background", value: 0xc8a5b5ff} + theme_color:{tags: "tab auto inactive border", value: 0x595fbcff} + theme_color:{tags: "drop_site background", value: 0x29a19890} + theme_color:{tags: "drop_site border", value: 0x81ddd690} + } + ``` + } + + //- rjf: handmade hero theme + { HandmadeHero handmade_hero "Handmade Hero", + ```theme: + { + theme_color:{tags: background, value: 0x0c0c0cff} + theme_color:{tags: "alt background", value: 0x161616ff} + theme_color:{tags: "pop background", value: 0x355b6eff} + theme_color:{tags: "fresh background", value: 0x31393dff} + theme_color:{tags: "match background", value: 0x31393dff} + theme_color:{tags: border, value: 0x404040ff} + theme_color:{tags: text, value: 0xcac1b6ff} + theme_color:{tags: "weak text", value: 0xa08563ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: hover, value: 0xffffffff} + theme_color:{tags: "focus overlay", value: 0x7485971e} + theme_color:{tags: "focus border", value: 0x5e6b79ff} + theme_color:{tags: cursor, value: 0x00ee00ff} + theme_color:{tags: selection, value: 0x99ccff0f} + theme_color:{tags: "inactive background", value: 0x0000002f} + theme_color:{tags: drop_shadow, value: 0x0000007f} + theme_color:{tags: "good_pop background", value: 0x2c5b36ff} + theme_color:{tags: "good_pop border", value: 0x568761ff} + theme_color:{tags: "good_pop hover", value: 0xe3f5d3ff} + theme_color:{tags: "good_pop weak text", value: 0xe3f5d3ff} + theme_color:{tags: "bad_pop background", value: 0x803425ff} + theme_color:{tags: "bad_pop hover", value: 0xff825cff} + theme_color:{tags: code_default, value: 0xa08563ff} + theme_color:{tags: code_symbol, value: 0xcc5735ff} + theme_color:{tags: code_type, value: 0xd8a51cff} + theme_color:{tags: code_local, value: 0xd6b995ff} + theme_color:{tags: code_register, value: 0xc04047ff} + theme_color:{tags: code_keyword, value: 0xac7b0aff} + theme_color:{tags: code_delimiter_or_operator, value: 0x907553ff} + theme_color:{tags: code_numeric, value: 0x6b8e23ff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x4f681cff} + theme_color:{tags: code_string, value: 0x6b8e23ff} + theme_color:{tags: code_meta, value: 0xdab98fff} + theme_color:{tags: code_comment, value: 0x686868ff} + theme_color:{tags: line_info_0, value: 0x4f3022ff} + theme_color:{tags: line_info_1, value: 0x4f3e15ff} + theme_color:{tags: line_info_2, value: 0x434e2aff} + theme_color:{tags: line_info_3, value: 0x36241fff} + theme_color:{tags: thread_0, value: 0xffcb7fff} + theme_color:{tags: thread_1, value: 0xb2ff65ff} + theme_color:{tags: thread_unwound, value: 0xb2ccd8ff} + theme_color:{tags: thread_error, value: 0xb23219ff} + theme_color:{tags: breakpoint, value: 0xa72911ff} + theme_color:{tags: "floating background", value: 0x18181980} + theme_color:{tags: "floating background alt", value: 0x0000005f} + theme_color:{tags: "floating background fresh", value: 0x31393d5f} + theme_color:{tags: "floating border", value: 0xbfbfbf1f} + theme_color:{tags: "floating scroll_bar background", value: 0x3b3b3b5f} + theme_color:{tags: "floating scroll_bar border", value: 0x5f5f5f5f} + theme_color:{tags: "menu_bar background", value: 0x1f1f27ff} + theme_color:{tags: "menu_bar border", value: 0x3d3d47ff} + theme_color:{tags: "scroll_bar background", value: 0x2b2b2bff} + theme_color:{tags: "scroll_bar border", value: 0x3f3f3fff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0x1f1f27ff} + theme_color:{tags: "tab border", value: 0x3d3d47ff} + theme_color:{tags: "tab text", value: 0xca9301ff} + theme_color:{tags: "tab text weak", value: 0x8c690eff} + theme_color:{tags: "tab inactive background", value: 0x171718ff} + theme_color:{tags: "tab inactive border", value: 0x1f1f27ff} + theme_color:{tags: "tab auto background", value: 0x243b38ff} + theme_color:{tags: "tab auto border", value: 0x478980ff} + theme_color:{tags: "tab auto inactive background", value: 0x102623ff} + theme_color:{tags: "tab auto inactive border", value: 0x1e5850ff} + theme_color:{tags: "drop_site background", value: 0xffffff05} + theme_color:{tags: "drop_site border", value: 0xffffff0f} + } + ``` + } + + //- rjf: naysayer + { Naysayer naysayer "Naysayer", + ```theme: + { + theme_color:{tags: background, value: 0x042327ff} + theme_color:{tags: "alt background", value: 0x11b1fff} + theme_color:{tags: "pop background", value: 0x355b6eff} + theme_color:{tags: "pop text", value: 0xbad7e6ff} + theme_color:{tags: "fresh background", value: 0x31393dff} + theme_color:{tags: "match background", value: 0x31393dff} + theme_color:{tags: border, value: 0x334d50ff} + theme_color:{tags: text, value: 0xdad3beff} + theme_color:{tags: "weak text", value: 0xb0a688ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: "menu_bar good text", value: 0x2a8242ff} + theme_color:{tags: "menu_bar neutral text", value: 0x5681ff} + theme_color:{tags: "menu_bar bad text", value: 0xa21200ff} + theme_color:{tags: "menu_bar weak text", value: 0x313131ff} + theme_color:{tags: "menu_bar bad_pop text weak", value: 0xffffffff} + theme_color:{tags: hover, value: 0xffffffff} + theme_color:{tags: "focus overlay", value: 0x86e08e20} + theme_color:{tags: "focus border", value: 0x86e08fff} + theme_color:{tags: cursor, value: 0x86e08fff} + theme_color:{tags: selection, value: 0x99ccff0f} + theme_color:{tags: "inactive background", value: 0x0000002f} + theme_color:{tags: drop_shadow, value: 0x0000007f} + theme_color:{tags: "good_pop background", value: 0x2c5b36ff} + theme_color:{tags: "good_pop border", value: 0x568761ff} + theme_color:{tags: "good_pop hover", value: 0xe3f5d3ff} + theme_color:{tags: "good_pop weak text", value: 0xe3f5d3ff} + theme_color:{tags: "bad_pop background", value: 0x803425ff} + theme_color:{tags: "bad_pop hover", value: 0xff825cff} + theme_color:{tags: code_default, value: 0xbdb395ff} + theme_color:{tags: code_symbol, value: 0xcbe0f5ff} + theme_color:{tags: code_type, value: 0xcbe0f5ff} + theme_color:{tags: code_local, value: 0xd9cfb3ff} + theme_color:{tags: code_register, value: 0xb7afd5ff} + theme_color:{tags: code_keyword, value: 0x9de3c0ff} + theme_color:{tags: code_delimiter_or_operator, value: 0x767676ff} + theme_color:{tags: code_numeric, value: 0x2ca198ff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x217770ff} + theme_color:{tags: code_string, value: 0x2ca198ff} + theme_color:{tags: code_meta, value: 0xB0FFB0ff} + theme_color:{tags: code_comment, value: 0x31b72cff} + theme_color:{tags: line_info_0, value: 0x4f3022ff} + theme_color:{tags: line_info_1, value: 0x4f3e15ff} + theme_color:{tags: line_info_2, value: 0x434e2aff} + theme_color:{tags: line_info_3, value: 0x36241fff} + theme_color:{tags: thread_0, value: 0xffcb7fff} + theme_color:{tags: thread_1, value: 0xb2ff65ff} + theme_color:{tags: thread_unwound, value: 0xb2ccd8ff} + theme_color:{tags: thread_error, value: 0xb23219ff} + theme_color:{tags: breakpoint, value: 0xa72911ff} + theme_color:{tags: "floating background", value: 0x3232792} + theme_color:{tags: "floating background alt", value: 0x0000005f} + theme_color:{tags: "floating background fresh", value: 0x31393d5f} + theme_color:{tags: "floating scroll_bar background", value: 0xe363bff} + theme_color:{tags: "menu_bar background", value: 0xb59e7aff} + theme_color:{tags: "menu_bar text", value: 0xff} + theme_color:{tags: "menu_bar border", value: 0x947d5aff} + theme_color:{tags: "scroll_bar background", value: 0xe363bff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0x13533aff} + theme_color:{tags: "tab border", value: 0x6c9182ff} + theme_color:{tags: "tab inactive background", value: 0x0} + theme_color:{tags: "tab inactive border", value: 0x947d5a6c} + theme_color:{tags: "tab auto background", value: 0x5b3939ff} + theme_color:{tags: "tab auto border", value: 0x875c5cff} + theme_color:{tags: "tab auto inactive background", value: 0x251b1bff} + theme_color:{tags: "tab auto inactive border", value: 0x563d3dff} + theme_color:{tags: "drop_site background", value: 0xffffff05} + theme_color:{tags: "drop_site border", value: 0xffffff0f} + } + ``` + } + + //- rjf: 4coder theme + { FourCoder four_coder "4coder", + ```theme: + { + theme_color:{tags: background,value: 0xc0c0cff} + theme_color:{tags: "alt background", value: 0x131313ff} + theme_color:{tags: "pop background", value: 0x4c00ff} + theme_color:{tags: "fresh background", value: 0x4c00ff} + theme_color:{tags: "match background", value: 0x4c00ff} + theme_color:{tags: border, value: 0x272727ff} + theme_color:{tags: text, value: 0x90b080ff} + theme_color:{tags: "weak text", value: 0x6b845fff} + theme_color:{tags: "menu_bar background", value: 0x888888ff} + theme_color:{tags: "menu_bar text", value: 0x20202ff} + theme_color:{tags: "menu_bar text weak", value: 0x525252ff} + theme_color:{tags: "good text", value: 0x32a852ff} + theme_color:{tags: "neutral text", value: 0x3a90bbff} + theme_color:{tags: "bad text", value: 0xcf5242ff} + theme_color:{tags: hover, value: 0xee00ff} + theme_color:{tags: "focus overlay", value: 0xee0012} + theme_color:{tags: "focus border", value: 0x00ee00ff} + theme_color:{tags: cursor, value: 0x00ee00ff} + theme_color:{tags: selection, value: 0x99ccff0f} + theme_color:{tags: "inactive background", value: 0x0000002f} + theme_color:{tags: drop_shadow, value: 0x0000007f} + theme_color:{tags: "good_pop background", value: 0x4900ff} + theme_color:{tags: "good_pop border", value: 0x4900ff} + theme_color:{tags: "bad_pop background", value: 0x430b00ff} + theme_color:{tags: code_default, value: 0x90b080ff} + theme_color:{tags: code_symbol, value: 0xbfd9b2ff} + theme_color:{tags: code_type, value: 0xbfd9b2ff} + theme_color:{tags: code_local, value: 0xbfd9b2ff} + theme_color:{tags: code_register, value: 0xb84cffff} + theme_color:{tags: code_keyword, value: 0xd08f1fff} + theme_color:{tags: code_delimiter_or_operator, value: 0x90b080ff} + theme_color:{tags: code_numeric, value: 0x50ff2fff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0x30af18ff} + theme_color:{tags: code_string, value: 0x50ff2fff} + theme_color:{tags: code_meta, value: 0x90b080ff} + theme_color:{tags: code_comment, value: 0x1f90f0ff} + theme_color:{tags: line_info_0, value: 0xa253dff} + theme_color:{tags: line_info_1, value: 0x9103dff} + theme_color:{tags: line_info_2, value: 0x1e083dff} + theme_color:{tags: line_info_3, value: 0x1e083dff} + theme_color:{tags: thread_0, value: 0xd08f1fff} + theme_color:{tags: thread_1, value: 0x1ea5d0ff} + theme_color:{tags: thread_unwound, value: 0xb2ccd8ff} + theme_color:{tags: thread_error, value: 0xb23219ff} + theme_color:{tags: breakpoint, value: 0xa72911ff} + theme_color:{tags: "scroll_bar background", value: 0x1d1d1dff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0x15490cff} + theme_color:{tags: "tab border", value: 0x15490cff} + theme_color:{tags: "tab text", value: 0x90b080ff} + theme_color:{tags: "tab text weak", value: 0x90b080ff} + theme_color:{tags: "tab inactive background", value: 0x21321eff} + theme_color:{tags: "tab inactive border", value: 0x21321eff} + theme_color:{tags: "tab auto background", value: 0x674f3eff} + theme_color:{tags: "tab auto border", value: 0x674f3eff} + theme_color:{tags: "tab auto inactive background", value: 0x47382eff} + theme_color:{tags: "tab auto inactive border", value: 0x47382eff} + theme_color:{tags: "drop_site background", value: 0xffffff05} + theme_color:{tags: "drop_site border", value: 0xffffff0f} + } + ``` + } + + //- rjf: grove theme + { Grove grove "Grove", + ```theme: + { + theme_color:{ tags: background , value: 0x1b1f22ff } + theme_color:{ tags: "alt background" , value: 0x232929ff } + theme_color:{ tags: "pop background" , value: 0x2f4838ff } + theme_color:{ tags: "fresh background" , value: 0x31393dff } + theme_color:{ tags: "match background" , value: 0x31393dff } + theme_color:{ tags: border , value: 0x485347ff } + theme_color:{ tags: text , value: 0xffffffff } + theme_color:{ tags: "weak text" , value: 0xa2a2a2ff } + theme_color:{ tags: "good text" , value: 0x32a852ff } + theme_color:{ tags: "neutral text" , value: 0x3a90bbff } + theme_color:{ tags: "bad text" , value: 0xcf5242ff } + theme_color:{ tags: hover , value: 0xffffffff } + theme_color:{ tags: "focus overlay" , value: 0xfda20012 } + theme_color:{ tags: "focus border" , value: 0xfda200ff } + theme_color:{ tags: cursor , value: 0x8aff00ff } + theme_color:{ tags: selection , value: 0x99ccff0f } + theme_color:{ tags: "inactive background" , value: 0x0 } + theme_color:{ tags: drop_shadow , value: 0x0000007f } + theme_color:{ tags: "good_pop background" , value: 0x2c5b36ff } + theme_color:{ tags: "good_pop border" , value: 0x568761ff } + theme_color:{ tags: "good_pop hover" , value: 0xe3f5d3ff } + theme_color:{ tags: "good_pop weak text" , value: 0xe3f5d3ff } + theme_color:{ tags: "bad_pop background" , value: 0x803425ff } + theme_color:{ tags: "bad_pop hover" , value: 0xff825cff } + theme_color:{ tags: code_default , value: 0xad8b69ff } + theme_color:{ tags: code_symbol , value: 0x87ad6aff } + theme_color:{ tags: code_type , value: 0xb67474ff } + theme_color:{ tags: code_local , value: 0xe9bf95ff } + theme_color:{ tags: code_register , value: 0xa688b2ff } + theme_color:{ tags: code_keyword , value: 0xe49e17ff } + theme_color:{ tags: code_delimiter_or_operator , value: 0x795e43ff } + theme_color:{ tags: code_numeric , value: 0x98b19eff } + theme_color:{ tags: code_numeric_alt_digit_group , value: 0x688b71ff } + theme_color:{ tags: code_string , value: 0x98b19eff } + theme_color:{ tags: code_meta , value: 0xad5979ff } + theme_color:{ tags: code_comment , value: 0x52675dff } + theme_color:{ tags: line_info_0 , value: 0x4f3022ff } + theme_color:{ tags: line_info_1 , value: 0x4f3e15ff } + theme_color:{ tags: line_info_2 , value: 0x434e2aff } + theme_color:{ tags: line_info_3 , value: 0x36241fff } + theme_color:{ tags: line_info_4 , value: 0x4f3022ff } + theme_color:{ tags: line_info_5 , value: 0x4f3e15ff } + theme_color:{ tags: line_info_6 , value: 0x434e2aff } + theme_color:{ tags: line_info_7 , value: 0x36241fff } + theme_color:{ tags: thread_0 , value: 0xffc258ff } + theme_color:{ tags: thread_1 , value: 0x82d331ff } + theme_color:{ tags: thread_2 , value: 0xff99e5ff } + theme_color:{ tags: thread_3 , value: 0x6598ffff } + theme_color:{ tags: thread_4 , value: 0x65ffcbff } + theme_color:{ tags: thread_5 , value: 0xff9819ff } + theme_color:{ tags: thread_6 , value: 0x9932ffff } + theme_color:{ tags: thread_7 , value: 0x65ff4cff } + theme_color:{ tags: thread_unwound , value: 0xb2ccd8ff } + theme_color:{ tags: thread_error , value: 0xb23219ff } + theme_color:{ tags: breakpoint , value: 0xa72911ff } + theme_color:{ tags: "floating background" , value: 0x1b1f2276 } + theme_color:{ tags: "floating background alt" , value: 0x0000005f } + theme_color:{ tags: "floating background fresh" , value: 0x31393d5f } + theme_color:{ tags: "floating border" , value: 0xbfbfbf1f } + theme_color:{ tags: "floating scroll_bar background" , value: 0x3b3b3b5f } + theme_color:{ tags: "floating scroll_bar border" , value: 0x5f5f5f5f } + theme_color:{ tags: "menu_bar background" , value: 0x243d32ff } + theme_color:{ tags: "menu_bar border" , value: 0x597b63ff } + theme_color:{ tags: "scroll_bar background" , value: 0x232929ff } + theme_color:{ tags: "scroll_bar border" , value: 0x3c4a3fff } + theme_color:{ tags: "implicit background" , value: 0x00000000 } + theme_color:{ tags: "implicit border" , value: 0x00000000 } + theme_color:{ tags: "hollow background" , value: 0x00000000 } + theme_color:{ tags: "hollow border" , value: 0xffffff1f } + theme_color:{ tags: "tab background" , value: 0x243d32ff } + theme_color:{ tags: "tab border" , value: 0x597b63ff } + theme_color:{ tags: "tab inactive background" , value: 0x30383eff } + theme_color:{ tags: "tab inactive border" , value: 0x6b7680ff } + theme_color:{ tags: "tab auto background" , value: 0x30636dff } + theme_color:{ tags: "tab auto border" , value: 0x768f94ff } + theme_color:{ tags: "tab auto inactive background" , value: 0x2f2633ff } + theme_color:{ tags: "tab auto inactive border" , value: 0x685073ff } + theme_color:{ tags: "drop_site background" , value: 0xffffff05 } + theme_color:{ tags: "drop_site border" , value: 0xffffff0f } + } + ``` + } + + //- rjf: todo + { FarManager far_manager "Far Manager", + ```theme: + { + theme_color:{tags: background, value: 0x000080ff} + theme_color:{tags: "pop background", value: 0x8080ff} + theme_color:{tags: "fresh background", value: 0x31393dff} + theme_color:{tags: "match background", value: 0x31393dff} + theme_color:{tags: border, value: 0x8080ff} + theme_color:{tags: text, value: 0xffffffff} + theme_color:{tags: "weak text", value: 0xffffffff} + theme_color:{tags: "good text", value: 0x00ff00ff} + theme_color:{tags: "neutral text", value: 0x00ffffff} + theme_color:{tags: "bad text", value: 0xff0000ff} + theme_color:{tags: hover, value: 0xffffffff} + theme_color:{tags: "focus overlay", value: 0xffff0012} + theme_color:{tags: "focus border", value: 0xffff00ff} + theme_color:{tags: cursor, value: 0xffff00ff} + theme_color:{tags: selection, value: 0xffff0018} + theme_color:{tags: "inactive background", value: 0x0000002f} + theme_color:{tags: drop_shadow, value: 0x0000007f} + theme_color:{tags: "good_pop background", value: 0x6c17ff} + theme_color:{tags: "good_pop border", value: 0x6c17ff} + theme_color:{tags: "bad_pop background", value: 0xff0000ff} + theme_color:{tags: code_default, value: 0xffffffff} + theme_color:{tags: code_symbol, value: 0xffffff} + theme_color:{tags: code_type, value: 0x00ff00ff} + theme_color:{tags: code_local, value: 0x00ffffff} + theme_color:{tags: code_register, value: 0xff00ffff} + theme_color:{tags: code_keyword, value: 0xffffffff} + theme_color:{tags: code_delimiter_or_operator, value: 0xffffffff} + theme_color:{tags: code_numeric, value: 0xffff00ff} + theme_color:{tags: code_numeric_alt_digit_group, value: 0xffff00ff} + theme_color:{tags: code_string, value: 0xffff00ff} + theme_color:{tags: code_meta, value: 0xff0000ff} + theme_color:{tags: code_comment, value: 0x008080ff} + theme_color:{tags: line_info_0, value: 0x8080ff} + theme_color:{tags: line_info_1, value: 0x800080ff} + theme_color:{tags: line_info_2, value: 0x800000ff} + theme_color:{tags: line_info_3, value: 0x08000ff} + theme_color:{tags: thread_0, value: 0xffff00ff} + theme_color:{tags: thread_1, value: 0x00ff00ff} + theme_color:{tags: thread_unwound, value: 0x00ffffff} + theme_color:{tags: thread_error, value: 0xff0000ff} + theme_color:{tags: breakpoint, value: 0xff0000ff} + theme_color:{tags: "menu_bar background", value: 0x008080ff} + theme_color:{tags: "menu_bar border", value: 0x8080ff} + theme_color:{tags: "scroll_bar background", value: 0x008080ff} + theme_color:{tags: "implicit background", value: 0x00000000} + theme_color:{tags: "implicit border", value: 0x00000000} + theme_color:{tags: "hollow background", value: 0x00000000} + theme_color:{tags: "hollow border", value: 0xffffff1f} + theme_color:{tags: "tab background", value: 0x8080ff} + theme_color:{tags: "tab border", value: 0x8080ff} + theme_color:{tags: "tab inactive background", value:0} + theme_color:{tags: "tab auto background", value: 0x800000ff} + theme_color:{tags: "tab auto border", value: 0x8080ff} + theme_color:{tags: "tab auto inactive background", value: 0x300000ff} + theme_color:{tags: "tab auto inactive border", value: 0x8080ff} + theme_color:{tags: "drop_site background", value: 0x80ff} + theme_color:{tags: "drop_site border", value: 0xffffff} + } + ``` + } } -@gen +@table(name lower_name) +RD_CodeColorTable: { - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF($(a.name));`; - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF($(a.name));`; - @expand(RD_CollectionTable a) `$(a.id_space == x -> "EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF("..a.name..");")`; - @expand(RD_CollectionTable a) `$(a.id_space == x -> "EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF("..a.name..");")`; + {CodeDefault "code_default"} + {CodeSymbol "code_symbol"} + {CodeType "code_type"} + {CodeLocal "code_local"} + {CodeRegister "code_register"} + {CodeKeyword "code_keyword"} + {CodeDelimiterOperator "code_delimiter_or_operator"} + {CodeNumeric "code_numeric"} + {CodeNumericAltDigitGroup "code_numeric_alt_digit_group"} + {CodeString "code_string"} + {CodeMeta "code_meta"} + {CodeComment "code_comment"} + {CodeLineNumbers "code_line_numbers"} + {CodeLineNumbersSelected "code_line_numbers_selected"} } -@data(String8) rd_collection_name_table: +@enum RD_CodeColorSlot: { - @expand(RD_CollectionTable a) `str8_lit_comp("$(a.name)")` -} - -@data(RD_EntityKind) rd_collection_entity_kind_table: -{ - @expand(RD_CollectionTable a) `RD_EntityKind_$(a.entity_kind)`, -} - -@data(CTRL_EntityKind) rd_collection_ctrl_entity_kind_table: -{ - @expand(RD_CollectionTable a) `CTRL_EntityKind_$(a.ctrl_entity_kind)`, -} - -@data(`EV_ViewRuleExprExpandInfoHookFunctionType *`) rd_collection_expr_expand_info_hook_function_table: -{ - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME($(a.name))` -} - -@data(`EV_ViewRuleExprExpandRangeInfoHookFunctionType *`) rd_collection_expr_expand_range_info_hook_function_table: -{ - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME($(a.name))` -} - -@data(`EV_ViewRuleExprExpandIDFromNumHookFunctionType *`) rd_collection_expr_expand_id_from_num_hook_function_table: -{ - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME($(a.id_space == x -> a.name)$(a.id_space != x -> identity))` -} - -@data(`EV_ViewRuleExprExpandIDFromNumHookFunctionType *`) rd_collection_expr_expand_num_from_id_hook_function_table: -{ - @expand(RD_CollectionTable a) `EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME($(a.id_space == x -> a.name)$(a.id_space != x -> identity))` -} - -//////////////////////////////// -//~ rjf: View Rules - -@table(name name_lower display_name params_schema icon can_filter filter_is_code typing_automatically_filters can_use_in_watch_table can_fill_value_cell can_expand show_in_docs description) -RD_ViewRuleTable: -{ - //- rjf: basics - { Empty empty "" "" Null 0 0 0 0 0 0 0 "" } - { GettingStarted getting_started "Getting Started" "" QuestionMark 0 0 0 0 0 0 0 "" } - - //- rjf: meta (settings) - { ExceptionFilters exception_filters "Exception Filters" "" Gear 0 0 0 0 0 0 1 "An interface which controls whether or not the debugger will halt attached processes upon encountering specific exception codes for the first time." } - { Settings settings "Settings" "" Gear 0 0 0 0 0 0 1 "An interface to modify general settings for the debugger's appearance and behavior." } - - //- rjf: temporary view for loading files - must analyze file before picking viewer - { PendingFile pending_file "Pending File" "" FileOutline 0 0 0 0 0 0 0 "" } - - //- rjf: query listers - { Commands commands "Commands" "" List 0 0 0 0 0 0 0 "" } - { FileSystem file_system "File System" "" FileOutline 0 0 0 0 0 0 0 "" } - { SystemProcesses system_processes "System Processes" "" Null 0 0 0 0 0 0 0 "" } - { EntityLister entity_lister "Entities" "" Null 0 0 0 0 0 0 0 "" } - { CtrlEntityLister ctrl_entity_lister "Control Entities" "" Null 0 0 0 0 0 0 0 "" } - { SymbolLister symbol_lister "Symbols" "" Null 0 0 0 0 0 0 0 "" } - - //- rjf: watch or watch-style tables - { Watch watch "Watch" "" Binoculars 1 1 1 0 0 0 1 "The familiar 'watch window' debugger interface. Allows the inputting of a number of expressions. Each expression in the table is evaluated within the context of the selected thread's selected call stack frame. If applicable (depending on visualization rules and the expression's type), these expressions may be hierarchically expanded, which displays children as more rows in the table. The values of these expressions may also be edited, and if possible, can be used to write to registers or memory in attached processes. Also contains a new *view rule* column, not found in other major debuggers, which allows per-row specification of various visualization rules. These view rules may be used to visualize and inspect the evaluation of expressions in a variety of ways. To learn more, read the 'View Rules' section." } - { Locals locals "Locals" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with local variables found within the selected call stack frame of the selected thread, according to the associated debug info. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - { Registers registers "Registers" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with all register names according to the selected thread's architecture. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - { Globals globals "Globals" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with all global variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - { ThreadLocals thread_locals "Thread Locals" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with all thread local variables within the selected thread's module. View rules and evaluation values can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - { Types types "Types" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with all types within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - { Procedures procedures "Procedures" "" Binoculars 1 1 1 0 0 0 1 "Nearly identical to `Watch`, but automatically filled with all procedures within the selected thread's module. View rules can be edited, like in `Watch`, but unlike `Watch`, expressions cannot be edited or added to the table." } - - //- rjf: configuration watch tables - { Targets targets "Targets" "" Target 1 1 1 0 0 0 1 "Displays a list of all targets, as well as controls for enabling, disabling, launching, editing, or deleting each target. For more information on targets, read the `Targets` section." } - { FilePathMap file_path_map "File Path Map" "" FileOutline 1 1 1 0 0 0 1 "Displays a table of *path maps*. Each path map is a pair of file or folder paths, one being a 'source' path, and one being a 'destination' path. These pairs are used by the debugger when automatically searching for specific files - for instance, when attempting to snap to a source code location specified by debug info. If debug info refers to a path on the machine on which a target executable was originally built, but that path is not valid on the debugger machine, but some alternative path exists, then path maps may be used to redirect the debugger from the debug info's specified paths to the associated appropriate debugger machine file paths." } - { AutoViewRules auto_view_rules "Auto View Rules" "" Binoculars 1 1 1 0 0 0 1 "Displays a table of *auto view rules*. Each *auto view rule* is a pair, with one element being a type, and the other being a view rule, which should be automatically applied to expressions of that type, when possible." } - { Breakpoints breakpoints "Breakpoints" "" CircleFilled 1 1 1 0 0 0 1 "Displays a table of all breakpoints, containing information about each breakpoint's name, location, and hit count. Also contains per-breakpoint controls for enabling, deleting, or editing each breakpoint. For more information on breakpoints and their features, read the 'Breakpoints' section." } - { WatchPins watch_pins "Watch Pins" "" Pin 1 1 1 0 0 0 1 "Displays a table of all watch pins (watched expressions, like those found in `Watch`, but instead of being within a table, being pinned to some source code location, like breakpoints). This table contains each pin's name, location, and controls for editing or deleting each pin." } - - //- rjf: debug entity info watch tables - { Scheduler scheduler "Scheduler" "" Scheduler 1 1 1 0 0 0 1 "Displays all processes and threads to which the debugger is currently attached, and contains controls for selecting and freezing threads." } - { CallStack call_stack "Call Stack" "" Thread 1 1 1 0 0 0 1 "Displays the call stack of the currently selected thread. Each frame in the call stack contains the associated module, function name, and return address. Allows selection of a particular call stack frame other than the top." } - { Modules modules "Modules" "" Module 1 1 1 0 0 0 1 "Displays a table of all modules currently loaded by any process to which the debugger is attached. This table displays each module's name, virtual address range in the containing process' address space, and which debug info file is being used by the debugger for the associated module." } - - //- rjf: data visualizers - { Text text "Text" "x:{'lang':lang, 'size':expr}" FileOutline 0 0 0 1 0 1 0 "" } - { Disasm disasm "Disassembly" "x:{'arch':arch, 'size':expr}" Glasses 0 0 0 1 0 1 1 "Displays disassembled instructions in a textual form from the selected thread's containing process virtual address space." } - { Output output "Output" "" List 0 0 0 0 0 0 1 "Displays debug strings, output from attached processes." } - { Memory memory "Memory" "x:{'size':expr}" Grid 0 0 0 1 0 1 1 "A hex-editor-like grid interface for viewing memory." } - { Bitmap bitmap "Bitmap" "x:{'w':expr, 'h':expr, 'fmt':tex2dformat}" Binoculars 0 0 0 1 0 1 1 "Visualizes memory as a bitmap." } - { Checkbox checkbox "Checkbox" "" CheckFilled 0 0 0 1 1 0 1 "Visualizes memory as an RGBA color." } - { ColorRGBA color_rgba "Color (RGBA)" "" Palette 0 0 0 1 1 1 1 "Visualizes memory as an RGBA color." } - { Geo3D geo3d "Geometry (3D)" "x:{'count':expr, 'vtx':expr, 'vtx_size':expr}" Binoculars 0 0 0 1 0 1 1 "Visualizes memory as 3D geometry." } -} - -@enum RD_ViewRuleKind: -{ - Null, - @expand(RD_ViewRuleTable a) `$(a.name)`, + @expand(RD_CodeColorTable a) `$(a.name)`, COUNT } -@struct RD_ViewRuleInfo: +@data(String8) rd_code_color_slot_name_table: { - `String8 string`; - `String8 description`; - `String8 display_name`; - `String8 params_schema`; - `RD_IconKind icon_kind`; - `RD_ViewRuleInfoFlags flags`; - `EV_ViewRuleExprExpandInfoHookFunctionType *expr_expand_info`; - `RD_ViewRuleUIFunctionType *ui`; -} - -@gen -{ - `RD_VIEW_RULE_UI_FUNCTION_DEF(null);`, - @expand(RD_ViewRuleTable a) `$(a.can_use_in_watch_table != 0 && a.can_expand != 0 -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(" .. a.name_lower .. ");")`, - @expand(RD_ViewRuleTable a) `RD_VIEW_RULE_UI_FUNCTION_DEF($(a.name_lower));`, -} - -@data(RD_ViewRuleInfo) rd_view_rule_kind_info_table: -{ - `{{0}, {0}, {0}, {0}, RD_IconKind_Null, 0, EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), RD_VIEW_RULE_UI_FUNCTION_NAME(null)}`, - @expand(RD_ViewRuleTable a) `{str8_lit_comp("$(a.name_lower)"), str8_lit_comp("$(a.description)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.params_schema)"), RD_IconKind_$(a.icon), (RD_ViewRuleInfoFlag_ShowInDocs*$(a.show_in_docs)|RD_ViewRuleInfoFlag_CanFilter*$(a.can_filter)|RD_ViewRuleInfoFlag_FilterIsCode*$(a.filter_is_code)|RD_ViewRuleInfoFlag_TypingAutomaticallyFilters*$(a.typing_automatically_filters)|RD_ViewRuleInfoFlag_CanUseInWatchTable*$(a.can_use_in_watch_table)|RD_ViewRuleInfoFlag_CanFillValueCell*$(a.can_fill_value_cell)|RD_ViewRuleInfoFlag_CanExpand*$(a.can_expand)), $(a.can_expand != 0 -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(" .. a.name_lower .. ")") $(a.can_expand == 0 -> "EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil)"), RD_VIEW_RULE_UI_FUNCTION_NAME($(a.name_lower))}`, -} - -//////////////////////////////// -//~ rjf: Built-In Debug Engine Kind -> Icon Kind Table - -@data(RD_IconKind) rd_entity_kind_icon_kind_table: -{ - @expand(RD_EntityKindTable a) `RD_IconKind_$(a.icon_kind)`, -} - -//////////////////////////////// -//~ rjf: Theme Tables - -@table(name_upper name_lower display_string) -RD_ThemePresetTable: -{ - { DefaultDark default_dark "Default (Dark)" } - { DefaultLight default_light "Default (Light)" } - { VSDark vs_dark "VS (Dark)" } - { VSLight vs_light "VS (Light)" } - { SolarizedDark solarized_dark "Solarized (Dark)" } - { SolarizedLight solarized_light "Solarized (Light)" } - { HandmadeHero handmade_hero "Handmade Hero" } - { FourCoder four_coder "4coder" } - { FarManager far_manager "Far Manager" } -} - -@table(name display_name name_lower default_dark default_light vs_dark vs_light solarized_dark solarized_light handmade_hero four_coder far_manager desc) -RD_ThemeColorTable: -{ - {Null "Null" null 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff 0xff00ffff ""} - - //- rjf: global ui colors - {Text "Text" text 0xe5e5e5ff 0x4c4c4cff 0xe5e5e5ff 0x000000ff 0x999999ff 0x333333ff 0xa08462ff 0x90b080ff 0x00fefeff ""} - {TextPositive "Text (Positive)" text_positive 0x4dc221ff 0x4d9e2eff 0x4dc221ff 0x4dc221ff 0x4dc221ff 0x4dc221ff 0x4dc221ff 0x4dc221ff 0x4dc221ff ""} - {TextNegative "Text (Negative)" text_negative 0xc56452ff 0xbd371eff 0xc56452ff 0xc46451ff 0xc56452ff 0xc56452ff 0xc56452ff 0xc56452ff 0xc56452ff ""} - {TextNeutral "Text (Neutral)" text_neutral 0x307eb2ff 0x0064a7ff 0x307eb2ff 0x307eb2ff 0x307eb2ff 0x307eb2ff 0x307eb2ff 0x307eb2ff 0x307eb2ff ""} - {TextWeak "Text (Weak)" text_weak 0xa4a4a4fe 0x4c4c4cff 0xa4a4a4fe 0x0000007f 0x9999998a 0x818181ff 0x6e512eff 0x566e4bff 0x00a9a9ff ""} - {Cursor "Cursor" cursor 0x8aff00ff 0x699830ff 0x8aff00ff 0x000000ff 0x8aff00ff 0x586e75ff 0x8aff00ff 0x8aff00ff 0x8aff00ff ""} - {CursorInactive "Cursor (Inactive)" cursor_inactive 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff 0xb23217ff ""} - {Focus "Focus" focus 0xfda200ff 0x9c5900ff 0xfda200ff 0x002affff 0xfda200ff 0x92743dff 0xfda200ff 0xfda200ff 0x00fefeff ""} - {Hover "Hover" hover 0xffffffff 0xffffffff 0xffffffff 0x000000ff 0xffffffff 0x747474ff 0xffffffff 0xffffffff 0xffffffff ""} - {DropShadow "Drop Shadow" drop_shadow 0x0000007f 0x0000004c 0x0000007f 0xa3a3a37e 0x0000007f 0xc9bfa394 0x0000007f 0x0000007f 0x0000007f ""} - {DisabledOverlay "Disabled Overlay" disabled_overlay 0x0000003f 0xa6a6a63f 0x0000003f 0x0000003f 0x0000003f 0xe4dac090 0x0000003f 0x0000003f 0x0000003f ""} - {DropSiteOverlay "Drop Site Overlay" drop_site_overlay 0xffffff0c 0x4848480c 0xffffff0c 0x0000000c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c 0xffffff0c ""} - {InactivePanelOverlay "Inactive Panel Overlay" inactive_panel_overlay 0x0000003f 0xa4a4a43f 0x0000003f 0xfefefe53 0x0000003f 0x0000001c 0x0000003f 0x0000003f 0x0000003f ""} - {SelectionOverlay "Selection Overlay" selection_overlay 0x99ccff4c 0x003d7a48 0x99ccff4c 0x3d74ab4b 0x99ccff4c 0x678cb24c 0x99ccff4c 0x99ccff4c 0x99ccff4c ""} - {HighlightOverlay "Highlight Overlay" highlight_overlay 0xffffff1e 0xffffff1e 0xffffff1e 0x0000001e 0xffffff1e 0xffffff1e 0xffffff1e 0xffffff1e 0xffffff1e ""} - {HighlightOverlayError "Error Highlight Overlay" error_highlight_overlay 0x5f12005f 0xff30005f 0x5f12005f 0x5f12005f 0x5f12005f 0x5f12005f 0x5f12005f 0x5f12005f 0x5f12005f ""} - - //- rjf: base ui container colors - {BaseBackground "Base Background" base_background 0x1b1b1bfe 0xccccccfe 0x1b1b1bfe 0xfefefefe 0x002a35fe 0xfcf5e2fe 0x0c0c0cfe 0x0c0c0cfe 0x000081fe ""} - {BaseBackgroundAlt "Base Background (Alternate)" base_background_alt 0x222222fe 0x2b2b2bfe 0x1b1b1bfe 0xe7e7e7fe 0x2b2b2bfe 0x2b2b2bfe 0x2b2b2bfe 0x2b2b2bfe 0x2b2b2bfe ""} - {BaseBorder "Base Border" base_border 0x3f3f3ffe 0xa4a4a4fe 0x3f3f3ffe 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0x423525fe 0x3f3f3ffe 0x0000fffe ""} - - //- rjf: menu bar ui container colors - {MenuBarBackground "Menu Bar Background" menu_bar_background 0x3e4c577f 0xeaeaea7f 0x1b1b1bfd 0xffffff7f 0x00202bff 0xeee8d5ff 0x0c0c0cfe 0x0c0c0cfe 0x007d7dff ""} - {MenuBarBackgroundAlt "Menu Bar Background (Alternate)" menu_bar_background_alt 0x3e4c577f 0x3e4c577f 0x1b1b1bfd 0xffffff7f 0x3e4c577f 0x3e4c577f 0x3e4c577f 0x3e4c577f 0x007d7dff ""} - {MenuBarBorder "Menu Bar Border" menu_bar_border 0xffffff19 0xa4a4a4fe 0x3f3f3ffe 0xb6b6b6ff 0xffffff19 0xbebaabfe 0xffffff19 0xffffff19 0xfefefe00 ""} - - //- rjf: floating ui container colors - {FloatingBackground "Floating Background" floating_background 0x33333333 0xccccccc0 0x33333333 0xfefefec7 0x007fa14e 0xffffff7c 0x0c0c0c32 0x0c0c0c3e 0x007c7c55 ""} - {FloatingBackgroundAlt "Floating Background (Alternate)" floating_background_alt 0x33333333 0x33333333 0x33333333 0x33333333 0x33333333 0x33333333 0x33333333 0x33333333 0x33333333 ""} - {FloatingBorder "Floating Border" floating_border 0x3f3f3ffd 0xa4a4a4fe 0x3f3f3ffd 0xb6b6b6ff 0xfdfdfd3a 0xbebaabfe 0x423425fe 0x3f3f3ffd 0x00ffff55 ""} - - //- rjf: ui element colors - {ImplicitButtonBackground "Implicit Button Background" implicit_button_background 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 ""} - {ImplicitButtonBorder "Implicit Button Border" implicit_button_border 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0xbdb9aa00 0x00000000 0x00000000 0x00000000 ""} - {PlainButtonBackground "Plain Button Background" plain_button_background 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe 0x1b1b1bfe ""} - {PlainButtonBorder "Plain Button Border" plain_button_border 0x3f3f3ffe 0x3f3f3ffe 0x3f3f3ffe 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0x3f3f3ffe 0x3f3f3ffe 0x3f3f3ffe ""} - {PositivePopButtonBackground "Positive Pop Button Background" positive_pop_button_background 0x2c5b36ff 0x65f534ff 0x2c5b36ff 0x84ce93ff 0x2c5b36ff 0xb6ddbeff 0x132e19ff 0x152f1bff 0x2c5b36ff ""} - {PositivePopButtonBorder "Positive Pop Button Border" positive_pop_button_border 0x3f3f3ffd 0x3f3f3ffd 0x3f3f3ffd 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0x3f3f3ffd 0x3f3f3ffd 0x3f3f3ffd ""} - {NegativePopButtonBackground "Negative Pop Button Background" negative_pop_button_background 0x803425ff 0xff694cff 0x803425ff 0xbd3e24ff 0x803425ff 0xf8b0a1ff 0x803425ff 0x43150cff 0x803425ff ""} - {NegativePopButtonBorder "Negative Pop Button Border" negative_pop_button_border 0x3f3f3ffd 0x3f3f3ffd 0x3f3f3ffd 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0x3f3f3ffd 0x3f3f3ffd 0x3f3f3ffd ""} - {NeutralPopButtonBackground "Neutral Pop Button Background" neutral_pop_button_background 0x355b6eff 0xa6becaff 0x355b6eff 0x6e9db5ff 0x355b6eff 0xb2d3e3ff 0x15445cff 0x1b323eff 0x933100ff ""} - {NeutralPopButtonBorder "Neutral Pop Button Border" neutral_pop_button_border 0x3f3f3ffd 0xa6a6a6fd 0x3f3f3ffd 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0x3f3f3ffd 0x3f3f3ffd 0x3f3f3ffd ""} - {ScrollBarButtonBackground "Scroll Bar Button Background" scroll_bar_button_background 0x2b2b2bfe 0xa9a9a9fe 0x2b2b2bfe 0xe8e8e8fe 0x005e77fe 0xe3dbc7fe 0x1f1f27fe 0x212721fe 0x007d7dff ""} - {ScrollBarButtonBorder "Scroll Bar Button Border" scroll_bar_button_border 0x3f3f3ffe 0xc0c0c0fe 0x3f3f3ffe 0xb6b6b6ff 0xfefefe3a 0xbebaabfe 0xfefefe4d 0x3f3f3ffe 0x3f3f3ffe ""} - {TabBackground "Tab Background" tab_background 0x6f5135fe 0xa98b6fff 0x0079ccff 0xfffffffe 0x005e77fe 0xfdf6e3ff 0x1f1f27fe 0x212721fe 0x007d7dff ""} - {TabBorder "Tab Border" tab_border 0xfefefe4d 0xffffff4d 0xfefefe4d 0xb6b6b6ff 0xfefefe4d 0xbebaabfe 0xfefefe4d 0xfefefe4d 0xfefefe4d ""} - {TabBackgroundInactive "Tab Background (Inactive)" tab_background_inactive 0x3e4c577f 0x8282827f 0xfefefe14 0xcdd4dc7f 0x3e4c577f 0xd4cfc0fe 0x131315ee 0x3a3a3a7f 0x3e4c577f ""} - {TabBorderInactive "Tab Border (Inactive)" tab_border_inactive 0xffffff19 0xffffff19 0xffffff00 0xb6b6b6ff 0xffffff19 0xbebaabfe 0xffffff19 0x00000019 0xfefefe19 ""} - - //- rjf: code colors - {CodeDefault "Code (Default)" code_default 0xcbcbcbff 0x4d4d4dff 0xcbcbcbff 0x000000ff 0xcbcbcbff 0x657b83ff 0xa08462ff 0x90b080ff 0x00fefeff ""} - {CodeSymbol "Code (Symbol)" code_symbol 0x42a2cffe 0x205670fe 0xdcdcaaff 0x000000ff 0xcb4a15ff 0xcb4a15ff 0xcc5634ff 0x42a2cffe 0x65b1ffff ""} - {CodeType "Code (Type)" code_type 0xfec746ff 0x996b00ff 0x4ec9afff 0xa33700ff 0xcb4a15ff 0xcb4a15ff 0xd8a51bff 0xfd7c52ff 0xfec746ff ""} - {CodeLocal "Code (Local)" code_local 0x98bc80ff 0x446a2bff 0x9cdbfeff 0x007666ff 0x98bc80ff 0x258ad2ff 0xc04047ff 0x98bc80ff 0x00ff00ff ""} - {CodeRegister "Code (Register)" code_register 0xb7afd5ff 0x4c35a1ff 0xb7afd5ff 0xb7afd5ff 0xb7afd5ff 0x373345ff 0xb7afd5ff 0xb7afd5ff 0xb7afd5ff ""} - {CodeKeyword "Code (Keyword)" code_keyword 0xb38d4cff 0x573700ff 0x569cd6ff 0x0000ffff 0x849803ff 0x586e75ff 0xac7a09ff 0xd08f1eff 0x00ffffff ""} - {CodeDelimiterOperator "Code (Delimiters/Operators)" code_delimiter_operator 0x767676ff 0x767676ff 0x767676ff 0x767676ff 0x767676ff 0x767676ff 0xa08462ff 0x90b080ff 0xffffffff ""} - {CodeNumeric "Code (Numeric)" code_numeric 0x98abb1ff 0x3f6e7dff 0xb5cea8ff 0x088658ff 0xd33582ff 0xd33482ef 0x698e21ff 0x4fff2eff 0x00ff00ff ""} - {CodeNumericAltDigitGroup "Code (Numeric, Alt. Digit Group)" code_numeric_alt_digit_group 0x738287ff 0x1f4450ff 0x729360ff 0x0c3828ff 0x902559ff 0x8e2659ff 0x3a4e11ff 0x3ccd21ff 0x738287ff ""} - {CodeString "Code (String)" code_string 0x98abb1ff 0x3c606bff 0xd59b85ff 0xa31414ff 0x1f9d91ff 0x29a198ff 0x6a8e22ff 0x4fff2eff 0x98abb1ff ""} - {CodeMeta "Code (Meta)" code_meta 0xd96759ff 0xad3627ff 0xd59c85ff 0x0000ffff 0x839802ff 0xd96759ff 0xdab98fff 0xa0b8a0ff 0xff0000ff ""} - {CodeComment "Code (Comment)" code_comment 0x717171ff 0x4b4b4bff 0x57a54aff 0x008000ff 0x556a6fff 0x93a1a1ff 0x686868ff 0x1e8fefff 0xffffffff ""} - {CodeLineNumbers "Code Line Numbers" code_line_numbers 0x7f7f7fff 0x4b4b4bff 0x2a91afff 0x227893ff 0x566c73ff 0x227893ef 0xa08462ff 0x7e7e7ffe 0x007d7dff ""} - {CodeLineNumbersSelected "Code Line Numbers (Selected)" code_line_numbers_selected 0xbebebeff 0x000000ff 0x9ddaecff 0x123d4bfe 0xa2aaacff 0x111e22ef 0xc8b399ff 0xbebebeff 0x00fefeff ""} - - //- rjf: debugging colors - {LineInfoBackground0 "Line Info Background 0" line_info_background_0 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f ""} - {LineInfoBackground1 "Line Info Background 1" line_info_background_1 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f ""} - {LineInfoBackground2 "Line Info Background 2" line_info_background_2 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f ""} - {LineInfoBackground3 "Line Info Background 3" line_info_background_3 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f ""} - {LineInfoBackground4 "Line Info Background 4" line_info_background_4 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f 0x99503d3f ""} - {LineInfoBackground5 "Line Info Background 5" line_info_background_5 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f 0xfe82493f ""} - {LineInfoBackground6 "Line Info Background 6" line_info_background_6 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f 0xffba173f ""} - {LineInfoBackground7 "Line Info Background 7" line_info_background_7 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f 0xcefd693f ""} - {Thread0 "Thread 0" thread_0 0xffcb7fff 0x945800ff 0xffcb7fff 0x945800ff 0xffcb7fff 0x945800ff 0xffcb7fff 0xffcb7fff 0xffcb7fff ""} - {Thread1 "Thread 1" thread_1 0xb2ff65ff 0x3f5b23ff 0xb2ff65ff 0x3f5b23ff 0xb2ff65ff 0x3f5b23ff 0xb2ff65ff 0xb2ff65ff 0xb2ff65ff ""} - {Thread2 "Thread 2" thread_2 0xff99e5ff 0x642a55ff 0xff99e5ff 0x642a55ff 0xff99e5ff 0x642a55ff 0xff99e5ff 0xff99e5ff 0xff99e5ff ""} - {Thread3 "Thread 3" thread_3 0x6598ffff 0x30456fff 0x6598ffff 0x30456fff 0x6598ffff 0x30456fff 0x6598ffff 0x6598ffff 0x6598ffff ""} - {Thread4 "Thread 4" thread_4 0x65ffcbff 0x264f41ff 0x65ffcbff 0x264f41ff 0x65ffcbff 0x264f41ff 0x65ffcbff 0x65ffcbff 0x65ffcbff ""} - {Thread5 "Thread 5" thread_5 0xff9819ff 0x736a5fff 0xff9819ff 0x736a5fff 0xff9819ff 0x736a5fff 0xff9819ff 0xff9819ff 0xff9819ff ""} - {Thread6 "Thread 6" thread_6 0x9932ffff 0x472f5eff 0x9932ffff 0x472f5eff 0x9932ffff 0x472f5eff 0x9932ffff 0x9932ffff 0x9932ffff ""} - {Thread7 "Thread 7" thread_7 0x65ff4cff 0x405d3bff 0x65ff4cff 0x405d3bff 0x65ff4cff 0x405d3bff 0x65ff4cff 0x65ff4cff 0x65ff4cff ""} - {ThreadUnwound "Thread (Unwound)" thread_unwound 0xb2ccd8ff 0x49606aff 0xb2ccd8ff 0x49606aff 0xb2ccd8ff 0x49606aff 0xb2ccd8ff 0xb2ccd8ff 0xb2ccd8ff ""} - {ThreadError "Thread (Error)" thread_error 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23219ff 0xb23218ff 0xb23219ff 0xb23219ff 0xb23219ff ""} - {Breakpoint "Breakpoint" breakpoint 0xa72911ff 0xff2800ff 0xa72911ff 0xa72911ff 0xa72911ff 0xff684bff 0xa72911ff 0xa72911ff 0xff2800ff ""} - {CacheLineBoundary "Cache Line Boundary" cache_line_boundary 0x355b6eff 0xa6becaff 0x355b6eff 0x6e9db5ff 0x355b6eff 0xb2d3e3ff 0x15445cff 0x1b323eff 0x933100ff ""} -} - -@table(old_name new_name) -RD_ThemeColorVersionRemapTable: -{ - {plain_text text} - {plain_background base_background} - {plain_border base_border} - {plain_overlay drop_site_overlay} - {code_function code_symbol} - {code_symbol code_delimiter_operator} - {code_numeric code_numeric_alt_digit_group} - {line_info_0 line_info_background_0} - {line_info_1 line_info_background_1} - {line_info_2 line_info_background_2} - {line_info_3 line_info_background_3} - {alt_background menu_bar_background} - {alt_border menu_bar_border} - {tab_inactive tab_background_inactive} - {tab_active tab_background} - {weak_text text_weak} - {text_selection selection} - {cursor cursor} - {highlight_0 focus} - {success_background positive_pop_button_background} - {failure_background negative_pop_button_background} - {action_background neutral_pop_button_background} -} - -@enum RD_ThemeColor: -{ - @expand(RD_ThemeColorTable a) `$(a.name)`, - COUNT, + @expand(RD_CodeColorTable a) `str8_lit_comp("$(a.lower_name)")` } @enum RD_ThemePreset: @@ -1143,96 +2314,9 @@ RD_ThemeColorVersionRemapTable: @expand(RD_ThemePresetTable a) `str8_lit_comp("$(a.name_lower)")`, } -@data(String8) rd_theme_color_version_remap_old_name_table: +@data(String8) rd_theme_preset_cfg_string_table: { - @expand(RD_ThemeColorVersionRemapTable a) `str8_lit_comp("$(a.old_name)")` -} - -@data(String8) rd_theme_color_version_remap_new_name_table: -{ - @expand(RD_ThemeColorVersionRemapTable a) `str8_lit_comp("$(a.new_name)")` -} - -@data(Vec4F32) rd_theme_preset_colors__default_dark: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.default_dark))`} -@data(Vec4F32) rd_theme_preset_colors__default_light: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.default_light))`} -@data(Vec4F32) rd_theme_preset_colors__vs_dark: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.vs_dark))`} -@data(Vec4F32) rd_theme_preset_colors__vs_light: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.vs_light))`} -@data(Vec4F32) rd_theme_preset_colors__solarized_dark: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.solarized_dark))`,} -@data(Vec4F32) rd_theme_preset_colors__solarized_light:{@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.solarized_light))`,} -@data(Vec4F32) rd_theme_preset_colors__handmade_hero: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.handmade_hero))`,} -@data(Vec4F32) rd_theme_preset_colors__four_coder: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.four_coder))`,} -@data(Vec4F32) rd_theme_preset_colors__far_manager: {@expand(RD_ThemeColorTable a) `rgba_from_u32_lit_comp($(a.far_manager))`;} -@data(`Vec4F32*`) rd_theme_preset_colors_table: -{ - @expand(RD_ThemePresetTable a) `rd_theme_preset_colors__$(a.name_lower)`, -} - -@data(String8) rd_theme_color_display_string_table: -{ - @expand(RD_ThemeColorTable a) `str8_lit_comp("$(a.display_name)")` -} - -@data(String8) rd_theme_color_cfg_string_table: -{ - @expand(RD_ThemeColorTable a) `str8_lit_comp("$(a.name_lower)")` -} - -//////////////////////////////// -//~ rjf: Settings - -@table(name name_lower display_string default_per_window default_s32 s32_min s32_max) -RD_SettingTable: -{ - {HoverAnimations hover_animations "Hover Animations" 0 1 0 1 } - {PressAnimations press_animations "Press Animations" 0 1 0 1 } - {FocusAnimations focus_animations "Focus Animations" 0 0 0 1 } - {TooltipAnimations tooltip_animations "Tooltip Animations" 0 1 0 1 } - {MenuAnimations menu_animations "Menu Animations" 0 1 0 1 } - {ScrollingAnimations scrolling_animations "Scrolling Animations" 0 1 0 1 } - {BackgroundBlur background_blur "Background Blur" 0 1 0 1 } - {ThreadLines thread_lines "Thread Lines" 0 1 0 1 } - {BreakpointLines breakpoint_lines "Breakpoint Lines" 0 1 0 1 } - {ThreadGlow thread_glow "Thread Glow" 0 1 0 1 } - {BreakpointGlow breakpoint_glow "Breakpoint Glow" 0 1 0 1 } - {OpaqueBackgrounds opaque_backgrounds "Opaque Backgrounds" 0 0 0 1 } - {TabWidth tab_width "Tab Width" 0 4 1 32 } - {MainFontSize main_font_size "Main Font Size" 1 11 6 72 } - {CodeFontSize code_font_size "Code Font Size" 1 11 6 72 } - {SmoothUIText smooth_ui_text "Smooth UI Text" 1 1 0 1 } - {SmoothCodeText smooth_code_text "Smooth Code Text" 1 0 0 1 } - {HintUIText hint_ui_text "Hint UI Text" 1 1 0 1 } - {HintCodeText hint_code_text "Hint Code Text" 1 1 0 1 } -} - -@enum RD_SettingCode: -{ - @expand(RD_SettingTable a) `$(a.name)`, - COUNT -} - -@data(String8) rd_setting_code_display_string_table: -{ - @expand(RD_SettingTable a) `str8_lit_comp("$(a.display_string)")` -} - -@data(String8) rd_setting_code_lower_string_table: -{ - @expand(RD_SettingTable a) `str8_lit_comp("$(a.name_lower)")` -} - -@data(B8) rd_setting_code_default_is_per_window_table: -{ - @expand(RD_SettingTable a) `$(a.default_per_window)` -} - -@data(RD_SettingVal) rd_setting_code_default_val_table: -{ - @expand(RD_SettingTable a) `{1, $(a.default_s32)}` -} - -@data(Rng1S32) rd_setting_code_s32_range_table: -{ - @expand(RD_SettingTable a) `{$(a.s32_min), $(a.s32_max)}` + @expand(RD_ThemePresetTable a) `str8_lit_comp("$(a.cfg)")`, } //////////////////////////////// @@ -1242,13 +2326,13 @@ RD_SettingTable: raddbg_readme: { @title "The RAD Debugger (ALPHA)"; - @p "The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It currently only supports local-machine Windows x64 debugging with PDBs, with plans to expand and port in the future."; + @p "The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It currently only supports local-machine Windows x64 debugging with PDBs, but we're actively working on support and ports for other toolchains and platforms."; @subtitle "Getting Started"; - @p "To launch the RAD Debugger with your executable and command line arguments, run `raddbg` from the command line like so:"; + @p "**Launching the debugger with your program information:** To launch the RAD Debugger with your executable and command line arguments, run `raddbg` from the command line like so:"; @p "```raddbg my_program.exe --foo --bar --baz```"; - @p "For more information, see the 'Command-Line Usage' section."; - @p "Default keyboard shortcuts for common debugger controls include:"; + @p "For more information, see the **Command-Line Usage** section."; + @p "**Basic commands and keybindings:** Default keyboard shortcuts for common debugger controls include:"; @unordered_list { @p "**Ctrl + O**: Open Source Code File"; @@ -1267,63 +2351,75 @@ raddbg_readme: @p "**Ctrl + Tab**: Focus Next Tab"; @p "**Ctrl + Shift + Tab**: Focus Previous Tab"; @p "**Ctrl + W**: Close Tab"; - @p "**F1**: Open Command Palette"; + @p "**F1**: Open Palette (lists commands, keybindings, settings, threads, processes, modules, types, and many other things)"; } - @p "For more information, see the 'Commands' section."; - @p "View rules can be used to visualize expressions differently in the watch window. Here are some examples:"; + @p "For more information, see the **Commands** section."; + + @p "**Configuration files (users and projects):** The RAD Debugger stores configuration in two files. One is the 'user file', the other is the 'project file'. Both files are the same format and can store the same kinds of data, but the user file is preferred by the debugger for more likely user-related data (windows, keybindings, theme), and the project file is preferred by the debugger for more likely project-related data (executable debugging targets, breakpoints, recent source files). Project files are more likely to be what you'd check into source control, whereas a user file is more likely to have your personal debugger settings (which will apply identically regardless of which project file is opened)."; + + @p "The debugger autosaves user and project files. You do not need to manually save them. To switch which path you are using for either, you can use the `Open User` (Ctrl + Alt + Shift + O, by default), or `Open Project` (Ctrl + Alt + O, by default) commands respectively. If a file does not exist at the path you enter for either, then a new one will be created, and the debugger will begin autosaving to it. If the initial paths to these files are not specified on the command line (via `--user` or `--project`), then the debugger uses default paths for them. The user file path, by default, will be `%appdata%/raddbg/default.raddbg_user`. The project file path will be whatever project path was last loaded for the user, or if no such path exists, `%appdata%/raddbg/default.raddbg_project`. If you suspect that your configuration files are corrupted or causing the debugger to behave poorly, it might help to delete your `%appdata%/raddbg` folder (although it'd also help if you [sent it to us in a bug report](https://github.com/EpicGamesExt/raddebugger/issues), so that we can investigate why they were corrupted to begin with!)."; + @p "For more information, see the `**User & Project Files** section."; + + @p "**Watch tabs and visualizers:** 'Watch' tabs in the RAD Debugger allow entering expressions, which can reference variables in your program, and visualize what their value is when your program is stopped at a particular time. These expressions roughly follow C expression syntax, but there are a number of extensions which can be used to visualize expressions in a more useful way. Here are some examples:"; @unordered_list { - @p "`array:16`: Visualize a pointer as pointing to a 16-element array."; - @p "`array:(count*2)`: Visualize a pointer as pointing to a `count*2`-element array."; - // @p "`list:next`: Visualize a linked list flatly, where each node has a `next` pointer, which points to the next node in the list."; - @p "`hex`: Visualize numeric literals as base-16 (hexadecimal)."; - @p "`dec`: Visualize numeric literals as base-10 (decimal)."; - @p "`oct`: Visualize numeric literals as base-8 (octal)."; - @p "`bin`: Visualize numeric literals as base-2 (binary)."; - @p "`omit:(foo bar baz)`: Prohibits members named `foo`, `bar`, and `baz` from being displayed."; - @p "`only:(foo bar baz)`: Only allows members named `foo`, `bar`, and `baz` to be displayed."; - @p "`slice`: Attempts to interpret a structure evaluation as encoding a slice, with a base pointer and an integer delimiting the number of elements to which the pointer points."; + @p "`array(pointer, 64)`: Visualizes `pointer` as pointing to a 256-element array."; + @p "`pointer, 64`: Visualizes `pointer` as pointing to a 256-element array."; + @p "`pointer, count`: Visualizes `pointer` as pointing to a `count`-element array."; + @p "`slice(some_slice_struct)`: Interprets a structure type as containing a base pointer and a count (either through an integer, or an 'end pointer'), and visualizes the base pointer, pointing to that many elements."; + @p "`rows(some_struct, a, b, c)`: Displays the value of `some_struct`, but only showing members `a`, `b`, and `c`."; + @p "`omit(some_struct, a, b, c)`: Displays the value of `some_struct`, but only showing members other than `a`, `b`, and `c`."; + @p "`hex(my_int)`: Visualizes the value of `my_int` in base-16 (hexadecimal) form."; + @p "`dec(my_int)`: Visualizes the value of `my_int` in base-10 (decimal) form."; + @p "`bin(my_int)`: Visualizes the value of `my_int` in base-2 (binary) form."; + @p "`oct(my_int)`: Visualizes the value of `my_int` in base-8 (octal) form."; + @p "`my_int, x`: Visualizes the value of `my_int` in base-16 (hexadecimal) form."; + @p "`my_int, d`: Visualizes the value of `my_int` in base-10 (decimal) form."; + @p "`my_int, b`: Visualizes the value of `my_int` in base-2 (binary) form."; + @p "`my_int, o`: Visualizes the value of `my_int` in base-8 (octal) form."; + @p "`digits(bin(my_int), 32)`: Visualizes the value of `my_int` in base-2 (binary) form, showing at minimum 32 bits."; + @p "`my_int.bin().digits(32)`: Visualizes the value of `my_int` in base-2 (binary) form, showing at minimum 32 bits."; + @p "`bitmap(base_pointer, width, height, fmt=rgba8)`: Visualizes the data starting at `base_pointer` as a bitmap, with width `width` and height `height`, with format `rgba8`."; } - @p "Multiple view rules can be specified on one line, so they can be combined like so:"; - @p "```array:16, hex, only: {x, y, z}```"; - @p "For more information, see the 'View Rules' section."; + @p "For more information, see the **Views** section."; @subtitle "Command-Line Usage"; - @p "When run normally, either by launching through a file explorer or running from a command line without arguments, `raddbg` will open a new instance of the debugger, and await further operations. But it also supports a number of command line options for a number of other purposes. These options are specified with a `-` or `--` prefix, followed by the name of the option, and if the option requires a parameter, followed by a `:` or `=`, followed by the parameter's content. A list of the possible options follows:"; + @p "When run normally, either by launching through a file explorer or running from a command line without arguments, `raddbg` will open a new instance of the debugger, and await further operations. But it also supports a number of command line options for a number of other purposes. These options are specified with a `-` or `--` prefix, followed by the name of the option, and if the option requires an argument value, followed by a `:` or `=`, followed by the argument value. A list of the possible options follows:"; @unordered_list { @p "`--help` Displays a help menu which documents the possible command line options."; - @p "`--user:` Use to specify the location of a user file which should be used. User files are used to store settings for users, including window and panel setups, path mapping, and visual settings. If this file does not exist, it will be created as necessary. This file will be autosaved as user-related changes are made. For more information on user files, read the 'User & Profile Files' section."; - @p "`--project:` Use to specify the location of a project file which should be used. Project files are used to store settings for users and projects. If this file does not exist, it will be created as necessary. This file will be autosaved as project-related changes are made. For more information on project files, read the 'User & Project Files' section."; + @p "`--user:` Use to specify the location of a user file which should be used. User files are used by default to store user-related settings, including window and panel setups, path mapping, and visual settings. If this file does not exist, it will be created as necessary. This file will be autosaved as user-related changes are made. For more information on user files, see the **User & Project Files** section."; + @p "`--project:` Use to specify the location of a project file which should be used. Project files are used by default to store project-related settings. If this file does not exist, it will be created as necessary. This file will be autosaved as project-related changes are made. For more information on project files, read the 'User & Project Files' section."; @p "`--auto_step` This will step into all active targets after the debugger initially starts."; @p "`--auto_run` This will run all active targets after the debugger initially starts."; - @p "`--quit_after_success` (or `-q`) This will close the debugger automatically after all processes exit, if they all exited successfully (with code 0), and ran with no interruptions.."; - @p "`--ipc` This will launch the debugger in the non-graphical IPC mode, which is used to communicate with another running instance of the debugger. The debugger instance will launch, send the specified command, then immediately terminate. This may be used by editors or other programs to control the debugger. For more information on commands, read the 'Commands' section. For more information on driving another debugger instance with this argument, read the 'Driving Another Debugger Instance' section." + @p "`--quit_after_success` (or `-q`) This will close the debugger automatically after all processes exit, if they all exited successfully (with code 0), and ran with no interruptions."; + @p "`--ipc` This will launch the debugger in the non-graphical IPC mode, which is used to communicate with another running instance of the debugger. The debugger instance will launch, send the specified command, then immediately terminate. This may be used by editors or other programs to control the debugger. For more information on the set of available commands, see the **Commands** section. For more information on driving another debugger instance with this argument, see the **Driving Another Debugger Instance** section."; } - @p "On the command line, non-options (meaning any command line arguments *not* prefixed with a `-` or `--`) can also be specified. with normal usage, they are interpreted as the command line for a target (see the 'Targets' section). When driving another debugger instance (using the `--ipc` argument), this additional command line text is used to encode a debugger command."; + @p "On the command line, non-options (meaning any command line arguments *not* prefixed with a `-` or `--`) can also be specified. With normal usage, they are interpreted as the command line for a target (see the **Targets** section). When driving another debugger instance (using the `--ipc` argument), this additional command line text is used to encode a debugger command."; @p "The debugger will stop parsing `-` and `--` prefixes as arguments after seeing a standalone `--`, *or* after seeing the first non-option argument, when reading the command line left-to-right. Some examples of command line usage and their interpretations are below:"; @unordered_list { - @p "`raddbg --foo --bar --a:b --c=d test.exe` All options are used to configure `raddbg`. `test.exe` is interpreted as a target executable. `b` is interpreted as the parameter for the `a` option. `d` is interpreted as the parameter for the `c` option."; - @p "`raddbg test.exe --foo --bar` `test.exe` is interpreted as a target executable. `--foo --bar` is interpreted as arguments for `test.exe`, and thus are *not* used to configure `raddbg`."; - @p "`raddbg -- test.exe` `test.exe` is interpreted as a target executable."; - @p "`raddbg --ipc find_code_location \"c:/foo/bar/baz.c:123:1\"` `--ipc` configures `raddbg` to drive another instance of `raddbg`. The remainder of the text is interpreted as a command."; - @p "`raddbg \"C:/path with spaces/test.exe\" --foo --bar` A target is formed from the `test.exe` path, and `--foo --bar` are interpreted as arguments to the `test.exe` target."; + @p "`raddbg --foo --bar --a:b --c=d test.exe`: All options are used to configure `raddbg`. `test.exe` is interpreted as a target executable. `b` is interpreted as the parameter for the `a` option. `d` is interpreted as the parameter for the `c` option."; + @p "`raddbg test.exe --foo --bar`: `test.exe`is interpreted as a target executable. `--foo --bar` is interpreted as arguments for `test.exe`, and thus are *not* used to configure `raddbg`."; + @p "`raddbg -- test.exe`: `test.exe` is interpreted as a target executable."; + @p "`raddbg --ipc find_code_location \"C:/foo/bar/baz.c:123:1\"`: `--ipc` configures `raddbg` to drive another instance of `raddbg`. The remainder of the text is interpreted as a command."; + @p "`raddbg \"C:/path with spaces/test.exe\" --foo --bar`: A target is formed from the `test.exe` path, and `--foo --bar` are interpreted as arguments to the `test.exe` target."; } @subtitle "Windows, Panels, & Tabs"; - @p "Each opened *window* in the debugger frontend is subdivided into *panels*. Panels subdivide regions of their window without overlapping. Each panel can contain multiple *tabs*, and can have one tab selected at any time. Tabs can be dragged and dropped between panels. Each tab is used to view one of the many supported debugger interfaces, including source code, disassembly, memory, or watches. When a tab is selected, that interface will fill the tab's containing panel's region of the containing window."; + @p "Each opened debugger window is subdivided into panels. Panels subdivide regions of their window without overlapping. Each panel can contain multiple tabs, and can have one tab selected at any time. Tabs can be dragged and dropped between panels. Each tab is used to view one of the many supported debugger interfaces, including source code, disassembly, memory, or watch tables. When a tab is selected, that interface will fill the tab's containing panel's region of the containing window."; @p "There are no 'special' windows, panels, or tabs; the debugger is written such that the number of windows, each window's panel organization, and the placement and arrangement of tabs can all be organized in a large variety of ways."; @p "A list of debugger interfaces, which can occupy tabs, are below:"; @unordered_list { - @expand(RD_ViewRuleTable a) @p "$(a.show_in_docs -> '`'..a.display_name..'` '..a.description)"; + @expand(RD_WatchTabFastPathTable a) @p "**$(a.display_name)**: $(a.description)"; } + @p "You can open one of these tabs in any panel by clicking the `+` icon next to that panel's tabs, or by executing the `Open Tab` command (bound to Ctrl + T) by default."; @subtitle "Commands"; - @p "The debugger is operated with *commands*. Commands may be manually executed in the debugger UI through the `Commands` menu, which you can open with the `Run Command` keybinding, which is F1 by default). Operations in the debugger UI are implemented with commands, so if it's ever unclear how to accomplish some operation through the UI, a useful fallback is searching for and running the command through the command menu."; + @p "The debugger, including implicitly with its UI, is operated almost entirely through 'commands'. Commands may be manually executed in the debugger UI within the palette (which you can open with F1 by default), or within the commands list which is opened when you execute the 'Run Command' command. Operations in the debugger UI are implemented with commands, so if it's ever unclear how to accomplish some operation through the UI, a useful fallback is searching for and running the command through the palette."; @p "Commands are also how a debugger instance launched with `--ipc` may communicate with a primary debugger instance."; - @p "A list of commands, how they're referred to textually (for the purposes of `--ipc` debugger instances), and their descriptions are below:"; + @p "A list of commands, how they're referred to textually (for the purposes of `--ipc` debugger instances), and their descriptions, are below:"; @unordered_list { @expand(D_CmdTable a) @p "$(a.ipc_docs_vis == 1 -> '`'..a.display_name..'` '..'(`'..a.string..'`) '..a.desc)"; @@ -1331,26 +2427,47 @@ raddbg_readme: } @subtitle "Targets"; - @p "A *target* is one executable and configuration for launching that executable, including command line arguments and working directory (the directory from which the executable is launched). Each target may also have a custom label (replaces the executable path when visualizing the target), and the name of a custom entry point function (when the default entry points - `main`, `WinMain`, etc. - are not desired when stepping into the program upon launch). The debugger can have several targets at once. Each target can also be enabled or disabled. Some operations work on all enabled targets - for instance, the `Run` or `Kill All` commands (standardly bound as F5 or Shift + F5). Enabling and disabling targets allows one to filter which targets are currently being worked with."; + @p "A *target* is one executable and configuration for launching that executable, including command line arguments and working directory (the directory from which the executable is launched). Each target may also have a custom label (prioritized over the executable name when visualizing the target, and also allows evaluation of the target in a Watch tab), and the name of a custom entry point function (when the default entry points - `main`, `WinMain`, etc. - are not desired when stepping into the program upon launch). The debugger can have several targets at once. Each target can also be enabled or disabled. Some operations work on all enabled targets - for instance, the `Run` or `Kill All` commands (standardly bound as F5 or Shift + F5). Enabling and disabling targets allows one to filter which targets are currently being worked with."; @p "To add a target, you can run the `Add Target` command. A target is also created automatically from command line arguments - the rules for how this happens can be found in the `Command-Line Usage` section."; - @p "Targets created through command line usage are temporary, meaning they are not persistently saved across runs of the debugger. To change this, you can right click the command-line-created target in the `Targets` view, and click `Save To Project`. After doing so, the target will be restored across runs, and will no longer need to be specified on the command-line."; + @p "Targets created through command line usage are temporary, meaning they are not persistently saved across runs of the debugger. To change this, find the target in the `Targets` tab, and click the `Save To Project` button on that target's row. After doing so, the target will be restored across runs, and will no longer need to be specified on the command-line."; - @subtitle "View Rules"; - @p "*View rules* are used to transform the way that evaluations in the debugger are visualized. An evaluation is produced by taking an expression string - for instance, the name of a variable - and using debug info and information from an attached process' live runtime (memory, registers, and so on) to interpret it."; + @subtitle "Views"; + @p "*Views* are used to transform the way that evaluations in the debugger are visualized. An evaluation is produced by taking an expression string - for instance, the name of a variable - and using debug info and information from an attached process' live runtime (memory, registers, and so on) to interpret it."; @p "Evaluations may be visualized in a variety of ways. A 64-bit unsigned integer may be visualized as a textual representation of the value with a radix of 10. A 32-bit floating-point value may be visualized as a textual representation of the value. An array of 32-bit floating-point values can be visualized as a list of textual representations of those values."; - @p "But all of these cases may be visualized in a number of other ways, as well. A 64-bit unsigned integer may be more usefully represented with a radix of 16, 8, or 2. An array of 32-bit floating-point values may encode the R, G, B, and A components of a color, or vertex positions for 3D geometry, or samples for a waveform. An array of bytes may encode raw pixel data for an image, or image data in a compressed format. A struct may have several members which are not useful to look at all the time. A struct may form the head of a linked list, and a flat linked list representation may be more preferable than the traditional watch view representation, which adds an additional layer of hierarchical nesting with the expansion of each 'next' pointer in a linked list. When designing the debugger, we felt that the traditional memory view and watch view representations of data in a debugged-process were not sufficient. View rules were added to the traditional watch view structure to allow per-row specification of extra visualization parameters."; - @p "View rules are specified with the name of a view rule, and depending on the view rule, a `:`, followed by parameters for the view rule. These parameters may be whitespace delimited, but importantly, multiple view rules may be specified per-row in a watch view. To explicitly separate the parameters of one view rule from the name of another - for instance, in a case like `array:16 bin`, where `bin` will not be interpreted as a view rule, but as a parameter of `array` - then commas and semicolons may be used to separate the two view rules (`array:16, bin`), or parentheses/braces/brackets may also be used to explicitly delimit the view rule parameters (`array:(16) bin`)."; - @p "A list of currently-supported view rules are below:"; + @p "But all of these cases may be visualized in a number of other ways, as well. A 64-bit unsigned integer may be more usefully represented with a radix of 16, 8, or 2. An array of 32-bit floating-point values may encode the R, G, B, and A components of a color, or vertex positions for 3D geometry, or samples for a waveform. An array of bytes may encode raw pixel data for an image, or image data in a compressed format. A struct may have several members which are not useful to look at all the time. A struct may form the head of a linked list, and a flat linked list representation may be more preferable than the traditional watch view representation, which adds an additional layer of hierarchical nesting with the expansion of each 'next' pointer in a linked list. When designing the debugger, we felt that the traditional memory view and watch view representations of data in a debugged-process were not sufficient. Views were added to the traditional watch table structure to allow per-expression specification of extra visualization parameters."; + @p "Views look just like function calls. They start with the name of the view, a `(`, then a list of expressions which form the arguments for the view (optionally delimited by `,`s), followed by a `)`. The meaning of these arguments can sometimes be inferred through their order; for example, in the case of `bitmap(ptr, 512, 256)`, the `bitmap` view uses the `ptr` as the primary expression to interpret as bitmap data, then assumes the widely-used pattern of width, then height, to interpret the following arguments as the dimensions of the bitmap. In other cases, arguments must be specifically named. For instance, the `fmt` argument in `bitmap(ptr, 512, 256, fmt=bgra8)` is required to override the `bitmap` view's default assumption of RGBA8 bitmap data."; + @p "A list of currently-supported views are below:"; @unordered_list { - @expand(D_ViewRuleTable a) @p "$(a.docs == 'x' -> '`'..a.string..'` ('..a.display_name..') '..a.description)"; + // TODO(rjf): @lenses generate via metaprogram + @p "`raw(expr)`: Ignores all views used in `expr`, including those automatically applied by type views."; + @p "`bin(expr)`: Visualizes all numeric values evaluated in `expr` as base-2 (binary)."; + @p "`oct(expr)`: Visualizes all numeric values evaluated in `expr` as base-8 (octal)."; + @p "`dec(expr)`: Visualizes all numeric values evaluated in `expr` as base-10 (decimal)."; + @p "`hex(expr)`: Visualizes all numeric values evaluated in `expr` as base-16 (hexadecimal)."; + @p "`digits(expr, num)`: Visualizes at least `num` digits in all numeric values evaluated in `expr`."; + @p "`no_string(expr)`: Disables textual string visualization with pointer evaluations in `expr`."; + @p "`no_char(expr)`: Disables character visualization with character or integer evaluations in `expr`."; + @p "`no_addr(expr)`: Disables explicit address visualization with pointer evaluations in `expr`."; + @p "`sequence(expr)`: Interprets `expr` as an integer, encoding how many sub-expressions `expr` should expand to produce. This can be used in combination with the `table` view to easily generate tables, indexing amongst many arrays."; + @p "`rows(expr, ...)`: Interpreting all post-`expr` arguments as member names, only expands to show those members of `expr`."; + @p "`omit(expr, ...)`: Interpreting all post-`expr` arguments as member names, expands to show all members of `expr`, except those with matching names."; + @p "`range1(expr, min, max)`: Expresses that `expr` is a bounded numeric value between `min` and `max`. Interpreted by the debugger to build slider UI for an evaluation."; + @p "`array(expr, count)`: Expresses that `expr` points to `count` values, rather than 1, or the fixed size implied by a static array. When expanded, displays only that many values."; + @p "`slice(expr)`: Expresses that `expr` evaluates to a structure type which bundles a base pointer and a count (encoding how many elements to which the base pointer points). This count can be expressed either as an integer, or as an 'end pointer'. When expanded, displays that many elements following that base pointer."; + @p "`table(expr, ...)`: Expresses that `expr` should be expanded normally, but interprets all post-`expr` arguments as expressions which should be used to form cells for rows which are generated by this expression's expansions. This replaces the normal cells which are generated for an expansion in a Watch table."; + @p "`text(expr, [lang = ...])`: Generates a text visualizer, interpreting `expr` as (being or pointing to) text."; + @p "`disasm(expr, [size = ...]`: Generates a disassembly visualizer, interpreting `expr` as (being or pointing to) machine code."; + @p "`memory(expr, [size = ...])`: Generates a memory visualizer, interpreting `expr` as (being or pointing to) raw bytes."; + @p "`bitmap(expr, width, height, [fmt = ...])`: Generates a bitmap visualizer, interpreting `expr` as (being or pointing to) raw bitmap data, with `width` and `height` as dimensions."; + @p "`color(expr)`: Generates a color picker, interpreting `expr` as a color value."; } @subtitle "Breakpoints"; - @p "Breakpoints interrupt execution of attached processes. They may be placed on specific code addresses, lines of source code, on specific symbol names. In the latter two cases, the higher level locations are resolved to code addresses. If there is no code associated with a line of source code, then the resolution path chooses to use the next closest line of source code in the same file. A symbol name breakpoint will only work if the symbol name is found within loaded debug info."; + @p "Breakpoints interrupt execution of attached processes. They may be placed on arbitrary addresses (e.g. by placing a breakpoint on an instruction within a disassembly view, or with an arbitrary expression, like the name of a function), or on lines of source code. In the latter case, the source code location is resolved to code addresses. If there is no code associated with a line of source code, then the resolution path chooses to use the next closest line of source code in the same file."; @p "Breakpoints may have stop conditions attached to them. When a breakpoint is hit by a thread, before it stops execution, the stop condition is evaluated, and if it evaluates to a nonzero value, only then is execution stopped."; @p "Each breakpoint has a hit count. Every time a breakpoint causes execution to stop, this counter is increased."; - @p "Processor breakpoints are not currently supported, but planned to be in the future."; + @p "Address breakpoints can also point to data, rather than code. This will cause execution to stop if some data is read from, written to, or executed. In this case, the debugger configures the hardware to use the available hardware data breakpoints feature. To enable this path, in the breakpoint's editor, express the number of bytes following the address that should be checked for writes/reads/executions (can be 1, 2, 4, or 8), and select whether or not you want to break on reads, writes, or executions."; @subtitle "User & Project Files"; @p "Applicable state controlling the debugger's appearance, behavior, targets, breakpoints, and other configurations is saved and reloaded across runs of the debugger through both *user files* and *project files*. These files are auto-saved. These files are written in a textual format which can be hand-edited as necessary, but they're also continuously re-read and re-written by the debugger. By default, the debugger uses `%appdata%/raddbg/default.raddbg_user` for its user file path, and `%appdata%/raddbg/default.raddbg_project` for its project file path. These paths can be overridden on the command line (see the 'Command-Line Usage' section)."; diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 8ba4a716..0c639e56 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.10f, 0.20f, 0.25f +#undef LAYER_COLOR +#define LAYER_COLOR 0xf0a215ff //////////////////////////////// //~ rjf: Generated Code @@ -10,115 +10,24 @@ #include "generated/raddbg.meta.c" //////////////////////////////// -//~ rjf: Handles - -internal RD_Handle -rd_handle_zero(void) -{ - RD_Handle result = {0}; - return result; -} - -internal B32 -rd_handle_match(RD_Handle a, RD_Handle b) -{ - return (a.u64[0] == b.u64[0] && a.u64[1] == b.u64[1]); -} +//~ rjf: Config ID Type Functions internal void -rd_handle_list_push_node(RD_HandleList *list, RD_HandleNode *node) +rd_cfg_id_list_push(Arena *arena, RD_CfgIDList *list, RD_CfgID id) { - DLLPushBack(list->first, list->last, node); + RD_CfgIDNode *n = push_array(arena, RD_CfgIDNode, 1); + n->v = id; + SLLQueuePush(list->first, list->last, n); list->count += 1; } -internal void -rd_handle_list_push(Arena *arena, RD_HandleList *list, RD_Handle handle) +internal RD_CfgIDList +rd_cfg_id_list_copy(Arena *arena, RD_CfgIDList *src) { - RD_HandleNode *n = push_array(arena, RD_HandleNode, 1); - n->handle = handle; - rd_handle_list_push_node(list, n); -} - -internal RD_HandleList -rd_handle_list_copy(Arena *arena, RD_HandleList list) -{ - RD_HandleList result = {0}; - for(RD_HandleNode *n = list.first; n != 0; n = n->next) + RD_CfgIDList result = {0}; + for(RD_CfgIDNode *n = src->first; n != 0; n = n->next) { - rd_handle_list_push(arena, &result, n->handle); - } - return result; -} - -//////////////////////////////// -//~ rjf: Config Type Functions - -internal void -rd_cfg_table_push_unparsed_string(Arena *arena, RD_CfgTable *table, String8 string, RD_CfgSrc source) -{ - if(table->slot_count == 0) - { - table->slot_count = 64; - table->slots = push_array(arena, RD_CfgSlot, table->slot_count); - } - MD_TokenizeResult tokenize = md_tokenize_from_text(arena, string); - MD_ParseResult parse = md_parse_from_text_tokens(arena, str8_lit(""), string, tokenize.tokens); - for MD_EachNode(tln, parse.root->first) if(tln->string.size != 0) - { - // rjf: map string -> hash*slot - String8 string = str8(tln->string.str, tln->string.size); - U64 hash = d_hash_from_string__case_insensitive(string); - U64 slot_idx = hash % table->slot_count; - RD_CfgSlot *slot = &table->slots[slot_idx]; - - // rjf: find existing value for this string - RD_CfgVal *val = 0; - for(RD_CfgVal *v = slot->first; v != 0; v = v->hash_next) - { - if(str8_match(v->string, string, StringMatchFlag_CaseInsensitive)) - { - val = v; - break; - } - } - - // rjf: create new value if needed - if(val == 0) - { - val = push_array(arena, RD_CfgVal, 1); - val->string = push_str8_copy(arena, string); - val->insertion_stamp = table->insertion_stamp_counter; - SLLStackPush_N(slot->first, val, hash_next); - SLLQueuePush_N(table->first_val, table->last_val, val, linear_next); - table->insertion_stamp_counter += 1; - } - - // rjf: create new node within this value - RD_CfgTree *tree = push_array(arena, RD_CfgTree, 1); - SLLQueuePush_NZ(&d_nil_cfg_tree, val->first, val->last, tree, next); - tree->source = source; - tree->root = md_tree_copy(arena, tln); - } -} - -internal RD_CfgVal * -rd_cfg_val_from_string(RD_CfgTable *table, String8 string) -{ - RD_CfgVal *result = &d_nil_cfg_val; - if(table->slot_count != 0) - { - U64 hash = d_hash_from_string__case_insensitive(string); - U64 slot_idx = hash % table->slot_count; - RD_CfgSlot *slot = &table->slots[slot_idx]; - for(RD_CfgVal *val = slot->first; val != 0; val = val->hash_next) - { - if(str8_match(val->string, string, StringMatchFlag_CaseInsensitive)) - { - result = val; - break; - } - } + rd_cfg_id_list_push(arena, &result, n->v); } return result; } @@ -130,16 +39,17 @@ internal void rd_regs_copy_contents(Arena *arena, RD_Regs *dst, RD_Regs *src) { MemoryCopyStruct(dst, src); - dst->entity_list = rd_handle_list_copy(arena, src->entity_list); + dst->cfg_list = rd_cfg_id_list_copy(arena, &src->cfg_list); dst->file_path = push_str8_copy(arena, src->file_path); dst->lines = d_line_list_copy(arena, &src->lines); dst->dbgi_key = di_key_copy(arena, &src->dbgi_key); + dst->expr = push_str8_copy(arena, src->expr); dst->string = push_str8_copy(arena, src->string); dst->cmd_name = push_str8_copy(arena, src->cmd_name); dst->params_tree = md_tree_copy(arena, src->params_tree); - if(dst->entity_list.count == 0 && !rd_handle_match(rd_handle_zero(), dst->entity)) + if(dst->cfg_list.count == 0 && dst->cfg != 0) { - rd_handle_list_push(arena, &dst->entity_list, dst->entity); + rd_cfg_id_list_push(arena, &dst->cfg_list, dst->cfg); } } @@ -165,695 +75,46 @@ rd_cmd_list_push_new(Arena *arena, RD_CmdList *cmds, String8 name, RD_Regs *regs } //////////////////////////////// -//~ rjf: Entity Functions +//~ rjf: View UI Rule Functions -//- rjf: nil - -internal B32 -rd_entity_is_nil(RD_Entity *entity) +internal RD_ViewUIRuleMap * +rd_view_ui_rule_map_make(Arena *arena, U64 slots_count) { - return (entity == 0 || entity == &rd_nil_entity); -} - -//- rjf: handle <-> entity conversions - -internal U64 -rd_index_from_entity(RD_Entity *entity) -{ - return (U64)(entity - rd_state->entities_base); -} - -internal RD_Handle -rd_handle_from_entity(RD_Entity *entity) -{ - RD_Handle handle = rd_handle_zero(); - if(!rd_entity_is_nil(entity)) - { - handle.u64[0] = rd_index_from_entity(entity); - handle.u64[1] = entity->gen; - } - return handle; -} - -internal RD_Entity * -rd_entity_from_handle(RD_Handle handle) -{ - RD_Entity *result = rd_state->entities_base + handle.u64[0]; - if(handle.u64[0] >= rd_state->entities_count || result->gen != handle.u64[1]) - { - result = &rd_nil_entity; - } - return result; -} - -//- rjf: entity recursion iterators - -internal RD_EntityRec -rd_entity_rec_depth_first(RD_Entity *entity, RD_Entity *subtree_root, U64 sib_off, U64 child_off) -{ - RD_EntityRec result = {0}; - if(!rd_entity_is_nil(*MemberFromOffset(RD_Entity **, entity, child_off))) - { - result.next = *MemberFromOffset(RD_Entity **, entity, child_off); - result.push_count = 1; - } - else for(RD_Entity *parent = entity; parent != subtree_root && !rd_entity_is_nil(parent); parent = parent->parent) - { - if(parent != subtree_root && !rd_entity_is_nil(*MemberFromOffset(RD_Entity **, parent, sib_off))) - { - result.next = *MemberFromOffset(RD_Entity **, parent, sib_off); - break; - } - result.pop_count += 1; - } - return result; -} - -//- rjf: ancestor/child introspection - -internal RD_Entity * -rd_entity_child_from_kind(RD_Entity *entity, RD_EntityKind kind) -{ - RD_Entity *result = &rd_nil_entity; - for(RD_Entity *child = entity->first; !rd_entity_is_nil(child); child = child->next) - { - if(!(child->flags & RD_EntityFlag_MarkedForDeletion) && child->kind == kind) - { - result = child; - break; - } - } - return result; -} - -//- rjf: entity list building - -internal void -rd_entity_list_push(Arena *arena, RD_EntityList *list, RD_Entity *entity) -{ - RD_EntityNode *n = push_array(arena, RD_EntityNode, 1); - n->entity = entity; - SLLQueuePush(list->first, list->last, n); - list->count += 1; -} - -internal RD_EntityArray -rd_entity_array_from_list(Arena *arena, RD_EntityList *list) -{ - RD_EntityArray result = {0}; - result.count = list->count; - result.v = push_array(arena, RD_Entity *, result.count); - U64 idx = 0; - for(RD_EntityNode *n = list->first; n != 0; n = n->next, idx += 1) - { - result.v[idx] = n->entity; - } - return result; -} - -//- rjf: entity -> color operations - -internal Vec4F32 -rd_hsva_from_entity(RD_Entity *entity) -{ - Vec4F32 result = {0}; - if(entity->flags & RD_EntityFlag_HasColor) - { - result = entity->color_hsva; - } - return result; -} - -internal Vec4F32 -rd_rgba_from_entity(RD_Entity *entity) -{ - Vec4F32 result = {0}; - if(entity->flags & RD_EntityFlag_HasColor) - { - Vec3F32 hsv = v3f32(entity->color_hsva.x, entity->color_hsva.y, entity->color_hsva.z); - Vec3F32 rgb = rgb_from_hsv(hsv); - result = v4f32(rgb.x, rgb.y, rgb.z, entity->color_hsva.w); - } - else switch(entity->kind) - { - default:{}break; - case RD_EntityKind_Breakpoint: - { - result = rd_rgba_from_theme_color(RD_ThemeColor_Breakpoint); - }break; - } - return result; -} - -//- rjf: entity -> expansion tree keys - -internal EV_Key -rd_ev_key_from_entity(RD_Entity *entity) -{ - EV_Key parent_key = rd_parent_ev_key_from_entity(entity); - EV_Key key = ev_key_make(ev_hash_from_key(parent_key), (U64)entity); - return key; -} - -internal EV_Key -rd_parent_ev_key_from_entity(RD_Entity *entity) -{ - EV_Key parent_key = ev_key_make(5381, (U64)entity); - return parent_key; -} - -//////////////////////////////// -//~ rjf: View Type Functions - -internal B32 -rd_view_is_nil(RD_View *view) -{ - return (view == 0 || view == &rd_nil_view); -} - -internal B32 -rd_view_is_project_filtered(RD_View *view) -{ - B32 result = 0; - String8 view_project = view->project_path; - if(view_project.size != 0) - { - RD_ViewRuleKind kind = rd_view_rule_kind_from_string(view->spec->string); - // TODO(rjf): @hack hack hack - this should be completely determined if the view - // is parameterized by an expression, but that is currently the same string as the - // query, and so we can't rely on that. when query expressions are separated from - // filter strings, we can rely on that here. - if((kind == RD_ViewRuleKind_Text || - kind == RD_ViewRuleKind_Disasm || - kind == RD_ViewRuleKind_Memory || - kind == RD_ViewRuleKind_Bitmap || - kind == RD_ViewRuleKind_Geo3D) && - view->query_string_size != 0) - { - String8 current_project = rd_cfg_path_from_src(RD_CfgSrc_Project); - result = !path_match_normalized(view_project, current_project); - } - } - return result; -} - -internal RD_Handle -rd_handle_from_view(RD_View *view) -{ - RD_Handle handle = rd_handle_zero(); - if(!rd_view_is_nil(view)) - { - handle.u64[0] = (U64)view; - handle.u64[1] = view->generation; - } - return handle; -} - -internal RD_View * -rd_view_from_handle(RD_Handle handle) -{ - RD_View *result = (RD_View *)handle.u64[0]; - if(rd_view_is_nil(result) || result->generation != handle.u64[1]) - { - result = &rd_nil_view; - } - return result; -} - -//////////////////////////////// -//~ rjf: View Spec Type Functions - -internal RD_ViewRuleKind -rd_view_rule_kind_from_string(String8 string) -{ - RD_ViewRuleKind kind = RD_ViewRuleKind_Null; - for EachEnumVal(RD_ViewRuleKind, k) - { - if(str8_match(string, rd_view_rule_kind_info_table[k].string, 0)) - { - kind = k; - break; - } - } - return kind; -} - -internal RD_ViewRuleInfo * -rd_view_rule_info_from_kind(RD_ViewRuleKind kind) -{ - return &rd_view_rule_kind_info_table[kind]; -} - -internal RD_ViewRuleInfo * -rd_view_rule_info_from_string(String8 string) -{ - RD_ViewRuleInfo *result = &rd_nil_view_rule_info; - { - RD_ViewRuleKind kind = rd_view_rule_kind_from_string(string); - if(kind != RD_ViewRuleKind_Null) - { - result = &rd_view_rule_kind_info_table[kind]; - } - } - return result; -} - -//////////////////////////////// -//~ rjf: Panel Type Functions - -//- rjf: basic type functions - -internal B32 -rd_panel_is_nil(RD_Panel *panel) -{ - return panel == 0 || panel == &rd_nil_panel; -} - -internal RD_Handle -rd_handle_from_panel(RD_Panel *panel) -{ - RD_Handle h = {0}; - h.u64[0] = (U64)panel; - h.u64[1] = panel->generation; - return h; -} - -internal RD_Panel * -rd_panel_from_handle(RD_Handle handle) -{ - RD_Panel *panel = (RD_Panel *)handle.u64[0]; - if(panel == 0 || panel->generation != handle.u64[1]) - { - panel = &rd_nil_panel; - } - return panel; -} - -internal UI_Key -rd_ui_key_from_panel(RD_Panel *panel) -{ - UI_Key panel_key = ui_key_from_stringf(ui_key_zero(), "panel_window_%p", panel); - return panel_key; -} - -//- rjf: tree construction - -internal void -rd_panel_insert(RD_Panel *parent, RD_Panel *prev_child, RD_Panel *new_child) -{ - DLLInsert_NPZ(&rd_nil_panel, parent->first, parent->last, prev_child, new_child, next, prev); - parent->child_count += 1; - new_child->parent = parent; + RD_ViewUIRuleMap *map = push_array(arena, RD_ViewUIRuleMap, 1); + map->slots_count = slots_count; + map->slots = push_array(arena, RD_ViewUIRuleSlot, map->slots_count); + return map; } internal void -rd_panel_remove(RD_Panel *parent, RD_Panel *child) +rd_view_ui_rule_map_insert(Arena *arena, RD_ViewUIRuleMap *map, String8 string, RD_ViewUIFunctionType *ui) { - DLLRemove_NPZ(&rd_nil_panel, parent->first, parent->last, child, next, prev); - child->next = child->prev = child->parent = &rd_nil_panel; - parent->child_count -= 1; + U64 hash = d_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + RD_ViewUIRuleNode *n = push_array(arena, RD_ViewUIRuleNode, 1); + n->v.name = push_str8_copy(arena, string); + n->v.ui = ui; + SLLQueuePush(map->slots[slot_idx].first, map->slots[slot_idx].last, n); } -//- rjf: tree walk - -internal RD_PanelRec -rd_panel_rec_depth_first(RD_Panel *panel, U64 sib_off, U64 child_off) +internal RD_ViewUIRule * +rd_view_ui_rule_from_string(String8 string) { - RD_PanelRec rec = {0}; - if(!rd_panel_is_nil(*MemberFromOffset(RD_Panel **, panel, child_off))) + RD_ViewUIRule *rule = &rd_nil_view_ui_rule; { - rec.next = *MemberFromOffset(RD_Panel **, panel, child_off); - rec.push_count = 1; - } - else if(!rd_panel_is_nil(*MemberFromOffset(RD_Panel **, panel, sib_off))) - { - rec.next = *MemberFromOffset(RD_Panel **, panel, sib_off); - } - else - { - RD_Panel *uncle = &rd_nil_panel; - for(RD_Panel *p = panel->parent; !rd_panel_is_nil(p); p = p->parent) + RD_ViewUIRuleMap *map = rd_state->view_ui_rule_map; + U64 hash = d_hash_from_string(string); + U64 slot_idx = hash%map->slots_count; + for(RD_ViewUIRuleNode *n = map->slots[slot_idx].first; n != 0; n = n->next) { - rec.pop_count += 1; - if(!rd_panel_is_nil(*MemberFromOffset(RD_Panel **, p, sib_off))) + if(str8_match(n->v.name, string, 0)) { - uncle = *MemberFromOffset(RD_Panel **, p, sib_off); + rule = &n->v; break; } } - rec.next = uncle; } - return rec; -} - -//- rjf: panel -> rect calculations - -internal Rng2F32 -rd_target_rect_from_panel_child(Rng2F32 parent_rect, RD_Panel *parent, RD_Panel *panel) -{ - Rng2F32 rect = parent_rect; - if(!rd_panel_is_nil(parent)) - { - Vec2F32 parent_rect_size = dim_2f32(parent_rect); - Axis2 axis = parent->split_axis; - rect.p1.v[axis] = rect.p0.v[axis]; - for(RD_Panel *child = parent->first; !rd_panel_is_nil(child); child = child->next) - { - rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent; - if(child == panel) - { - break; - } - rect.p0.v[axis] = rect.p1.v[axis]; - } - //rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; - //rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; - } - rect.x0 = round_f32(rect.x0); - rect.x1 = round_f32(rect.x1); - rect.y0 = round_f32(rect.y0); - rect.y1 = round_f32(rect.y1); - return rect; -} - -internal Rng2F32 -rd_target_rect_from_panel(Rng2F32 root_rect, RD_Panel *root, RD_Panel *panel) -{ - Temp scratch = scratch_begin(0, 0); - - // rjf: count ancestors - U64 ancestor_count = 0; - for(RD_Panel *p = panel->parent; !rd_panel_is_nil(p); p = p->parent) - { - ancestor_count += 1; - } - - // rjf: gather ancestors - RD_Panel **ancestors = push_array(scratch.arena, RD_Panel *, ancestor_count); - { - U64 ancestor_idx = 0; - for(RD_Panel *p = panel->parent; !rd_panel_is_nil(p); p = p->parent) - { - ancestors[ancestor_idx] = p; - ancestor_idx += 1; - } - } - - // rjf: go from highest ancestor => panel and calculate rect - Rng2F32 parent_rect = root_rect; - for(S64 ancestor_idx = (S64)ancestor_count-1; - 0 <= ancestor_idx && ancestor_idx < ancestor_count; - ancestor_idx -= 1) - { - RD_Panel *ancestor = ancestors[ancestor_idx]; - RD_Panel *parent = ancestor->parent; - if(!rd_panel_is_nil(parent)) - { - parent_rect = rd_target_rect_from_panel_child(parent_rect, parent, ancestor); - } - } - - // rjf: calculate final rect - Rng2F32 rect = rd_target_rect_from_panel_child(parent_rect, panel->parent, panel); - - scratch_end(scratch); - return rect; -} - -//- rjf: view ownership insertion/removal - -internal void -rd_panel_insert_tab_view(RD_Panel *panel, RD_View *prev_view, RD_View *view) -{ - DLLInsert_NPZ(&rd_nil_view, panel->first_tab_view, panel->last_tab_view, prev_view, view, order_next, order_prev); - panel->tab_view_count += 1; - if(!rd_view_is_project_filtered(view)) - { - panel->selected_tab_view = rd_handle_from_view(view); - } -} - -internal void -rd_panel_remove_tab_view(RD_Panel *panel, RD_View *view) -{ - if(rd_view_from_handle(panel->selected_tab_view) == view) - { - panel->selected_tab_view = rd_handle_zero(); - if(rd_handle_match(rd_handle_zero(), panel->selected_tab_view)) - { - for(RD_View *v = view->order_next; !rd_view_is_nil(v); v = v->order_next) - { - if(!rd_view_is_project_filtered(v)) - { - panel->selected_tab_view = rd_handle_from_view(v); - break; - } - } - } - if(rd_handle_match(rd_handle_zero(), panel->selected_tab_view)) - { - for(RD_View *v = view->order_prev; !rd_view_is_nil(v); v = v->order_prev) - { - if(!rd_view_is_project_filtered(v)) - { - panel->selected_tab_view = rd_handle_from_view(v); - break; - } - } - } - } - DLLRemove_NPZ(&rd_nil_view, panel->first_tab_view, panel->last_tab_view, view, order_next, order_prev); - panel->tab_view_count -= 1; -} - -internal RD_View * -rd_selected_tab_from_panel(RD_Panel *panel) -{ - RD_View *view = rd_view_from_handle(panel->selected_tab_view); - if(rd_view_is_project_filtered(view)) - { - view = &rd_nil_view; - } - return view; -} - -//- rjf: icons & display strings - -internal RD_IconKind -rd_icon_kind_from_view(RD_View *view) -{ - RD_IconKind result = view->spec->icon_kind; - return result; -} - -internal DR_FancyStringList -rd_title_fstrs_from_view(Arena *arena, RD_View *view, Vec4F32 primary_color, Vec4F32 secondary_color, F32 size) -{ - DR_FancyStringList result = {0}; - Temp scratch = scratch_begin(&arena, 1); - String8 query = str8(view->query_buffer, view->query_string_size); - String8 file_path = rd_file_path_from_eval_string(scratch.arena, query); - - //- rjf: query is file path - do specific file name strings - if(file_path.size != 0) - { - // rjf: compute disambiguated file name - String8List qualifiers = {0}; - String8 file_name = str8_skip_last_slash(file_path); - if(rd_state->ambiguous_path_slots_count != 0) - { - U64 hash = d_hash_from_string__case_insensitive(file_name); - U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; - RD_AmbiguousPathNode *node = 0; - { - for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; - n != 0; - n = n->next) - { - if(str8_match(n->name, file_name, StringMatchFlag_CaseInsensitive)) - { - node = n; - break; - } - } - } - if(node != 0 && node->paths.node_count > 1) - { - // rjf: get all colliding paths - String8Array collisions = str8_array_from_list(scratch.arena, &node->paths); - - // rjf: get all reversed path parts for each collision - String8List *collision_parts_reversed = push_array(scratch.arena, String8List, collisions.count); - for EachIndex(idx, collisions.count) - { - String8List parts = str8_split_path(scratch.arena, collisions.v[idx]); - for(String8Node *n = parts.first; n != 0; n = n->next) - { - str8_list_push_front(scratch.arena, &collision_parts_reversed[idx], n->string); - } - } - - // rjf: get the search path & its reversed parts - String8List parts = str8_split_path(scratch.arena, file_path); - String8List parts_reversed = {0}; - for(String8Node *n = parts.first; n != 0; n = n->next) - { - str8_list_push_front(scratch.arena, &parts_reversed, n->string); - } - - // rjf: iterate all collision part reversed lists, in lock-step with - // search path; disqualify until we only have one path remaining; gather - // qualifiers - { - U64 num_collisions_left = collisions.count; - String8Node **collision_nodes = push_array(scratch.arena, String8Node *, collisions.count); - for EachIndex(idx, collisions.count) - { - collision_nodes[idx] = collision_parts_reversed[idx].first; - } - for(String8Node *n = parts_reversed.first; num_collisions_left > 1 && n != 0; n = n->next) - { - B32 part_is_qualifier = 0; - for EachIndex(idx, collisions.count) - { - if(collision_nodes[idx] != 0 && !str8_match(collision_nodes[idx]->string, n->string, StringMatchFlag_CaseInsensitive)) - { - collision_nodes[idx] = 0; - num_collisions_left -= 1; - part_is_qualifier = 1; - } - else if(collision_nodes[idx] != 0) - { - collision_nodes[idx] = collision_nodes[idx]->next; - } - } - if(part_is_qualifier) - { - str8_list_push_front(scratch.arena, &qualifiers, n->string); - } - } - } - } - } - - // rjf: push qualifiers - for(String8Node *n = qualifiers.first; n != 0; n = n->next) - { - String8 string = push_str8f(arena, "<%S> ", n->string); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size*0.95f, secondary_color, string); - } - - // rjf: push file name - DR_FancyString fstr = - { - rd_font_from_slot(RD_FontSlot_Main), - push_str8_copy(arena, file_name), - primary_color, - size, - }; - dr_fancy_string_list_push(arena, &result, &fstr); - } - - //- rjf: query is not file path - do general case, for view rule & expression - else - { - DR_FancyString fstr1 = - { - rd_font_from_slot(RD_FontSlot_Main), - view->spec->display_name, - primary_color, - size, - }; - dr_fancy_string_list_push(arena, &result, &fstr1); - if(query.size != 0) - { - DR_FancyString fstr2 = - { - rd_font_from_slot(RD_FontSlot_Code), - str8_lit(" "), - primary_color, - size, - }; - dr_fancy_string_list_push(arena, &result, &fstr2); - DR_FancyString fstr3 = - { - rd_font_from_slot(RD_FontSlot_Code), - push_str8_copy(arena, query), - secondary_color, - size*0.8f, - }; - dr_fancy_string_list_push(arena, &result, &fstr3); - } - } - scratch_end(scratch); - return result; -} - -//////////////////////////////// -//~ rjf: Window Type Functions - -internal RD_Handle -rd_handle_from_window(RD_Window *window) -{ - RD_Handle handle = {0}; - if(window != 0) - { - handle.u64[0] = (U64)window; - handle.u64[1] = window->gen; - } - return handle; -} - -internal RD_Window * -rd_window_from_handle(RD_Handle handle) -{ - RD_Window *window = (RD_Window *)handle.u64[0]; - if(window != 0 && window->gen != handle.u64[1]) - { - window = 0; - } - return window; -} - -//////////////////////////////// -//~ rjf: Command Parameters From Context - -internal B32 -rd_prefer_dasm_from_window(RD_Window *window) -{ - RD_Panel *panel = window->focused_panel; - RD_View *view = rd_selected_tab_from_panel(panel); - RD_ViewRuleKind view_kind = rd_view_rule_kind_from_string(view->spec->string); - B32 result = 0; - if(view_kind == RD_ViewRuleKind_Disasm) - { - result = 1; - } - else if(view_kind == RD_ViewRuleKind_Text) - { - result = 0; - } - else - { - B32 has_src = 0; - B32 has_dasm = 0; - for(RD_Panel *p = window->root_panel; !rd_panel_is_nil(p); p = rd_panel_rec_depth_first_pre(p).next) - { - RD_View *p_view = rd_selected_tab_from_panel(p); - RD_ViewRuleKind p_view_kind = rd_view_rule_kind_from_string(p_view->spec->string); - if(p_view_kind == RD_ViewRuleKind_Text) - { - has_src = 1; - } - if(p_view_kind == RD_ViewRuleKind_Disasm) - { - has_dasm = 1; - } - } - if(has_src && !has_dasm) {result = 0;} - if(has_dasm && !has_src) {result = 1;} - } - return result; + return rule; } //////////////////////////////// @@ -909,170 +170,233 @@ rd_get_hover_regs(void) return rd_state->hover_regs; } -internal void -rd_open_ctx_menu(UI_Key anchor_box_key, Vec2F32 anchor_box_off, RD_RegSlot slot) -{ - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - ui_ctx_menu_open(rd_state->ctx_menu_key, anchor_box_key, anchor_box_off); - arena_clear(window->ctx_menu_arena); - window->ctx_menu_regs = rd_regs_copy(window->ctx_menu_arena, rd_regs()); - window->ctx_menu_regs_slot = slot; - } -} - //////////////////////////////// //~ rjf: Name Allocation internal U64 -rd_name_bucket_idx_from_string_size(U64 size) +rd_name_bucket_num_from_string_size(U64 size) { - U64 size_rounded = u64_up_to_pow2(size+1); - size_rounded = ClampBot((1<<4), size_rounded); - U64 bucket_idx = 0; - switch(size_rounded) + U64 bucket_num = 0; + if(size > 0) { - case 1<<4: {bucket_idx = 0;}break; - case 1<<5: {bucket_idx = 1;}break; - case 1<<6: {bucket_idx = 2;}break; - case 1<<7: {bucket_idx = 3;}break; - case 1<<8: {bucket_idx = 4;}break; - case 1<<9: {bucket_idx = 5;}break; - case 1<<10:{bucket_idx = 6;}break; - default:{bucket_idx = ArrayCount(rd_state->free_name_chunks)-1;}break; + for EachElement(idx, rd_name_bucket_chunk_sizes) + { + if(size <= rd_name_bucket_chunk_sizes[idx]) + { + bucket_num = idx+1; + break; + } + } } - return bucket_idx; + return bucket_num; } internal String8 rd_name_alloc(String8 string) { - if(string.size == 0) {return str8_zero();} - U64 bucket_idx = rd_name_bucket_idx_from_string_size(string.size); - - // rjf: loop -> find node, allocate if not there - // - // (we do a loop here so that all allocation logic goes through - // the same path, such that we *always* pull off a free list, - // rather than just using what was pushed onto an arena directly, - // which is not undoable; the free lists we control, and are thus - // trivially undoable) - // + //- rjf: allocate node RD_NameChunkNode *node = 0; - for(;node == 0;) { - node = rd_state->free_name_chunks[bucket_idx]; - - // rjf: pull from bucket free list - if(node != 0) + U64 bucket_num = rd_name_bucket_num_from_string_size(string.size); + if(bucket_num == ArrayCount(rd_name_bucket_chunk_sizes)) { - if(bucket_idx == ArrayCount(rd_state->free_name_chunks)-1) + RD_NameChunkNode *best_node = 0; + RD_NameChunkNode *best_node_prev = 0; + U64 best_node_size = max_U64; { - node = 0; - RD_NameChunkNode *prev = 0; - for(RD_NameChunkNode *n = rd_state->free_name_chunks[bucket_idx]; - n != 0; - prev = n, n = n->next) + for(RD_NameChunkNode *n = rd_state->free_name_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next)) { - if(n->size >= string.size) + if(n->size >= string.size && n->size < best_node_size) { - if(prev == 0) - { - rd_state->free_name_chunks[bucket_idx] = n->next; - } - else - { - prev->next = n->next; - } - node = n; - break; + best_node = n; + best_node_prev = prev; + best_node_size = n->size; } } } + if(best_node != 0) + { + node = best_node; + if(best_node_prev) + { + best_node_prev->next = best_node->next; + } + else + { + rd_state->free_name_chunks[bucket_num-1] = best_node->next; + } + } else { - SLLStackPop(rd_state->free_name_chunks[bucket_idx]); + U64 chunk_size = u64_up_to_pow2(string.size); + node = (RD_NameChunkNode *)push_array(rd_state->arena, U8, chunk_size); } } - - // rjf: no found node -> allocate new, push onto associated free list - if(node == 0) + else if(bucket_num != 0) { - U64 chunk_size = 0; - if(bucket_idx < ArrayCount(rd_state->free_name_chunks)-1) + node = rd_state->free_name_chunks[bucket_num-1]; + if(node != 0) { - chunk_size = 1<<(bucket_idx+4); + SLLStackPop(rd_state->free_name_chunks[bucket_num-1]); } else { - chunk_size = u64_up_to_pow2(string.size); + node = (RD_NameChunkNode *)push_array(rd_state->arena, U8, rd_name_bucket_chunk_sizes[bucket_num-1]); } - U8 *chunk_memory = push_array(rd_state->arena, U8, chunk_size); - RD_NameChunkNode *chunk = (RD_NameChunkNode *)chunk_memory; - chunk->size = chunk_size; - SLLStackPush(rd_state->free_name_chunks[bucket_idx], chunk); } } - // rjf: fill string & return - String8 allocated_string = str8((U8 *)node, string.size); - MemoryCopy((U8 *)node, string.str, string.size); - return allocated_string; + //- rjf: fill node + String8 result = {0}; + if(node != 0) + { + result.str = (U8 *)node; + result.size = string.size; + MemoryCopy(result.str, string.str, result.size); + } + return result; } internal void rd_name_release(String8 string) { - if(string.size == 0) {return;} - U64 bucket_idx = rd_name_bucket_idx_from_string_size(string.size); - RD_NameChunkNode *node = (RD_NameChunkNode *)string.str; - node->size = u64_up_to_pow2(string.size); - SLLStackPush(rd_state->free_name_chunks[bucket_idx], node); + U64 bucket_num = rd_name_bucket_num_from_string_size(string.size); + if(1 <= bucket_num && bucket_num <= ArrayCount(rd_name_bucket_chunk_sizes)) + { + U64 bucket_idx = bucket_num-1; + RD_NameChunkNode *node = (RD_NameChunkNode *)string.str; + SLLStackPush(rd_state->free_name_chunks[bucket_idx], node); + node->size = u64_up_to_pow2(string.size); + } } //////////////////////////////// -//~ rjf: New Config/Entity Data Structure Functions +//~ rjf: Config Tree Functions internal RD_Cfg * rd_cfg_alloc(void) { + rd_state->cfg_change_gen += 1; + + // rjf: allocate RD_Cfg *result = rd_state->free_cfg; - if(result) { - SLLStackPop(rd_state->free_cfg); + if(result) + { + SLLStackPop(rd_state->free_cfg); + } + else + { + result = push_array_no_zero(rd_state->arena, RD_Cfg, 1); + } } - else - { - result = push_array_no_zero(rd_state->arena, RD_Cfg, 1); - } - U64 old_gen = result->gen; + + // rjf: generate ID & fill + rd_state->cfg_id_gen += 1; MemoryZeroStruct(result); result->first = result->last = result->next = result->prev = result->parent = &rd_nil_cfg; - result->gen = old_gen + 1; + result->id = rd_state->cfg_id_gen; + + // rjf: store to ID -> cfg map + { + RD_CfgNode *cfg_id_node = rd_state->free_cfg_id_node; + if(cfg_id_node != 0) + { + SLLStackPop(rd_state->free_cfg_id_node); + } + else + { + cfg_id_node = push_array(rd_state->arena, RD_CfgNode, 1); + } + U64 hash = d_hash_from_string(str8_struct(&result->id)); + U64 slot_idx = hash%rd_state->cfg_id_slots_count; + DLLPushBack(rd_state->cfg_id_slots[slot_idx].first, rd_state->cfg_id_slots[slot_idx].last, cfg_id_node); + cfg_id_node->v = result; + } + return result; } internal void rd_cfg_release(RD_Cfg *cfg) { + rd_state->cfg_change_gen += 1; + Temp scratch = scratch_begin(0, 0); + + // rjf: unhook from context rd_cfg_unhook(cfg->parent, cfg); + + // rjf: gather root & all descendants RD_CfgList nodes = {0}; for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rd_cfg_rec__depth_first(cfg, c).next) { rd_cfg_list_push(scratch.arena, &nodes, c); } + + // rjf: release all nodes for(RD_CfgNode *n = nodes.first; n != 0; n = n->next) { RD_Cfg *c = n->v; - c->gen += 1; rd_name_release(c->string); SLLStackPush(rd_state->free_cfg, c); + c->first = c->last = c->prev = c->parent = 0; + c->id = 0; + c->string = str8_zero(); + U64 hash = d_hash_from_string(str8_struct(&c->id)); + U64 slot_idx = hash%rd_state->cfg_id_slots_count; + for(RD_CfgNode *n = rd_state->cfg_id_slots[slot_idx].first; n != 0; n = n->next) + { + if(n->v == c) + { + DLLRemove(rd_state->cfg_id_slots[slot_idx].first, rd_state->cfg_id_slots[slot_idx].last, n); + SLLStackPush(rd_state->free_cfg_id_node, n); + break; + } + } } + scratch_end(scratch); } +internal void +rd_cfg_release_all_children(RD_Cfg *cfg) +{ + for(RD_Cfg *child = cfg->first, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) + { + next = child->next; + rd_cfg_release(child); + } +} + +internal RD_Cfg * +rd_cfg_from_id(RD_CfgID id) +{ + RD_Cfg *result = &rd_nil_cfg; + if(id != 0 && + id == rd_state->cfg_last_accessed_id && + id == rd_state->cfg_last_accessed->id) + { + result = rd_state->cfg_last_accessed; + } + else + { + U64 hash = d_hash_from_string(str8_struct(&id)); + U64 slot_idx = hash%rd_state->cfg_id_slots_count; + for(RD_CfgNode *n = rd_state->cfg_id_slots[slot_idx].first; n != 0; n = n->next) + { + if(n->v->id == id) + { + result = n->v; + break; + } + } + } + rd_state->cfg_last_accessed_id = id; + rd_state->cfg_last_accessed = result; + return result; +} + internal RD_Cfg * rd_cfg_new(RD_Cfg *parent, String8 string) { @@ -1095,27 +419,103 @@ rd_cfg_newf(RD_Cfg *parent, char *fmt, ...) return result; } +internal RD_Cfg * +rd_cfg_new_replace(RD_Cfg *parent, String8 string) +{ + Temp scratch = scratch_begin(0, 0); + string = push_str8_copy(scratch.arena, string); + for(RD_Cfg *child = parent->first->next, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) + { + next = child->next; + rd_cfg_release(child); + } + if(parent->first == &rd_nil_cfg) + { + rd_cfg_new(parent, str8_zero()); + } + RD_Cfg *child = parent->first; + rd_cfg_equip_string(child, string); + scratch_end(scratch); + return child; +} + +internal RD_Cfg * +rd_cfg_new_replacef(RD_Cfg *parent, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + RD_Cfg *result = rd_cfg_new_replace(parent, string); + va_end(args); + scratch_end(scratch); + return result; +} + +internal RD_Cfg * +rd_cfg_deep_copy(RD_Cfg *src_root) +{ + RD_CfgRec rec = {0}; + RD_Cfg *dst_root = &rd_nil_cfg; + RD_Cfg *dst_parent = &rd_nil_cfg; + for(RD_Cfg *src = src_root; src != &rd_nil_cfg; src = rec.next) + { + RD_Cfg *dst = rd_cfg_new(dst_parent, src->string); + if(dst_root == &rd_nil_cfg) + { + dst_root = dst; + } + rec = rd_cfg_rec__depth_first(src_root, src); + if(rec.push_count > 0) + { + dst_parent = dst; + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_parent = dst_parent->parent; + } + } + return dst_root; +} + internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string) { - if(cfg->string.size != 0) - { - rd_name_release(cfg->string); - } + rd_name_release(cfg->string); cfg->string = rd_name_alloc(string); + rd_state->cfg_change_gen += 1; +} + +internal void +rd_cfg_equip_stringf(RD_Cfg *cfg, char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + rd_cfg_equip_string(cfg, string); + va_end(args); + scratch_end(scratch); } internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child) { - DLLInsert_NPZ(&rd_nil_cfg, parent->first, parent->last, prev_child, new_child, next, prev); - new_child->parent = parent; + if(parent != &rd_nil_cfg) + { + if(new_child->parent != &rd_nil_cfg) + { + rd_cfg_unhook(new_child->parent, new_child); + } + DLLInsert_NPZ(&rd_nil_cfg, parent->first, parent->last, prev_child, new_child, next, prev); + new_child->parent = parent; + } } internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child) { - if(parent == child->parent && parent != &rd_nil_cfg) + if(child != &rd_nil_cfg && parent == child->parent && parent != &rd_nil_cfg) { DLLRemove_NPZ(&rd_nil_cfg, parent->first, parent->last, child, next, prev); child->parent = &rd_nil_cfg; @@ -1126,17 +526,42 @@ internal RD_Cfg * rd_cfg_child_from_string(RD_Cfg *parent, String8 string) { RD_Cfg *child = &rd_nil_cfg; - for(RD_Cfg *c = parent->first; c != &rd_nil_cfg; c = c->next) + if(string.size != 0) { - if(str8_match(c->string, string, 0)) + for(RD_Cfg *c = parent->first; c != &rd_nil_cfg; c = c->next) { - child = c; - break; + if(str8_match(c->string, string, 0)) + { + child = c; + break; + } } } return child; } +internal RD_Cfg * +rd_cfg_child_from_string_or_alloc(RD_Cfg *parent, String8 string) +{ + RD_Cfg *child = rd_cfg_child_from_string(parent, string); + if(child == &rd_nil_cfg) + { + child = rd_cfg_new(parent, string); + } + return child; +} + +internal RD_Cfg * +rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 string) +{ + RD_Cfg *result = rd_cfg_child_from_string(parent, string); + if(result == &rd_nil_cfg) + { + result = parent; + } + return result; +} + internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string) { @@ -1168,12 +593,30 @@ rd_cfg_top_level_list_from_string(Arena *arena, String8 string) return result; } +internal RD_CfgArray +rd_cfg_array_from_list(Arena *arena, RD_CfgList *list) +{ + RD_CfgArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, RD_Cfg *, array.count); + U64 idx = 0; + for(RD_CfgNode *n = list->first; n != 0; n = n->next, idx += 1) + { + array.v[idx] = n->v; + } + return array; +} + internal RD_CfgList -rd_cfg_tree_list_from_string(Arena *arena, String8 string) +rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string) { RD_CfgList result = {0}; Temp scratch = scratch_begin(&arena, 1); + + //- rjf: parse the string as metadesk MD_Node *root = md_tree_from_string(scratch.arena, string); + + //- rjf: iterate the top-level metadesk trees, generate new cfg trees for each for MD_EachNode(tln, root->first) { RD_Cfg *dst_root_n = &rd_nil_cfg; @@ -1181,19 +624,53 @@ rd_cfg_tree_list_from_string(Arena *arena, String8 string) MD_NodeRec rec = {0}; for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next) { + // rjf: lookup schema for this string + MD_Node *schema = &md_nil_node; + { + MD_NodePtrList schemas = rd_schemas_from_name(dst_active_parent_n->parent->string); + for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next) + { + schema = md_child_from_string(n->v, dst_active_parent_n->string, 0); + } + } + + // rjf: extract & transform metadesk node's string (it is raw textual data, so we need to + // go escaped -> raw, and derelativize paths) + String8 dst_n_string = {0}; + { + String8 src_n_string = src_n->string; + String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string); + if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0)) + { + if(str8_match(schema->first->string, str8_lit("path"), 0)) + { + src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path); + } + else if(str8_match(schema->first->string, str8_lit("path_pt"), 0)) + { + String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw); + src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column); + } + } + dst_n_string = src_n_string__raw; + } + + // rjf: allocate, fill, & insert new cfg for this metadesk node RD_Cfg *dst_n = rd_cfg_alloc(); - rd_cfg_equip_string(dst_n, src_n->string); + rd_cfg_equip_string(dst_n, dst_n_string); if(dst_active_parent_n != &rd_nil_cfg) { rd_cfg_insert_child(dst_active_parent_n, dst_active_parent_n->last, dst_n); } + + // rjf: recurse rec = md_node_rec_depth_first_pre(src_n, tln); + if(dst_active_parent_n == &rd_nil_cfg) + { + dst_root_n = dst_n; + } if(rec.push_count > 0) { - if(dst_active_parent_n == &rd_nil_cfg) - { - dst_root_n = dst_n; - } dst_active_parent_n = dst_n; } else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) @@ -1208,7 +685,7 @@ rd_cfg_tree_list_from_string(Arena *arena, String8 string) } internal String8 -rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) +rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg) { Temp scratch = scratch_begin(&arena, 1); String8List strings = {0}; @@ -1218,49 +695,101 @@ rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) { NestTask *next; RD_Cfg *cfg; + MD_Node *schema; B32 is_simple; }; NestTask *top_nest_task = 0; RD_CfgRec rec = {0}; for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = rec.next) { + // rjf: look up parent's schemas + MD_NodePtrList schemas = {0}; + if(top_nest_task != 0) + { + RD_Cfg *parent = top_nest_task->cfg; + schemas = rd_schemas_from_name(parent->string); + } + + // rjf: look up child schema + MD_Node *c_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next) + { + c_schema = md_child_from_string(n->v, c->string, 0); + } + // rjf: push name of this node if(c->string.size != 0 || c->first == &rd_nil_cfg) { + // rjf: extract the textualized form for this string (we may need to escape / relativize) + String8 c_serialized_string = c->string; + { + MD_Node *c_schema = &md_nil_node; + if(top_nest_task != 0) + { + c_schema = top_nest_task->schema; + } + + // rjf: paths -> relativize + if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0)) + { + if(str8_match(c_schema->first->string, str8_lit("path"), 0)) + { + String8 path_absolute = c->string; + String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path); + c_serialized_string = path_relative; + } + else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0)) + { + String8 value = c->string; + String8TxtPtPair parts = str8_txt_pt_pair_from_string(value); + String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path); + c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column); + } + } + + // rjf: all strings -> escape + c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string); + } + + // rjf: generate all strings for this node's string String8List c_name_strings = {0}; - B32 name_can_be_pushed_standalone = 0; { - Temp temp = temp_begin(scratch.arena); - MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c->string); - name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| - MD_TokenFlag_Numeric| - MD_TokenFlag_StringLiteral| - MD_TokenFlag_Symbol)); - temp_end(temp); - } - if(name_can_be_pushed_standalone) - { - str8_list_push(scratch.arena, &c_name_strings, c->string); - } - else - { - String8 c_name_escaped = escaped_from_raw_str8(scratch.arena, c->string); - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); - str8_list_push(scratch.arena, &c_name_strings, c_name_escaped); - str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + B32 name_can_be_pushed_standalone = 0; + { + Temp temp = temp_begin(scratch.arena); + MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string); + name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier| + MD_TokenFlag_Numeric| + MD_TokenFlag_StringLiteral| + MD_TokenFlag_Symbol)); + temp_end(temp); + } + if(name_can_be_pushed_standalone) + { + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + } + else + { + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + str8_list_push(scratch.arena, &c_name_strings, c_serialized_string); + str8_list_push(scratch.arena, &c_name_strings, str8_lit("\"")); + } } + + // rjf: if we're in a simple nesting task, then just break children by space if(top_nest_task != 0 && top_nest_task->is_simple) { str8_list_push(scratch.arena, &strings, str8_lit(" ")); } + + // rjf: join c's strings with main string list str8_list_concat_in_place(&strings, &c_name_strings); } // rjf: grab next recursion rec = rd_cfg_rec__depth_first(cfg, c); - // rjf: determine if this node is simple, and can be encoded on a single line - - // if so, push a new nesting task onto the stack + // rjf: push a new nesting task before descending to children if(c->first != &rd_nil_cfg) { B32 is_simple_children_list = 1; @@ -1274,6 +803,7 @@ rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg) } NestTask *task = push_array(scratch.arena, NestTask, 1); task->cfg = c; + task->schema = c_schema; task->is_simple = is_simple_children_list; SLLStackPush(top_nest_task, task); } @@ -1348,280 +878,626 @@ rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg) { RD_CfgNode *n = push_array(arena, RD_CfgNode, 1); n->v = cfg; - SLLQueuePush(list->first, list->last, n); + DLLPushBack(list->first, list->last, n); list->count += 1; } -//////////////////////////////// -//~ rjf: Entity State Functions - -//- rjf: entity allocation + tree forming - -internal RD_Entity * -rd_entity_alloc(RD_Entity *parent, RD_EntityKind kind) +internal void +rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg) { - B32 user_defined_lifetime = !!(rd_entity_kind_flags_table[kind] & RD_EntityKindFlag_UserDefinedLifetime); - U64 free_list_idx = !!user_defined_lifetime; - if(rd_entity_is_nil(parent)) { parent = rd_state->entities_root; } - - // rjf: empty free list -> push new - if(!rd_state->entities_free[free_list_idx]) + RD_CfgNode *n = push_array(arena, RD_CfgNode, 1); + n->v = cfg; + if(list->first != 0) { - RD_Entity *entity = push_array(rd_state->entities_arena, RD_Entity, 1); - rd_state->entities_count += 1; - rd_state->entities_free_count += 1; - SLLStackPush(rd_state->entities_free[free_list_idx], entity); - } - - // rjf: pop new entity off free-list - RD_Entity *entity = rd_state->entities_free[free_list_idx]; - SLLStackPop(rd_state->entities_free[free_list_idx]); - rd_state->entities_free_count -= 1; - rd_state->entities_active_count += 1; - - // rjf: zero entity - { - U64 gen = entity->gen; - MemoryZeroStruct(entity); - entity->gen = gen; - } - - // rjf: set up alloc'd entity links - entity->first = entity->last = entity->next = entity->prev = entity->parent = &rd_nil_entity; - entity->parent = parent; - - // rjf: stitch up parent links - if(rd_entity_is_nil(parent)) - { - rd_state->entities_root = entity; + n->next = list->first; } else { - DLLPushBack_NPZ(&rd_nil_entity, parent->first, parent->last, entity, next, prev); + list->last = n; } - - // rjf: fill out metadata - entity->kind = kind; - rd_state->entities_id_gen += 1; - entity->id = rd_state->entities_id_gen; - entity->gen += 1; - entity->alloc_time_us = os_now_microseconds(); - - // rjf: initialize to deleted, record history, then "undelete" if this allocation can be undone - if(user_defined_lifetime) - { - // TODO(rjf) - } - - // rjf: dirtify caches - rd_state->kind_alloc_gens[kind] += 1; - - // rjf: log - LogInfoNamedBlockF("new_entity") - { - log_infof("kind: \"%S\"\n", d_entity_kind_display_string_table[kind]); - log_infof("id: $0x%I64x\n", entity->id); - } - - return entity; + list->first = n; + list->count += 1; } -internal void -rd_entity_mark_for_deletion(RD_Entity *entity) +internal RD_PanelTree +rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg) { - if(!rd_entity_is_nil(entity)) + Temp scratch = scratch_begin(&arena, 1); + RD_Cfg *wcfg = rd_window_from_cfg(cfg); + RD_Cfg *src_root = rd_cfg_child_from_string(wcfg, str8_lit("panels")); + RD_PanelNode *dst_root = &rd_nil_panel_node; + RD_PanelNode *dst_focused = &rd_nil_panel_node; { - entity->flags |= RD_EntityFlag_MarkedForDeletion; - rd_state->kind_alloc_gens[entity->kind] += 1; + Axis2 active_split_axis = rd_cfg_child_from_string(wcfg, str8_lit("split_x")) != &rd_nil_cfg ? Axis2_X : Axis2_Y; + RD_CfgRec rec = {0}; + RD_PanelNode *dst_active_parent = &rd_nil_panel_node; + for(RD_Cfg *src = src_root; src != &rd_nil_cfg; src = rec.next) + { + // rjf: build a panel node + RD_PanelNode *dst = push_array(arena, RD_PanelNode, 1); + MemoryCopyStruct(dst, &rd_nil_panel_node); + dst->parent = dst_active_parent; + if(dst_active_parent != &rd_nil_panel_node) + { + DLLPushBack_NPZ(&rd_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev); + dst_active_parent->child_count += 1; + } + if(dst_root == &rd_nil_panel_node) + { + dst_root = dst; + } + + // rjf: extract cfg info + B32 panel_has_children = 0; + dst->cfg = src; + dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string)); + dst->tab_side = (rd_cfg_child_from_string(src, str8_lit("tabs_on_bottom")) != &rd_nil_cfg ? Side_Max : Side_Min); + dst->split_axis = active_split_axis; + for(RD_Cfg *src_child = src->first; src_child != &rd_nil_cfg; src_child = src_child->next) + { + MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string); + if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric) + { + panel_has_children = 1; + } + else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0)) + { + // NOTE(rjf): skip - this is a panel option. + } + else if(str8_match(src_child->string, str8_lit("selected"), 0)) + { + dst_focused = dst; + } + else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier) + { + rd_cfg_list_push(arena, &dst->tabs, src_child); + if(rd_cfg_child_from_string(src_child, str8_lit("selected")) != &rd_nil_cfg) + { + dst->selected_tab = src_child; + } + } + } + + // rjf: recurse + rec = rd_cfg_rec__depth_first(src_root, src); + if(!panel_has_children) + { + MemoryZeroStruct(&rec); + rec.next = &rd_nil_cfg; + for(RD_Cfg *p = src; p != src_root && p != &rd_nil_cfg; p = p->parent, rec.pop_count += 1) + { + if(p->next != &rd_nil_cfg) + { + rec.next = p->next; + break; + } + } + } + if(rec.push_count > 0) + { + dst_active_parent = dst; + active_split_axis = axis2_flip(active_split_axis); + } + else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) + { + dst_active_parent = dst_active_parent->parent; + active_split_axis = axis2_flip(active_split_axis); + } + } } + scratch_end(scratch); + RD_PanelTree tree = {dst_root, dst_focused}; + return tree; } -internal void -rd_entity_release(RD_Entity *entity) +internal RD_PanelNodeRec +rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off) +{ + RD_PanelNodeRec rec = {&rd_nil_panel_node}; + if(*MemberFromOffset(RD_PanelNode **, panel, child_off) != &rd_nil_panel_node) + { + rec.next = *MemberFromOffset(RD_PanelNode **, panel, child_off); + rec.push_count += 1; + } + else for(RD_PanelNode *p = panel; p != &rd_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1) + { + if(*MemberFromOffset(RD_PanelNode **, p, sib_off) != &rd_nil_panel_node) + { + rec.next = *MemberFromOffset(RD_PanelNode **, p, sib_off); + break; + } + } + return rec; +} + +internal RD_PanelNode * +rd_panel_node_from_tree_cfg(RD_PanelNode *root, RD_Cfg *cfg) +{ + RD_PanelNode *result = &rd_nil_panel_node; + for(RD_PanelNode *p = root; + p != &rd_nil_panel_node; + p = rd_panel_node_rec__depth_first_pre(root, p).next) + { + if(p->cfg == cfg) + { + result = p; + break; + } + } + return result; +} + +internal Rng2F32 +rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel) +{ + Rng2F32 rect = parent_rect; + if(parent != &rd_nil_panel_node) + { + Vec2F32 parent_rect_size = dim_2f32(parent_rect); + Axis2 axis = parent->split_axis; + rect.p1.v[axis] = rect.p0.v[axis]; + for(RD_PanelNode *child = parent->first; child != &rd_nil_panel_node; child = child->next) + { + rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent; + if(child == panel) + { + break; + } + rect.p0.v[axis] = rect.p1.v[axis]; + } + //rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis]; + //rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)]; + } + rect.x0 = round_f32(rect.x0); + rect.x1 = round_f32(rect.x1); + rect.y0 = round_f32(rect.y0); + rect.y1 = round_f32(rect.y1); + return rect; +} + +internal Rng2F32 +rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel) { Temp scratch = scratch_begin(0, 0); - // rjf: unpack - U64 free_list_idx = !!(rd_entity_kind_flags_table[entity->kind] & RD_EntityKindFlag_UserDefinedLifetime); - - // rjf: release whole tree - typedef struct Task Task; - struct Task + // rjf: count ancestors + U64 ancestor_count = 0; + for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) { - Task *next; - RD_Entity *e; - }; - Task start_task = {0, entity}; - Task *first_task = &start_task; - Task *last_task = &start_task; - for(Task *task = first_task; task != 0; task = task->next) - { - for(RD_Entity *child = task->e->first; !rd_entity_is_nil(child); child = child->next) - { - Task *t = push_array(scratch.arena, Task, 1); - t->e = child; - SLLQueuePush(first_task, last_task, t); - } - LogInfoNamedBlockF("end_entity") - { - log_infof("kind: \"%S\"\n", d_entity_kind_display_string_table[task->e->kind]); - log_infof("id: $0x%I64x\n", task->e->id); - } - SLLStackPush(rd_state->entities_free[free_list_idx], task->e); - rd_state->entities_free_count += 1; - rd_state->entities_active_count -= 1; - task->e->gen += 1; - if(task->e->string.size != 0) - { - rd_name_release(task->e->string); - } - rd_state->kind_alloc_gens[task->e->kind] += 1; + ancestor_count += 1; } + // rjf: gather ancestors + RD_PanelNode **ancestors = push_array(scratch.arena, RD_PanelNode *, ancestor_count); + { + U64 ancestor_idx = 0; + for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) + { + ancestors[ancestor_idx] = p; + ancestor_idx += 1; + } + } + + // rjf: go from highest ancestor => panel and calculate rect + Rng2F32 parent_rect = root_rect; + for(S64 ancestor_idx = (S64)ancestor_count-1; + 0 <= ancestor_idx && ancestor_idx < ancestor_count; + ancestor_idx -= 1) + { + RD_PanelNode *ancestor = ancestors[ancestor_idx]; + RD_PanelNode *parent = ancestor->parent; + if(parent != &rd_nil_panel_node) + { + parent_rect = rd_target_rect_from_panel_node_child(parent_rect, parent, ancestor); + } + } + + // rjf: calculate final rect + Rng2F32 rect = rd_target_rect_from_panel_node_child(parent_rect, panel->parent, panel); + scratch_end(scratch); + return rect; } -internal void -rd_entity_change_parent(RD_Entity *entity, RD_Entity *old_parent, RD_Entity *new_parent, RD_Entity *prev_child) +internal B32 +rd_cfg_is_project_filtered(RD_Cfg *cfg) { - Assert(entity->parent == old_parent); - Assert(prev_child->parent == old_parent || rd_entity_is_nil(prev_child)); - if(prev_child != entity) + RD_Cfg *project = rd_cfg_child_from_string(cfg, str8_lit("project")); + B32 result = (project != &rd_nil_cfg && !path_match_normalized(rd_state->project_path, project->first->string)); + return result; +} + +internal RD_KeyMapNodePtrList +rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string) +{ + RD_KeyMapNodePtrList list = {0}; { - // rjf: fix up links - if(!rd_entity_is_nil(old_parent)) + U64 hash = d_hash_from_string(string); + U64 slot_idx = hash%rd_state->key_map->name_slots_count; + for(RD_KeyMapNode *n = rd_state->key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next) { - DLLRemove_NPZ(&rd_nil_entity, old_parent->first, old_parent->last, entity, next, prev); + if(str8_match(n->name, string, 0)) + { + RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1); + ptr->v = n; + SLLQueuePush(list.first, list.last, ptr); + list.count += 1; + } } - if(!rd_entity_is_nil(new_parent)) + } + return list; +} + +internal RD_KeyMapNodePtrList +rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding) +{ + RD_KeyMapNodePtrList list = {0}; + { + U64 hash = d_hash_from_string(str8_struct(&binding)); + U64 slot_idx = hash%rd_state->key_map->binding_slots_count; + for(RD_KeyMapNode *n = rd_state->key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next) { - DLLInsert_NPZ(&rd_nil_entity, new_parent->first, new_parent->last, prev_child, entity, next, prev); + if(MemoryMatchStruct(&binding, &n->binding)) + { + RD_KeyMapNodePtr *ptr = push_array(arena, RD_KeyMapNodePtr, 1); + ptr->v = n; + SLLQueuePush(list.first, list.last, ptr); + list.count += 1; + } } - entity->parent = new_parent; - - // rjf: notify - rd_state->kind_alloc_gens[entity->kind] += 1; } + return list; } -internal RD_Entity * -rd_entity_child_from_kind_or_alloc(RD_Entity *entity, RD_EntityKind kind) +internal Vec4F32 +rd_hsva_from_cfg(RD_Cfg *cfg) { - RD_Entity *child = rd_entity_child_from_kind(entity, kind); - if(rd_entity_is_nil(child)) + Vec4F32 hsva = {0}; + RD_Cfg *hsva_root = rd_cfg_child_from_string(cfg, str8_lit("hsva")); + RD_Cfg *h = hsva_root->first; + RD_Cfg *s = h->next; + RD_Cfg *v = s->next; + RD_Cfg *a = v->next; + hsva.x = (F32)f64_from_str8(h->string); + hsva.y = (F32)f64_from_str8(s->string); + hsva.z = (F32)f64_from_str8(v->string); + hsva.w = (F32)f64_from_str8(a->string); + return hsva; +} + +internal Vec4F32 +rd_color_from_cfg(RD_Cfg *cfg) +{ + Vec4F32 hsva = rd_hsva_from_cfg(cfg); + Vec4F32 rgba = linear_from_srgba(rgba_from_hsva(hsva)); + return rgba; +} + +internal B32 +rd_disabled_from_cfg(RD_Cfg *cfg) +{ + MD_Node *child_schema = &md_nil_node; + MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { - child = rd_entity_alloc(entity, kind); + child_schema = md_child_from_string(n->v, str8_lit("enabled"), 0); } - return child; -} - -//- rjf: entity simple equipment - -internal void -rd_entity_equip_txt_pt(RD_Entity *entity, TxtPt point) -{ - rd_require_entity_nonnil(entity, return); - entity->text_point = point; - entity->flags |= RD_EntityFlag_HasTextPoint; -} - -internal void -rd_entity_equip_disabled(RD_Entity *entity, B32 value) -{ - rd_require_entity_nonnil(entity, return); - entity->disabled = value; -} - -internal void -rd_entity_equip_u64(RD_Entity *entity, U64 u64) -{ - rd_require_entity_nonnil(entity, return); - entity->u64 = u64; - entity->flags |= RD_EntityFlag_HasU64; -} - -internal void -rd_entity_equip_color_rgba(RD_Entity *entity, Vec4F32 rgba) -{ - rd_require_entity_nonnil(entity, return); - Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); - Vec3F32 hsv = hsv_from_rgb(rgb); - Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); - rd_entity_equip_color_hsva(entity, hsva); -} - -internal void -rd_entity_equip_color_hsva(RD_Entity *entity, Vec4F32 hsva) -{ - rd_require_entity_nonnil(entity, return); - entity->color_hsva = hsva; - entity->flags |= RD_EntityFlag_HasColor; -} - -internal void -rd_entity_equip_cfg_src(RD_Entity *entity, RD_CfgSrc cfg_src) -{ - rd_require_entity_nonnil(entity, return); - entity->cfg_src = cfg_src; -} - -internal void -rd_entity_equip_timestamp(RD_Entity *entity, U64 timestamp) -{ - rd_require_entity_nonnil(entity, return); - entity->timestamp = timestamp; -} - -//- rjf: control layer correllation equipment - -internal void -rd_entity_equip_vaddr(RD_Entity *entity, U64 vaddr) -{ - rd_require_entity_nonnil(entity, return); - entity->vaddr = vaddr; - entity->flags |= RD_EntityFlag_HasVAddr; -} - -//- rjf: name equipment - -internal void -rd_entity_equip_name(RD_Entity *entity, String8 name) -{ - rd_require_entity_nonnil(entity, return); - if(entity->string.size != 0) + MD_Node *default_tag = md_tag_from_string(child_schema, str8_lit("default"), 0); + String8 value_string = rd_cfg_child_from_string(cfg, str8_lit("enabled"))->first->string; + if(value_string.size == 0) { - rd_name_release(entity->string); + value_string = default_tag->first->string; } + B32 is_enabled = !!e_value_from_string(value_string).u64; + B32 is_disabled = !is_enabled; + if(value_string.size == 0) + { + is_disabled = 0; + } + return is_disabled; +} + +internal RD_Location +rd_location_from_cfg(RD_Cfg *cfg) +{ + RD_Location dst_loc = {0}; + { + RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); + RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); + if(src_loc != &rd_nil_cfg) + { + String8TxtPtPair loc_description = str8_txt_pt_pair_from_string(src_loc->first->string); + dst_loc.file_path = loc_description.string; + dst_loc.pt = loc_description.pt; + } + else if(addr_loc != &rd_nil_cfg) + { + dst_loc.expr = addr_loc->first->string; + } + } + return dst_loc; +} + +internal String8 +rd_label_from_cfg(RD_Cfg *cfg) +{ + RD_Cfg *label_root = rd_cfg_child_from_string(cfg, str8_lit("label")); + String8 result = label_root->first->string; + return result; +} + +internal String8 +rd_expr_from_cfg(RD_Cfg *cfg) +{ + RD_Cfg *expr_root = rd_cfg_child_from_string(cfg, str8_lit("expression")); + String8 result = expr_root->first->string; + return result; +} + +internal String8 +rd_path_from_cfg(RD_Cfg *cfg) +{ + RD_Cfg *root = rd_cfg_child_from_string(cfg, str8_lit("path")); + String8 result = root->first->string; + return result; +} + +internal D_Target +rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) +{ + D_Target target = {0}; + target.exe = rd_cfg_child_from_string(cfg, str8_lit("executable"))->first->string; + target.args = rd_cfg_child_from_string(cfg, str8_lit("arguments"))->first->string; + target.working_directory = rd_cfg_child_from_string(cfg, str8_lit("working_directory"))->first->string; + target.custom_entry_point_name = rd_cfg_child_from_string(cfg, str8_lit("entry_point"))->first->string; + target.stdout_path = rd_cfg_child_from_string(cfg, str8_lit("stdout_path"))->first->string; + target.stderr_path = rd_cfg_child_from_string(cfg, str8_lit("stderr_path"))->first->string; + target.stdin_path = rd_cfg_child_from_string(cfg, str8_lit("stdin_path"))->first->string; + target.debug_subprocesses = (rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses")) != &rd_nil_cfg); + for(RD_Cfg *child = cfg->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("environment"), 0)) + { + str8_list_push(arena, &target.env, child->first->string); + } + } + return target; +} + +internal MD_NodePtrList +rd_schemas_from_name(String8 name) +{ + MD_NodePtrList schemas = {0}; + for EachElement(idx, rd_name_schema_info_table) + { + if(str8_match(name, rd_name_schema_info_table[idx].name, 0)) + { + schemas = rd_state->schemas[idx]; + break; + } + } + return schemas; +} + +internal String8 +rd_default_setting_from_names(String8 schema_name, String8 setting_name) +{ + String8 result = {0}; + { + MD_Node *setting_schema = &md_nil_node; + MD_NodePtrList schemas = rd_schemas_from_name(schema_name); + for(MD_NodePtrNode *n = schemas.first; n != 0 && setting_schema == &md_nil_node; n = n->next) + { + setting_schema = md_child_from_string(n->v, setting_name, 0); + } + if(setting_schema != &md_nil_node) + { + MD_Node *default_tag = md_tag_from_string(setting_schema, str8_lit("default"), 0); + if(default_tag != &md_nil_node) + { + result = default_tag->first->string; + } + } + } + return result; +} + +internal String8 +rd_setting_from_name(String8 name) +{ + String8 result = {0}; if(name.size != 0) { - entity->string = rd_name_alloc(name); - } - else - { - entity->string = str8_zero(); + Temp scratch = scratch_begin(0, 0); + + // rjf: find most-granular config scopes to begin looking for the setting + typedef struct CfgSeedTask CfgSeedTask; + struct CfgSeedTask + { + CfgSeedTask *next; + RD_Cfg *cfg; + B32 allow_bucket_chains; + }; + RD_Cfg *view_cfg = rd_cfg_from_id(rd_regs()->view); + if(view_cfg == &rd_nil_cfg) + { + view_cfg = rd_cfg_from_id(rd_regs()->tab); + } + CfgSeedTask panel_task = {0, &rd_nil_cfg, 1}; + if(panel_task.cfg == &rd_nil_cfg) { panel_task.cfg = rd_cfg_from_id(rd_regs()->panel); } + if(panel_task.cfg == &rd_nil_cfg) { panel_task.cfg = rd_cfg_from_id(rd_regs()->window); } + CfgSeedTask view_task = {&panel_task, view_cfg, 1}; + CfgSeedTask *first_task = &view_task; + CfgSeedTask *last_task = &panel_task; + + // rjf: for each task, look for the setting, follow parent chain upwards + RD_Cfg *setting = &rd_nil_cfg; + for(CfgSeedTask *t = first_task; t != 0; t = t->next) + { + for(RD_Cfg *cfg = t->cfg; cfg != &rd_nil_cfg; cfg = cfg->parent) + { + setting = rd_cfg_child_from_string(cfg, name); + if(setting != &rd_nil_cfg) + { + goto break_all; + } + if(cfg->parent == rd_state->root_cfg && t->allow_bucket_chains) + { + String8 next_bucket = {0}; + B32 allow_bucket_chains = 0; + if(str8_match(cfg->string, str8_lit("user"), 0)) + { + next_bucket = str8_lit("project"); + } + else if(str8_match(cfg->string, str8_lit("project"), 0)) + { + next_bucket = str8_lit("user"); + } + else + { + allow_bucket_chains = 1; + next_bucket = str8_lit("user"); + } + if(next_bucket.size != 0) + { + CfgSeedTask *task = push_array(scratch.arena, CfgSeedTask, 1); + SLLQueuePush(first_task, last_task, task); + task->cfg = rd_cfg_child_from_string(rd_state->root_cfg, next_bucket); + task->allow_bucket_chains = allow_bucket_chains; + } + } + } + } + break_all:; + + // rjf: return resultant child string stored under this key + result = setting->first->string; + + // rjf: no result -> look for default in schemas + if(result.size == 0) + { + for(CfgSeedTask *t = first_task; t != 0; t = t->next) + { + for(RD_Cfg *cfg = t->cfg; cfg != &rd_nil_cfg; cfg = cfg->parent) + { + result = rd_default_setting_from_names(cfg->string, name); + if(result.size != 0) + { + goto break_all2; + } + } + } + break_all2:; + } + + scratch_end(scratch); } + return result; } -//- rjf: file path map override lookups +internal B32 +rd_setting_b32_from_name(String8 name) +{ + B32 result = 0; + String8 value = rd_setting_from_name(name); + if(value.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 expr = push_str8f(scratch.arena, "raw((bool)(%S))", value); + E_Eval eval = e_eval_from_string(expr); + result = !!e_value_eval_from_eval(eval).value.u64; + scratch_end(scratch); + } + return result; +} + +internal U64 +rd_setting_u64_from_name(String8 name) +{ + U64 result = 0; + String8 value = rd_setting_from_name(name); + if(value.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 expr = push_str8f(scratch.arena, "raw((uint64)(%S))", value); + E_Eval eval = e_eval_from_string(expr); + result = e_value_eval_from_eval(eval).value.u64; + scratch_end(scratch); + } + return result; +} + +internal F32 +rd_setting_f32_from_name(String8 name) +{ + F32 result = 0.f; + String8 value = rd_setting_from_name(name); + if(value.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 expr = push_str8f(scratch.arena, "raw((float32)(%S))", value); + E_Eval eval = e_eval_from_string(expr); + result = e_value_eval_from_eval(eval).value.f32; + scratch_end(scratch); + } + return result; +} + +internal RD_Cfg * +rd_immediate_cfg_from_key(String8 string) +{ + RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); + RD_Cfg *immediate = &rd_nil_cfg; + RD_Cfg *cfg = &rd_nil_cfg; + for(RD_Cfg *child = transient->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("immediate"), 0)) + { + cfg = rd_cfg_child_from_string(child, string); + if(cfg != &rd_nil_cfg) + { + immediate = child; + break; + } + } + } + if(cfg == &rd_nil_cfg) + { + immediate = rd_cfg_new(transient, str8_lit("immediate")); + cfg = rd_cfg_new(immediate, string); + } + rd_cfg_child_from_string_or_alloc(immediate, str8_lit("hot")); + return cfg; +} + +internal RD_Cfg * +rd_immediate_cfg_from_keyf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 key = push_str8fv(scratch.arena, fmt, args); + RD_Cfg *result = rd_immediate_cfg_from_key(key); + va_end(args); + scratch_end(scratch); + return result; +} internal String8 rd_mapped_from_file_path(Arena *arena, String8 file_path) { Temp scratch = scratch_begin(&arena, 1); - String8 result = file_path; if(file_path.size != 0) { - String8 file_path__normalized = path_normalized_from_string(scratch.arena, file_path); - String8List file_path_parts = str8_split_path(scratch.arena, file_path__normalized); - RD_EntityList maps = rd_query_cached_entity_list_with_kind(RD_EntityKind_FilePathMap); + String8List file_path_parts = str8_split_path(scratch.arena, file_path); + RD_CfgList maps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); String8 best_map_dst = {0}; U64 best_map_match_length = max_U64; String8Node *best_map_remaining_suffix_first = 0; - for(RD_EntityNode *n = maps.first; n != 0; n = n->next) + for(RD_CfgNode *n = maps.first; n != 0; n = n->next) { - String8 map_src = rd_entity_child_from_kind(n->entity, RD_EntityKind_Source)->string; - String8 map_src__normalized = path_normalized_from_string(scratch.arena, map_src); - String8List map_src_parts = str8_split_path(scratch.arena, map_src__normalized); + String8 map_src = rd_cfg_child_from_string(n->v, str8_lit("source"))->first->string; + String8List map_src_parts = str8_split_path(scratch.arena, map_src); B32 matches = 1; U64 match_length = 0; String8Node *file_path_part_n = file_path_parts.first; @@ -1639,26 +1515,22 @@ rd_mapped_from_file_path(Arena *arena, String8 file_path) if(matches && match_length < best_map_match_length) { best_map_match_length = match_length; - best_map_dst = rd_entity_child_from_kind(n->entity, RD_EntityKind_Dest)->string; + best_map_dst = rd_cfg_child_from_string(n->v, str8_lit("dest"))->first->string; best_map_remaining_suffix_first = file_path_part_n; } } if(best_map_dst.size != 0) { - String8 best_map_dst__normalized = path_normalized_from_string(scratch.arena, best_map_dst); - String8List best_map_dst_parts = str8_split_path(scratch.arena, best_map_dst__normalized); + String8List best_map_dst_parts = str8_split_path(scratch.arena, best_map_dst); for(String8Node *n = best_map_remaining_suffix_first; n != 0; n = n->next) { str8_list_push(scratch.arena, &best_map_dst_parts, n->string); } StringJoin join = {.sep = str8_lit("/")}; - result = str8_list_join(arena, &best_map_dst_parts, &join); - } - else - { - result = path_normalized_from_string(arena, result); + file_path = str8_list_join(scratch.arena, &best_map_dst_parts, &join); } } + String8 result = push_str8_copy(arena, file_path); scratch_end(scratch); return result; } @@ -1684,17 +1556,17 @@ rd_possible_overrides_from_file_path(Arena *arena, String8 file_path) PathStyle pth_style = PathStyle_Relative; String8List pth_parts = path_normalized_list_from_string(scratch.arena, file_path, &pth_style); { - RD_EntityList links = rd_query_cached_entity_list_with_kind(RD_EntityKind_FilePathMap); - for(RD_EntityNode *n = links.first; n != 0; n = n->next) + RD_CfgList links = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); + for(RD_CfgNode *n = links.first; n != 0; n = n->next) { //- rjf: unpack link - RD_Entity *link = n->entity; - RD_Entity *src = rd_entity_child_from_kind(link, RD_EntityKind_Source); - RD_Entity *dst = rd_entity_child_from_kind(link, RD_EntityKind_Dest); + RD_Cfg *link = n->v; + RD_Cfg *src = rd_cfg_child_from_string(link, str8_lit("source")); + RD_Cfg *dst = rd_cfg_child_from_string(link, str8_lit("dest")); PathStyle src_style = PathStyle_Relative; PathStyle dst_style = PathStyle_Relative; - String8List src_parts = path_normalized_list_from_string(scratch.arena, src->string, &src_style); - String8List dst_parts = path_normalized_list_from_string(scratch.arena, dst->string, &dst_style); + String8List src_parts = path_normalized_list_from_string(scratch.arena, src->first->string, &src_style); + String8List dst_parts = path_normalized_list_from_string(scratch.arena, dst->first->string, &dst_style); //- rjf: determine if this link can possibly redirect to the target file path B32 dst_redirects_to_pth = 0; @@ -1732,287 +1604,21 @@ rd_possible_overrides_from_file_path(Arena *arena, String8 file_path) } } } + scratch_end(scratch); return result; } -//- rjf: top-level state queries - -internal RD_Entity * -rd_entity_root(void) -{ - return rd_state->entities_root; -} - -internal RD_EntityList -rd_push_entity_list_with_kind(Arena *arena, RD_EntityKind kind) -{ - ProfBeginFunction(); - RD_EntityList result = {0}; - for(RD_Entity *entity = rd_state->entities_root; - !rd_entity_is_nil(entity); - entity = rd_entity_rec_depth_first_pre(entity, &rd_nil_entity).next) - { - if(entity->kind == kind && !(entity->flags & RD_EntityFlag_MarkedForDeletion)) - { - rd_entity_list_push(arena, &result, entity); - } - } - ProfEnd(); - return result; -} - -internal RD_Entity * -rd_entity_from_id(RD_EntityID id) -{ - RD_Entity *result = &rd_nil_entity; - for(RD_Entity *e = rd_entity_root(); - !rd_entity_is_nil(e); - e = rd_entity_rec_depth_first_pre(e, &rd_nil_entity).next) - { - if(e->id == id) - { - result = e; - break; - } - } - return result; -} - -internal RD_Entity * -rd_entity_from_name_and_kind(String8 string, RD_EntityKind kind) -{ - RD_Entity *result = &rd_nil_entity; - RD_EntityList all_of_this_kind = rd_query_cached_entity_list_with_kind(kind); - for(RD_EntityNode *n = all_of_this_kind.first; n != 0; n = n->next) - { - if(str8_match(n->entity->string, string, 0)) - { - result = n->entity; - break; - } - } - return result; -} - -//////////////////////////////// -//~ rjf: Frontend Entity Info Extraction - -internal D_Target -rd_d_target_from_entity(RD_Entity *entity) -{ - RD_Entity *src_target_exe = rd_entity_child_from_kind(entity, RD_EntityKind_Executable); - RD_Entity *src_target_args = rd_entity_child_from_kind(entity, RD_EntityKind_Arguments); - RD_Entity *src_target_wdir = rd_entity_child_from_kind(entity, RD_EntityKind_WorkingDirectory); - RD_Entity *src_target_stdo = rd_entity_child_from_kind(entity, RD_EntityKind_StdoutPath); - RD_Entity *src_target_stde = rd_entity_child_from_kind(entity, RD_EntityKind_StderrPath); - RD_Entity *src_target_stdi = rd_entity_child_from_kind(entity, RD_EntityKind_StdinPath); - RD_Entity *src_target_entry = rd_entity_child_from_kind(entity, RD_EntityKind_EntryPoint); - D_Target target = {0}; - target.exe = src_target_exe->string; - target.args = src_target_args->string; - target.working_directory = src_target_wdir->string; - target.custom_entry_point_name = src_target_entry->string; - target.stdout_path = src_target_stdo->string; - target.stderr_path = src_target_stde->string; - target.stdin_path = src_target_stdi->string; - target.debug_subprocesses = entity->debug_subprocesses; - return target; -} - -internal DR_FancyStringList -rd_title_fstrs_from_entity(Arena *arena, RD_Entity *entity, Vec4F32 secondary_color, F32 size) -{ - DR_FancyStringList result = {0}; - RD_Entity *exe = rd_entity_child_from_kind(entity, RD_EntityKind_Executable); - RD_Entity *args = rd_entity_child_from_kind(entity, RD_EntityKind_Arguments); - RD_Entity *loc = rd_entity_child_from_kind(entity, RD_EntityKind_Location); - RD_Entity *cnd = rd_entity_child_from_kind(entity, RD_EntityKind_Condition); - RD_Entity *src = rd_entity_child_from_kind(entity, RD_EntityKind_Source); - RD_Entity *dst = rd_entity_child_from_kind(entity, RD_EntityKind_Dest); - RD_IconKind icon_kind = rd_entity_kind_icon_kind_table[entity->kind]; - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Text); - if(icon_kind != RD_IconKind_Null) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Icons), size, secondary_color, rd_icon_kind_text_table[icon_kind]); - } - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); - if(entity->kind == RD_EntityKind_Target && entity->cfg_src == RD_CfgSrc_CommandLine) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Icons), size, rd_rgba_from_theme_color(RD_ThemeColor_TextNegative), rd_icon_kind_text_table[RD_IconKind_Info]); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); - } - String8 name = entity->string; - B32 name_is_code = 1; - if(rd_entity_kind_flags_table[entity->kind] & RD_EntityKindFlag_NameIsPath) - { - name_is_code = 0; - } - String8 location = {0}; - B32 location_is_code = 0; - String8 exe_name = str8_skip_last_slash(exe->string); - String8 args_string = args->string; - String8 cnd_string = cnd->string; - if(!rd_entity_is_nil(loc)) - { - if(loc->string.size != 0 && loc->flags & RD_EntityFlag_HasTextPoint) - { - location = push_str8f(arena, "%S:%I64d:%I64d", loc->string, loc->text_point.line, loc->text_point.column); - location_is_code = 0; - } - else if(loc->string.size != 0) - { - location = loc->string; - location_is_code = 1; - } - else if(loc->flags & RD_EntityFlag_HasVAddr) - { - location = push_str8f(arena, "0x%I64x", loc->vaddr); - location_is_code = 1; - } - } - B32 extra = 0; - F32 size_extrafied = size; - Vec4F32 color_extrafied = color; - if(name.size != 0) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), size, color, name); - extra = 1; - size_extrafied = size*0.95f; - color_extrafied = secondary_color; - } - if(location.size != 0) - { - if(extra) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - } - if(location_is_code) - { - DR_FancyStringList loc_fstrs = {0}; - RD_Font(RD_FontSlot_Code) - loc_fstrs = rd_fancy_string_list_from_code_string(arena, 1.f, 0, color_extrafied, location); - dr_fancy_string_list_concat_in_place(&result, &loc_fstrs); - } - else - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size_extrafied, color_extrafied, location); - } - extra = 1; - size_extrafied = size*0.95f; - color_extrafied = secondary_color; - } - if(exe_name.size != 0) - { - if(extra) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - } - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size_extrafied, color_extrafied, exe_name); - extra = 1; - size_extrafied = size*0.95f; - color_extrafied = secondary_color; - } - if(args_string.size != 0) - { - if(extra) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - } - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size_extrafied, color_extrafied, args_string); - extra = 1; - size_extrafied = size*0.95f; - color_extrafied = secondary_color; - } - if(cnd_string.size != 0) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, color_extrafied, str8_lit(" if ")); - RD_Font(RD_FontSlot_Code) UI_FontSize(size_extrafied) - { - DR_FancyStringList cnd_fstrs = rd_fancy_string_list_from_code_string(arena, 1.f, 0.f, color_extrafied, cnd_string); - dr_fancy_string_list_concat_in_place(&result, &cnd_fstrs); - } - } - if(entity->kind == RD_EntityKind_FilePathMap) - { - String8 src_string = src->string; - Vec4F32 src_color = color; - String8 dst_string = dst->string; - Vec4F32 dst_color = color; - if(src_string.size == 0) - { - src_string = str8_lit("(source path)"); - src_color = secondary_color; - } - if(dst_string.size == 0) - { - dst_string = str8_lit("(destination path)"); - dst_color = secondary_color; - } - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size, src_color, src_string); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Icons), size, secondary_color, rd_icon_kind_text_table[RD_IconKind_RightArrow]); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size, dst_color, dst_string); - } - if(entity->kind == RD_EntityKind_AutoViewRule) - { - String8 src_string = src->string; - Vec4F32 src_color = color; - String8 dst_string = dst->string; - Vec4F32 dst_color = color; - DR_FancyStringList src_fstrs = {0}; - DR_FancyStringList dst_fstrs = {0}; - if(src_string.size == 0) - { - src_string = str8_lit("(type)"); - src_color = secondary_color; - dr_fancy_string_list_push_new(arena, &src_fstrs, rd_font_from_slot(RD_FontSlot_Main), size, src_color, src_string); - } - else RD_Font(RD_FontSlot_Code) - { - src_fstrs = rd_fancy_string_list_from_code_string(arena, 1.f, 0, src_color, src_string); - } - if(dst_string.size == 0) - { - dst_string = str8_lit("(view rule)"); - dst_color = secondary_color; - dr_fancy_string_list_push_new(arena, &dst_fstrs, rd_font_from_slot(RD_FontSlot_Main), size, dst_color, dst_string); - } - else RD_Font(RD_FontSlot_Code) - { - dst_fstrs = rd_fancy_string_list_from_code_string(arena, 1.f, 0, dst_color, dst_string); - } - dr_fancy_string_list_concat_in_place(&result, &src_fstrs); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Icons), size, secondary_color, rd_icon_kind_text_table[RD_IconKind_RightArrow]); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&result, &dst_fstrs); - } - if((entity->kind == RD_EntityKind_Target || entity->kind == RD_EntityKind_Breakpoint) && entity->disabled) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size*0.95f, secondary_color, str8_lit("(Disabled)")); - } - if(entity->kind == RD_EntityKind_Breakpoint) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, v4f32(0, 0, 0, 0), str8_lit(" ")); - String8 string = push_str8f(arena, "(%I64u hit%s)", entity->u64, entity->u64 == 1 ? "" : "s"); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size_extrafied, secondary_color, string); - } - return result; -} - //////////////////////////////// //~ rjf: Control Entity Info Extraction internal Vec4F32 -rd_rgba_from_ctrl_entity(CTRL_Entity *entity) +rd_color_from_ctrl_entity(CTRL_Entity *entity) { - Vec4F32 result = rd_rgba_from_theme_color(RD_ThemeColor_Text); + Vec4F32 result = {0}; if(entity->rgba != 0) { - result = rgba_from_u32(entity->rgba); + result = linear_from_srgba(rgba_from_u32(entity->rgba)); } if(entity->rgba == 0) switch(entity->kind) { @@ -2023,11 +1629,11 @@ rd_rgba_from_ctrl_entity(CTRL_Entity *entity) CTRL_Entity *main_thread = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Thread); if(main_thread != entity) { - result = rd_rgba_from_theme_color(RD_ThemeColor_Thread1); + result = ui_color_from_name(str8_lit("thread_1")); } else { - result = rd_rgba_from_theme_color(RD_ThemeColor_Thread0); + result = ui_color_from_name(str8_lit("thread_0")); } }break; } @@ -2049,134 +1655,28 @@ rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity) return string; } -internal DR_FancyStringList -rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, Vec4F32 secondary_color, F32 size, B32 include_extras) -{ - DR_FancyStringList result = {0}; - - //- rjf: unpack entity info - F32 extras_size = size*0.95f; - Vec4F32 color = rd_rgba_from_ctrl_entity(entity); - String8 name = rd_name_from_ctrl_entity(arena, entity); - RD_IconKind icon_kind = RD_IconKind_Null; - B32 name_is_code = 0; - switch(entity->kind) - { - default:{}break; - case CTRL_EntityKind_Machine: {icon_kind = RD_IconKind_Machine;}break; - case CTRL_EntityKind_Process: {icon_kind = RD_IconKind_Threads;}break; - case CTRL_EntityKind_Thread: {icon_kind = RD_IconKind_Thread; name_is_code = 1;}break; - case CTRL_EntityKind_Module: {icon_kind = RD_IconKind_Module;}break; - } - - //- rjf: push icon - if(icon_kind != RD_IconKind_Null) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Icons), size, secondary_color, rd_icon_kind_text_table[icon_kind]); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); - } - - //- rjf: push containing process prefix - if(entity->kind == CTRL_EntityKind_Thread || - entity->kind == CTRL_EntityKind_Module) - { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); - if(processes.count > 1) - { - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); - String8 process_name = rd_name_from_ctrl_entity(arena, process); - Vec4F32 process_color = rd_rgba_from_ctrl_entity(process); - if(process_name.size != 0) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), size, process_color, process_name); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" / ")); - } - } - } - - //- rjf: push name - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), size, color, name); - - //- rjf: threads get callstack extras - if(entity->kind == CTRL_EntityKind_Thread && include_extras) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); - Arch arch = entity->arch; - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity); - for(U64 idx = 0, limit = 6; idx < unwind.frames.count && idx < limit; idx += 1) - { - CTRL_UnwindFrame *f = &unwind.frames.v[unwind.frames.count - 1 - idx]; - U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); - if(rdi != &di_rdi_parsed_nil) - { - RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); - name = push_str8_copy(arena, name); - if(name.size != 0) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), extras_size, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - if(idx+1 < unwind.frames.count) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), extras_size, secondary_color, str8_lit(" > ")); - if(idx+1 == limit) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), extras_size, secondary_color, str8_lit("...")); - } - } - } - } - } - di_scope_close(di_scope); - } - - //- rjf: modules get debug info status extras - if(entity->kind == CTRL_EntityKind_Module && include_extras) - { - DI_Scope *di_scope = di_scope_open(); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); - if(rdi->raw_data_size == 0) - { - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Code), size, secondary_color, str8_lit(" ")); - dr_fancy_string_list_push_new(arena, &result, rd_font_from_slot(RD_FontSlot_Main), extras_size, secondary_color, str8_lit("(Symbols not found)")); - } - di_scope_close(di_scope); - } - - return result; -} - //////////////////////////////// //~ rjf: Evaluation Spaces -//- rjf: entity <-> eval space +//- rjf: cfg <-> eval space -internal RD_Entity * -rd_entity_from_eval_space(E_Space space) +internal RD_Cfg * +rd_cfg_from_eval_space(E_Space space) { - RD_Entity *entity = &rd_nil_entity; - if(space.kind == RD_EvalSpaceKind_MetaEntity) + RD_Cfg *cfg = &rd_nil_cfg; + if(space.kind == RD_EvalSpaceKind_MetaCfg) { - RD_Handle handle = {space.u64s[0], space.u64s[1]}; - entity = rd_entity_from_handle(handle); + RD_CfgID id = space.u64s[0]; + cfg = rd_cfg_from_id(id); } - return entity; + return cfg; } internal E_Space -rd_eval_space_from_entity(RD_Entity *entity) +rd_eval_space_from_cfg(RD_Cfg *cfg) { - E_Space space = e_space_make(RD_EvalSpaceKind_MetaEntity); - RD_Handle handle = rd_handle_from_entity(entity); - space.u64s[0] = handle.u64[0]; - space.u64s[1] = handle.u64[1]; + E_Space space = e_space_make(RD_EvalSpaceKind_MetaCfg); + space.u64s[0] = cfg->id; return space; } @@ -2187,12 +1687,13 @@ rd_ctrl_entity_from_eval_space(E_Space space) { CTRL_Entity *entity = &ctrl_entity_nil; if(space.kind == RD_EvalSpaceKind_CtrlEntity || - space.kind == RD_EvalSpaceKind_MetaCtrlEntity) + space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + space.kind == RD_EvalSpaceKind_MetaUnattachedProcess) { CTRL_Handle handle; handle.machine_id = space.u64s[0]; handle.dmn_handle.u64[0] = space.u64s[1]; - entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, handle); + entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, handle); } return entity; } @@ -2206,134 +1707,49 @@ rd_eval_space_from_ctrl_entity(CTRL_Entity *entity, E_SpaceKind kind) return space; } -//- rjf: entity -> meta eval +//- rjf: command name <-> eval space -internal CTRL_MetaEval * -rd_ctrl_meta_eval_from_entity(Arena *arena, RD_Entity *entity) +internal String8 +rd_cmd_name_from_eval(E_Eval eval) { - ProfBeginFunction(); - CTRL_MetaEval *meval = push_array(arena, CTRL_MetaEval, 1); - RD_Entity *exe = rd_entity_child_from_kind(entity, RD_EntityKind_Executable); - RD_Entity *args= rd_entity_child_from_kind(entity, RD_EntityKind_Arguments); - RD_Entity *wdir= rd_entity_child_from_kind(entity, RD_EntityKind_WorkingDirectory); - RD_Entity *entr= rd_entity_child_from_kind(entity, RD_EntityKind_EntryPoint); - RD_Entity *stdo= rd_entity_child_from_kind(entity, RD_EntityKind_StdoutPath); - RD_Entity *stde= rd_entity_child_from_kind(entity, RD_EntityKind_StderrPath); - RD_Entity *stdi= rd_entity_child_from_kind(entity, RD_EntityKind_StdinPath); - RD_Entity *loc = rd_entity_child_from_kind(entity, RD_EntityKind_Location); - RD_Entity *cnd = rd_entity_child_from_kind(entity, RD_EntityKind_Condition); - RD_Entity *src = rd_entity_child_from_kind(entity, RD_EntityKind_Source); - RD_Entity *dst = rd_entity_child_from_kind(entity, RD_EntityKind_Dest); - String8 label_string = push_str8_copy(arena, entity->string); - String8 src_loc_string = {0}; - String8 vaddr_loc_string = {0}; - String8 function_loc_string = {0}; - if(loc->flags & RD_EntityFlag_HasTextPoint) + String8 result = {0}; + if(eval.space.kind == RD_EvalSpaceKind_MetaCmd) { - src_loc_string = push_str8f(arena, "%S:%I64u:%I64u", loc->string, loc->text_point.line, loc->text_point.column); + result = e_string_from_id(eval.value.u64); } - else if(loc->flags & RD_EntityFlag_HasVAddr) - { - vaddr_loc_string = push_str8f(arena, "0x%I64x", loc->vaddr); - } - else if(loc->string.size != 0) - { - function_loc_string = push_str8_copy(arena, loc->string); - } - String8 cnd_string = push_str8_copy(arena, cnd->string); - meval->enabled = !entity->disabled; - meval->hit_count = entity->u64; - meval->color = u32_from_rgba(rd_rgba_from_entity(entity)); - meval->label = label_string; - meval->exe = exe->string; - meval->args = args->string; - meval->working_directory = wdir->string; - meval->entry_point = entr->string; - meval->stdout_path = stdo->string; - meval->stderr_path = stde->string; - meval->stdin_path = stdi->string; - meval->source_location = src_loc_string; - meval->address_location = vaddr_loc_string; - meval->function_location = function_loc_string; - meval->condition = cnd_string; - meval->debug_subprocesses.b32 = entity->debug_subprocesses; - switch(entity->kind) - { - default:{}break; - case RD_EntityKind_FilePathMap: - { - meval->source_path = src->string; - meval->destination_path = dst->string; - }break; - case RD_EntityKind_AutoViewRule: - { - meval->type = src->string; - meval->view_rule = dst->string; - }break; - } - ProfEnd(); - return meval; -} - -internal CTRL_MetaEval * -rd_ctrl_meta_eval_from_ctrl_entity(Arena *arena, CTRL_Entity *entity) -{ - ProfBeginFunction(); - CTRL_MetaEval *meval = push_array(arena, CTRL_MetaEval, 1); - meval->frozen = entity->is_frozen; - meval->vaddr_range = entity->vaddr_range; - meval->color = entity->rgba; - meval->label = entity->string; - meval->id = entity->id; - if(entity->kind == CTRL_EntityKind_Thread) - { - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(entity); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(arena, di_scope, process, &base_unwind); - meval->callstack.count = rich_unwind.total_frame_count; - meval->callstack.v = push_array(arena, CTRL_MetaEvalFrame, meval->callstack.count); - U64 idx = 0; - for(U64 base_idx = 0; base_idx < rich_unwind.concrete_frame_count; base_idx += 1) - { - U64 inline_idx = 0; - for(CTRL_CallStackInlineFrame *f = rich_unwind.frames[base_idx].first_inline_frame; f != 0; f = f->next, inline_idx += 1) - { - meval->callstack.v[idx].vaddr = regs_rip_from_arch_block(entity->arch, rich_unwind.frames[base_idx].regs); - meval->callstack.v[idx].inline_depth = inline_idx + 1; - idx += 1; - } - meval->callstack.v[idx].vaddr = regs_rip_from_arch_block(entity->arch, rich_unwind.frames[base_idx].regs); - idx += 1; - } - di_scope_close(di_scope); - } - if(entity->kind == CTRL_EntityKind_Module) - { - DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); - meval->label = str8_skip_last_slash(entity->string); - meval->exe = path_normalized_from_string(arena, entity->string); - meval->dbg = path_normalized_from_string(arena, dbgi_key.path); - } - ProfEnd(); - return meval; + return result; } //- rjf: eval space reads/writes +internal U64 +rd_eval_space_gen(void *u, E_Space space) +{ + U64 result = 0; + switch(space.kind) + { + case RD_EvalSpaceKind_MetaCfg: + case RD_EvalSpaceKind_MetaQuery: + { + result = rd_state->cfg_change_gen; + }break; + } + return result; +} + internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) { Temp scratch = scratch_begin(0, 0); B32 result = 0; - CTRL_MetaEval *meval_read = 0; - Rng1U64 meval_legal_range = {0}; switch(space.kind) { - //- rjf: filesystem reads - case E_SpaceKind_FileSystem: + //- rjf: reads from hash store key + case E_SpaceKind_HashStoreKey: { - U128 key = space.u128; + HS_Root root = {space.u64_0}; + HS_ID id = {space.u128}; + HS_Key key = hs_key_make(root, id); U128 hash = hs_hash_from_key(key, 0); HS_Scope *scope = hs_scope_open(); { @@ -2349,6 +1765,39 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) hs_scope_close(scope); }break; + //- rjf: file reads + case E_SpaceKind_File: + { + // rjf: unpack space/path + U64 file_path_string_id = space.u64_0; + String8 file_path = e_string_from_id(file_path_string_id); + + // rjf: find containing chunk range + U64 chunk_size = KB(4); + Rng1U64 containing_range = range; + containing_range.min -= containing_range.min%chunk_size; + containing_range.max += chunk_size-1; + containing_range.max -= containing_range.max%chunk_size; + + // rjf: map to hash + HS_Key key = fs_key_from_path_range(file_path, containing_range, 0); + U128 hash = hs_hash_from_key(key, 0); + + // rjf: look up from hash store + HS_Scope *scope = hs_scope_open(); + { + String8 data = hs_data_from_hash(scope, hash); + Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size); + Rng1U64 read_range = intersect_1u64(range, legal_range); + if(read_range.min < read_range.max) + { + result = 1; + MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range)); + } + } + hs_scope_close(scope); + }break; + //- rjf: interior control entity reads (inside process address space or thread register block) case RD_EvalSpaceKind_CtrlEntity: { @@ -2358,24 +1807,22 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) default:{}break; case CTRL_EntityKind_Process: { - Temp scratch = scratch_begin(0, 0); - CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, entity->handle, range, d_state->frame_eval_memread_endt_us); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, entity->handle, range, rd_state->frame_eval_memread_endt_us); String8 data = slice.data; if(data.size == dim_1u64(range)) { result = 1; MemoryCopy(out, data.str, data.size); } - scratch_end(scratch); }break; case CTRL_EntityKind_Thread: { - Temp scratch = scratch_begin(0, 0); - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(entity); - U64 frame_idx = e_interpret_ctx->reg_unwind_count; - if(frame_idx < unwind.frames.count) + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, 1, rd_state->frame_eval_memread_endt_us); + U64 concrete_frame_idx = e_interpret_ctx->reg_unwind_count; + if(concrete_frame_idx < call_stack.concrete_frames_count) { - CTRL_UnwindFrame *f = &unwind.frames.v[frame_idx]; + CTRL_CallStackFrame *f = call_stack.concrete_frames[concrete_frame_idx]; U64 regs_size = regs_block_size_from_arch(e_interpret_ctx->reg_arch); Rng1U64 legal_range = r1u64(0, regs_size); Rng1U64 read_range = intersect_1u64(legal_range, range); @@ -2383,75 +1830,167 @@ rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range) MemoryCopy(out, (U8 *)f->regs + read_range.min, read_size); result = (read_size == dim_1u64(range)); } - scratch_end(scratch); + ctrl_scope_close(ctrl_scope); }break; } }break; - //- rjf: meta reads (metadata about either control entities or debugger state) - case RD_EvalSpaceKind_MetaCtrlEntity: + //- rjf: meta-config reads + case RD_EvalSpaceKind_MetaCfg: { - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); - U64 hash = ctrl_hash_from_handle(entity->handle); - U64 slot_idx = hash%rd_state->ctrl_entity_meval_cache_slots_count; - RD_CtrlEntityMetaEvalCacheSlot *slot = &rd_state->ctrl_entity_meval_cache_slots[slot_idx]; - RD_CtrlEntityMetaEvalCacheNode *node = 0; - for(RD_CtrlEntityMetaEvalCacheNode *n = slot->first; n != 0; n = n->next) + // rjf: unpack cfg + RD_Cfg *root_cfg = rd_cfg_from_eval_space(space); + String8 child_key = e_string_from_id(space.u64s[1]); + RD_Cfg *cfg = root_cfg; + if(child_key.size != 0) { - if(ctrl_handle_match(n->handle, entity->handle)) + cfg = rd_cfg_child_from_string(root_cfg, child_key); + } + + // rjf: determine data to read from, depending on child type in schema + String8 read_data = {0}; + if(child_key.size != 0) + { + MD_NodePtrList schemas = rd_schemas_from_name(root_cfg->string); + MD_Node *expr_child_schema = &md_nil_node; + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { - node = n; - break; + child_schema = md_child_from_string(n->v, child_key, 0); + if(child_schema != &md_nil_node) + { + expr_child_schema = md_child_from_string(n->v, str8_lit("expression"), 0); + } + } + String8 child_type_name = child_schema->first->string; + if(str8_match(child_type_name, str8_lit("path"), 0) || + str8_match(child_type_name, str8_lit("path_pt"), 0) || + str8_match(child_type_name, str8_lit("code_string"), 0) || + str8_match(child_type_name, str8_lit("expr_string"), 0) || + str8_match(child_type_name, str8_lit("string"), 0)) + { + read_data = cfg->first->string; + } + else + { + String8 value_string = cfg->first->string; + if(value_string.size == 0) + { + value_string = md_tag_from_string(child_schema, str8_lit("default"), 0)->first->string; + } + if(value_string.size == 0 && !md_node_is_nil(md_tag_from_string(child_schema, str8_lit("override"), 0))) + { + for(RD_Cfg *parent = root_cfg->parent; parent != &rd_nil_cfg; parent = parent->parent) + { + RD_Cfg *parent_child_w_key = rd_cfg_child_from_string(parent, child_key); + if(parent_child_w_key != &rd_nil_cfg) + { + value_string = parent_child_w_key->first->string; + break; + } + value_string = rd_default_setting_from_names(parent->string, child_key); + if(value_string.size != 0) + { + break; + } + } + } + E_Key parent_key = {0}; + if(expr_child_schema != &md_nil_node && child_schema != expr_child_schema) + { + parent_key = e_key_from_string(rd_cfg_child_from_string(root_cfg, expr_child_schema->string)->first->string); + } + E_ParentKey(parent_key) + { + if(str8_match(child_type_name, str8_lit("bool"), 0)) + { + B32 value = !!e_value_from_stringf("(bool)(%S)", value_string).u64; + read_data = push_str8_copy(scratch.arena, str8_struct(&value)); + } + else if(str8_match(child_type_name, str8_lit("u64"), 0)) + { + U64 value = e_value_from_stringf("(uint64)(%S)", value_string).u64; + read_data = push_str8_copy(scratch.arena, str8_struct(&value)); + } + else if(str8_match(child_type_name, str8_lit("u32"), 0)) + { + U64 value = e_value_from_stringf("(uint32)(%S)", value_string).u64; + read_data = push_str8_copy(scratch.arena, str8_struct(&value)); + } + else if(str8_match(child_type_name, str8_lit("f32"), 0)) + { + F32 value = e_value_from_stringf("(float32)(%S)", value_string).f32; + read_data = push_str8_copy(scratch.arena, str8_struct(&value)); + } + } } } - if(!node) + + // rjf: if no child key? -> just read from this cfg's child string - first 8 bytes -> offset of string (just 8), then string's content + if(child_key.size == 0) { - CTRL_MetaEval *meval = rd_ctrl_meta_eval_from_ctrl_entity(scratch.arena, entity); - String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); - U64 pos_min = arena_pos(rd_frame_arena()); - arena_push(rd_frame_arena(), 0, 64); - CTRL_MetaEval *meval_read = struct_from_serialized(rd_frame_arena(), CTRL_MetaEval, meval_srlzed); - struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); - U64 pos_opl = arena_pos(scratch.arena); - node = push_array(rd_frame_arena(), RD_CtrlEntityMetaEvalCacheNode, 1); - SLLQueuePush(slot->first, slot->last, node); - node->handle = entity->handle; - node->meval = meval_read; - node->range = r1u64(0, pos_opl-pos_min); + read_data = cfg->first->string; } - meval_read = node->meval; - meval_legal_range = node->range; - }goto meta_eval; - case RD_EvalSpaceKind_MetaEntity: - { - // rjf: calculate meta evaluation - CTRL_MetaEval *meval = rd_ctrl_meta_eval_from_entity(scratch.arena, rd_entity_from_eval_space(space)); - // rjf: copy meta evaluation to scratch arena, to form range of legal reads - arena_push(scratch.arena, 0, 64); - String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); - U64 pos_min = arena_pos(scratch.arena); - meval_read = struct_from_serialized(scratch.arena, CTRL_MetaEval, meval_srlzed); - U64 pos_opl = arena_pos(scratch.arena); - - // rjf: rebase all pointer values in meta evaluation to be relative to base pointer - struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); - - // rjf: form legal range - meval_legal_range = r1u64(0, pos_opl-pos_min); - }goto meta_eval; - meta_eval:; - { - if(contains_1u64(meval_legal_range, range.min)) + // rjf: perform read + Rng1U64 legal_range = r1u64(0, read_data.size); + Rng1U64 read_range = intersect_1u64(range, legal_range); + if(read_range.min < read_range.max) { result = 1; - U64 range_dim = dim_1u64(range); - U64 bytes_to_read = Min(range_dim, (meval_legal_range.max - range.min)); - MemoryCopy(out, ((U8 *)meval_read) + range.min, bytes_to_read); - if(bytes_to_read < range_dim) + MemoryCopy(out, read_data.str + read_range.min, dim_1u64(read_range)); + } + }break; + + //- rjf: meta-entity reads + case RD_EvalSpaceKind_MetaCtrlEntity: + { + // rjf: unpack cfg + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); + String8 child_key = e_string_from_id(space.u64s[2]); + + // rjf: determine data to read from, depending on child name in schema + String8 read_data = {0}; + if(child_key.size != 0) + { + MD_NodePtrList schemas = rd_schemas_from_name(ctrl_entity_kind_code_name_table[entity->kind]); + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) { - MemoryZero((U8 *)out + bytes_to_read, range_dim - bytes_to_read); + child_schema = md_child_from_string(n->v, child_key, 0); } + if(str8_match(child_schema->string, str8_lit("exe"), 0) || + str8_match(child_schema->string, str8_lit("label"), 0)) + { + read_data = entity->string; + } + else if(str8_match(child_schema->string, str8_lit("dbg"), 0)) + { + read_data = ctrl_entity_child_from_kind(entity, CTRL_EntityKind_DebugInfoPath)->string; + } + else if(str8_match(child_schema->string, str8_lit("vaddr_range"), 0)) + { + read_data = str8_struct(&entity->vaddr_range); + } + else if(str8_match(child_schema->string, str8_lit("id"), 0)) + { + read_data = str8_struct(&entity->id); + } + else if(str8_match(child_schema->string, str8_lit("active"), 0)) + { + B32 is_frozen = ctrl_entity_tree_is_frozen(entity); + B32 is_active = !is_frozen; + read_data = push_str8_copy(scratch.arena, str8_struct(&is_active)); + } + } + + // rjf: perform read + Rng1U64 legal_range = r1u64(0, read_data.size); + Rng1U64 read_range = intersect_1u64(range, legal_range); + if(read_range.min < read_range.max) + { + result = 1; + MemoryCopy(out, read_data.str + read_range.min, dim_1u64(read_range)); } }break; } @@ -2486,7 +2025,7 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) Rng1U64 legal_range = r1u64(0, regs_size); Rng1U64 write_range = intersect_1u64(legal_range, range); U64 write_size = dim_1u64(write_range); - void *new_regs = ctrl_query_cached_reg_block_from_thread(scratch.arena, d_state->ctrl_entity_store, entity->handle); + void *new_regs = ctrl_reg_block_from_thread(scratch.arena, &d_state->ctrl_entity_store->ctx, entity->handle); MemoryCopy((U8 *)new_regs + write_range.min, in, write_size); result = ctrl_thread_write_reg_block(entity->handle, new_regs); scratch_end(scratch); @@ -2494,100 +2033,103 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) } }break; - //- rjf: meta-entity writes - case RD_EvalSpaceKind_MetaEntity: + //- rjf: meta-config writes + case RD_EvalSpaceKind_MetaCfg: { - Temp scratch = scratch_begin(0, 0); + result = 1; - // rjf: get entity, produce meta-eval - RD_Entity *entity = rd_entity_from_eval_space(space); - CTRL_MetaEval *meval = rd_ctrl_meta_eval_from_entity(scratch.arena, entity); + // rjf: unpack write info + String8 write_string = str8_cstring_capped(in, (U8 *)in + dim_1u64(range)); - // rjf: copy meta evaluation to scratch arena, to form range of legal reads - arena_push(scratch.arena, 0, 64); - String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); - U64 pos_min = arena_pos(scratch.arena); - CTRL_MetaEval *meval_read = struct_from_serialized(scratch.arena, CTRL_MetaEval, meval_srlzed); - U64 pos_opl = arena_pos(scratch.arena); + // rjf: unpack cfg + RD_Cfg *root_cfg = rd_cfg_from_eval_space(space); + String8 child_key = e_string_from_id(space.u64s[1]); - // rjf: rebase all pointer values in meta evaluation to be relative to base pointer - struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); - - // rjf: perform write to entity - if(0){} -#define FlatMemberCase(name) else if(range.min == OffsetOf(CTRL_MetaEval, name) && dim_1u64(range) <= sizeof(meval_read->name)) -#define StringMemberCase(name) else if(range.min == (U64)meval_read->name.str) - FlatMemberCase(enabled) {result = 1; rd_entity_equip_disabled(entity, !!((U8 *)in)[0]);} - FlatMemberCase(debug_subprocesses) {result = 1; entity->debug_subprocesses = !!((U8 *)in)[0]; } - StringMemberCase(label) {result = 1; rd_entity_equip_name(entity, str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(exe) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Executable), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(args) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Arguments), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(working_directory) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_WorkingDirectory), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(entry_point) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_EntryPoint), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(stdout_path) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_StdoutPath), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(stderr_path) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_StderrPath), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(stdin_path) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_StdinPath), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(source_path) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Source), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(destination_path) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Dest), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(type) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Source), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(view_rule) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Dest), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(condition) {result = 1; rd_entity_equip_name(rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Condition), str8_cstring_capped(in, (U8 *)in + 4096));} - StringMemberCase(source_location) + // rjf: no child key? -> overwrite child string + if(child_key.size == 0) { - result = 1; - String8TxtPtPair src_loc = str8_txt_pt_pair_from_string(str8_cstring_capped(in, (U8 *)in + 4096)); - RD_Entity *loc = rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Location); - rd_entity_equip_name(loc, src_loc.string); - rd_entity_equip_txt_pt(loc, src_loc.pt); + rd_cfg_new_replace(root_cfg, write_string); } - StringMemberCase(address_location) + + // rjf: child key -> look up & edit child + else { - U64 vaddr = 0; - if(try_u64_from_str8_c_rules(str8_cstring_capped(in, (U8 *)in + 4096), &vaddr)) + // rjf: modifying a label? -> poison this identifier in the macro map + if(str8_match(child_key, str8_lit("label"), 0)) { - RD_Entity *loc = rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Location); - rd_entity_equip_vaddr(loc, vaddr); - rd_entity_equip_name(loc, str8_zero()); - loc->flags &= ~RD_EntityFlag_HasTextPoint; - result = 1; + String8 pre_edit_label = rd_label_from_cfg(root_cfg); + if(!str8_match(pre_edit_label, write_string, 0)) + { + E_Expr *expr = e_string2expr_map_lookup(e_ir_ctx->macro_map, pre_edit_label); + if(expr != &e_expr_nil) + { + e_string2expr_map_inc_poison(e_ir_ctx->macro_map, pre_edit_label); + e_string2expr_map_insert(e_cache->arena, e_ir_ctx->macro_map, write_string, expr); + } + } + } + + // rjf: zero-range? delete child + if(range.min == range.max) + { + rd_cfg_release(rd_cfg_child_from_string(root_cfg, child_key)); + } + + // rjf: non-zero-range? create child if needed & write value + else + { + RD_Cfg *child_cfg = rd_cfg_child_from_string_or_alloc(root_cfg, child_key); + rd_cfg_new_replace(child_cfg, write_string); } } - StringMemberCase(function_location) - { - result = 1; - RD_Entity *loc = rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Location); - loc->flags &= ~RD_EntityFlag_HasTextPoint; - rd_entity_equip_name(loc, str8_cstring_capped(in, (U8 *)in + 4096)); - } -#undef FlatMemberCase -#undef StringMemberCase - scratch_end(scratch); }break; + case RD_EvalSpaceKind_MetaCtrlEntity: { Temp scratch = scratch_begin(0, 0); - // rjf: get entity, produce meta-eval + // rjf: unpack write info + String8 write_string = str8_cstring_capped(in, (U8 *)in + dim_1u64(range)); + + // rjf: unpack cfg CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); - CTRL_MetaEval *meval = rd_ctrl_meta_eval_from_ctrl_entity(scratch.arena, entity); + String8 child_key = e_string_from_id(space.u64s[2]); - // rjf: copy meta evaluation to scratch arena, to form range of legal reads - arena_push(scratch.arena, 0, 64); - String8 meval_srlzed = serialized_from_struct(scratch.arena, CTRL_MetaEval, meval); - U64 pos_min = arena_pos(scratch.arena); - CTRL_MetaEval *meval_read = struct_from_serialized(scratch.arena, CTRL_MetaEval, meval_srlzed); - U64 pos_opl = arena_pos(scratch.arena); + // rjf: perform write, based on child name in schema + if(child_key.size != 0) + { + MD_NodePtrList schemas = rd_schemas_from_name(ctrl_entity_kind_code_name_table[entity->kind]); + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && child_schema == &md_nil_node; n = n->next) + { + child_schema = md_child_from_string(n->v, child_key, 0); + } + if(str8_match(child_schema->string, str8_lit("label"), 0)) + { + result = 1; + ctrl_entity_equip_string(d_state->ctrl_entity_store, entity, write_string); + rd_cmd(D_CmdKind_SetEntityName, .ctrl_entity = entity->handle, .string = write_string); + } + else if(str8_match(child_schema->string, str8_lit("dbg"), 0)) + { + // TODO(rjf) + } + else if(str8_match(child_schema->string, str8_lit("active"), 0)) + { + result = 1; + B32 new_active = 0; + MemoryCopy(&new_active, in, dim_1u64(range)); + if(!new_active) + { + rd_cmd(D_CmdKind_FreezeEntity, .ctrl_entity = entity->handle); + } + else + { + rd_cmd(D_CmdKind_ThawEntity, .ctrl_entity = entity->handle); + } + } + } - // rjf: rebase all pointer values in meta evaluation to be relative to base pointer - struct_rebase_ptrs(CTRL_MetaEval, meval_read, meval_read); - - // rjf: perform write to entity - if(0){} -#define FlatMemberCase(name) else if(range.min == OffsetOf(CTRL_MetaEval, name) && dim_1u64(range) <= sizeof(meval_read->name)) -#define StringMemberCase(name) else if(range.min == (U64)meval_read->name.str) - StringMemberCase(label) {result = 1; ctrl_entity_equip_string(d_state->ctrl_entity_store, entity, str8_cstring_capped(in, (U8 *)in + 4096));} -#undef FlatMemberCase -#undef StringMemberCase scratch_end(scratch); }break; } @@ -2596,22 +2138,30 @@ rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range) //- rjf: asynchronous streamed reads -> hashes from spaces -internal U128 +internal HS_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated) { - U128 result = {0}; + HS_Key result = {0}; switch(space.kind) { - case E_SpaceKind_FileSystem: + case E_SpaceKind_HashStoreKey: { - result = space.u128; + HS_Root root = {space.u64_0}; + HS_ID id = {space.u128}; + result = hs_key_make(root, id); + }break; + case E_SpaceKind_File: + { + U64 file_path_string_id = space.u64_0; + String8 file_path = e_string_from_id(file_path_string_id); + result = fs_key_from_path_range(file_path, range, 0); }break; case RD_EvalSpaceKind_CtrlEntity: { CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(space); if(entity->kind == CTRL_EntityKind_Process) { - result = ctrl_hash_store_key_from_process_vaddr_range(entity->handle, range, zero_terminated); + result = ctrl_key_from_process_vaddr_range(entity->handle, range, zero_terminated, 0, 0); } }break; } @@ -2626,21 +2176,25 @@ rd_whole_range_from_eval_space(E_Space space) Rng1U64 result = {0}; switch(space.kind) { - case E_SpaceKind_FileSystem: + case E_SpaceKind_HashStoreKey: { - HS_Scope *scope = hs_scope_open(); - U128 hash = {0}; - for(U64 idx = 0; idx < 2; idx += 1) + HS_Root root = {space.u64_0}; + HS_ID id = {space.u128}; + HS_Key key = hs_key_make(root, id); + U128 hash = hs_hash_from_key(key, 0); + HS_Scope *hs_scope = hs_scope_open(); { - hash = hs_hash_from_key(space.u128, idx); - if(!u128_match(hash, u128_zero())) - { - break; - } + String8 data = hs_data_from_hash(hs_scope, hash); + result = r1u64(0, data.size); } - String8 data = hs_data_from_hash(scope, hash); - result = r1u64(0, data.size); - hs_scope_close(scope); + hs_scope_close(hs_scope); + }break; + case E_SpaceKind_File: + { + U64 file_path_string_id = space.u64_0; + String8 file_path = e_string_from_id(file_path_string_id); + FileProperties props = os_properties_from_file_path(file_path); + result = r1u64(0, props.size); }break; case RD_EvalSpaceKind_CtrlEntity: { @@ -2660,46 +2214,68 @@ rd_whole_range_from_eval_space(E_Space space) //- rjf: writing values back to child processes internal B32 -rd_commit_eval_value_string(E_Eval dst_eval, String8 string, B32 string_needs_unescaping) +rd_commit_eval_value_string(E_Eval dst_eval, String8 string) { B32 result = 0; - if(dst_eval.mode == E_Mode_Offset) + if(dst_eval.irtree.mode == E_Mode_Offset) { Temp scratch = scratch_begin(0, 0); - E_TypeKey type_key = e_type_unwrap(dst_eval.type_key); + + //- rjf: unpack type of destination + E_TypeKey type_key = e_type_key_unwrap(dst_eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative); E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_unwrap(e_type_direct_from_key(e_type_unwrap(dst_eval.type_key))); + E_TypeKey direct_type_key = e_type_key_unwrap(dst_eval.irtree.type_key, E_TypeUnwrapFlag_All); E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); + + //- rjf: determine data we'll write + B32 got_commit_data = 0; String8 commit_data = {0}; B32 commit_at_ptr_dest = 0; - if((E_TypeKind_FirstBasic <= type_kind && type_kind <= E_TypeKind_LastBasic) || - type_kind == E_TypeKind_Enum) + if(!e_type_key_match(e_type_key_zero(), type_key)) { - E_Eval src_eval = e_eval_from_string(scratch.arena, string); - commit_data = push_str8_copy(scratch.arena, str8_struct(&src_eval.value)); - commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(type_key)); - } - else if(type_kind == E_TypeKind_Ptr || type_kind == E_TypeKind_Array) - { - E_Eval src_eval = e_eval_from_string(scratch.arena, string); - E_Eval src_eval_value = e_value_eval_from_eval(src_eval); - E_TypeKind src_eval_value_type_kind = e_type_kind_from_key(src_eval_value.type_key); - if(direct_type_kind == E_TypeKind_Char8 || - direct_type_kind == E_TypeKind_UChar8 || - e_type_kind_is_integer(direct_type_kind)) + //- rjf: meta evaluations? -> always treat string as textual content, as-is, + // and commit that. + if(!got_commit_data && dst_eval.space.kind == RD_EvalSpaceKind_MetaCfg) { + got_commit_data = 1; + commit_data = string; + } + + //- rjf: basic types or enums? treat string as an expression, cast to the + // destination type, and compute commit data as being the binary representation + // of the new value. + if(!got_commit_data && + ((E_TypeKind_FirstBasic <= type_kind && type_kind <= E_TypeKind_LastBasic) || + type_kind == E_TypeKind_Enum)) + { + got_commit_data = 1; + E_Eval src_eval = e_eval_from_stringf("(%S)(%S)", e_type_string_from_key(scratch.arena, type_key), string); + commit_data = push_str8_copy(scratch.arena, str8_struct(&src_eval.value)); + commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(type_key)); + } + + //- rjf: pointer or array to characters/integers? -> try to treat + // new value string as textual data + if(!got_commit_data && + ((type_kind == E_TypeKind_Ptr || type_kind == E_TypeKind_Array) && + (direct_type_kind == E_TypeKind_Char8 || + direct_type_kind == E_TypeKind_Char16 || + direct_type_kind == E_TypeKind_Char32 || + direct_type_kind == E_TypeKind_UChar8 || + direct_type_kind == E_TypeKind_UChar16 || + direct_type_kind == E_TypeKind_UChar32 || + e_type_kind_is_integer(direct_type_kind)))) + { + got_commit_data = 1; B32 is_quoted = 0; - if(string_needs_unescaping) + if(string.size >= 1 && string.str[0] == '"') { - if(string.size >= 1 && string.str[0] == '"') - { - string = str8_skip(string, 1); - is_quoted = 1; - } - if(string.size >= 1 && string.str[string.size-1] == '"') - { - string = str8_chop(string, 1); - } + string = str8_skip(string, 1); + is_quoted = 1; + } + if(string.size >= 1 && string.str[string.size-1] == '"') + { + string = str8_chop(string, 1); } if(is_quoted) { @@ -2714,162 +2290,94 @@ rd_commit_eval_value_string(E_Eval dst_eval, String8 string, B32 string_needs_un { commit_at_ptr_dest = 1; } + switch(direct_type_kind) + { + default:{}break; + case E_TypeKind_S16: + case E_TypeKind_U16: + case E_TypeKind_Char16: + case E_TypeKind_UChar16: + { + String16 data16 = str16_from_8(scratch.arena, commit_data); + commit_data = str8((U8 *)data16.str, data16.size*sizeof(U16)); + }break; + case E_TypeKind_Char32: + case E_TypeKind_UChar32: + case E_TypeKind_S32: + case E_TypeKind_U32: + { + String32 data32 = str32_from_8(scratch.arena, commit_data); + commit_data = str8((U8 *)data32.str, data32.size*sizeof(U32)); + }break; + } } - else if(type_kind == E_TypeKind_Ptr && - (e_type_kind_is_pointer_or_ref(src_eval_value_type_kind) || - e_type_kind_is_integer(src_eval_value_type_kind)) && - src_eval_value.mode == E_Mode_Value) + + //- rjf: pointer? -> try to treat new value as numeric value + if(!got_commit_data && type_kind == E_TypeKind_Ptr) { - commit_data = push_str8_copy(scratch.arena, str8_struct(&src_eval.value)); - commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(src_eval.type_key)); - commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(type_key)); + E_Eval src_eval = e_eval_from_string(string); + E_Eval src_eval_value = e_value_eval_from_eval(src_eval); + E_TypeKind src_eval_value_type_kind = e_type_kind_from_key(src_eval_value.irtree.type_key); + if((e_type_kind_is_pointer_or_ref(src_eval_value_type_kind) || + e_type_kind_is_integer(src_eval_value_type_kind)) && + src_eval_value.irtree.mode == E_Mode_Value) + { + got_commit_data = 1; + commit_data = push_str8_copy(scratch.arena, str8_struct(&src_eval.value)); + commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(src_eval.irtree.type_key)); + commit_data.size = Min(commit_data.size, e_type_byte_size_from_key(type_key)); + } } } - if(commit_data.size != 0 && e_type_byte_size_from_key(type_key) != 0) + + //- rjf: determine destination offset we'll write the new data to + U64 dst_offset = dst_eval.value.u64; + if(got_commit_data && commit_at_ptr_dest) + { + E_Eval dst_value_eval = e_value_eval_from_eval(dst_eval); + dst_offset = dst_value_eval.value.u64; + } + + //- rjf: if we have commit data, then write that data to the destination offset + if(got_commit_data) { - U64 dst_offset = dst_eval.value.u64; - if(dst_eval.mode == E_Mode_Offset && commit_at_ptr_dest) - { - E_Eval dst_value_eval = e_value_eval_from_eval(dst_eval); - dst_offset = dst_value_eval.value.u64; - } result = e_space_write(dst_eval.space, commit_data.str, r1u64(dst_offset, dst_offset + commit_data.size)); } + scratch_end(scratch); } return result; } -//- rjf: view rule config tree info extraction - -internal U64 -rd_base_offset_from_eval(E_Eval eval) -{ - if(e_type_kind_is_pointer_or_ref(e_type_kind_from_key(eval.type_key))) - { - eval = e_value_eval_from_eval(eval); - } - return eval.value.u64; -} - -internal E_Value -rd_value_from_params_key(MD_Node *params, String8 key) -{ - Temp scratch = scratch_begin(0, 0); - MD_Node *key_node = md_child_from_string(params, key, 0); - String8 expr = md_string_from_children(scratch.arena, key_node); - E_Eval eval = e_eval_from_string(scratch.arena, expr); - E_Eval value_eval = e_value_eval_from_eval(eval); - scratch_end(scratch); - return value_eval.value; -} - -internal Rng1U64 -rd_range_from_eval_params(E_Eval eval, MD_Node *params) -{ - Temp scratch = scratch_begin(0, 0); - U64 size = rd_value_from_params_key(params, str8_lit("size")).u64; - E_TypeKey type_key = e_type_unwrap(eval.type_key); - E_TypeKind type_kind = e_type_kind_from_key(type_key); - E_TypeKey direct_type_key = e_type_unwrap(e_type_direct_from_key(eval.type_key)); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - if(size == 0 && e_type_kind_is_pointer_or_ref(type_kind) && (direct_type_kind == E_TypeKind_Struct || - direct_type_kind == E_TypeKind_Union || - direct_type_kind == E_TypeKind_Class || - direct_type_kind == E_TypeKind_Array)) - { - size = e_type_byte_size_from_key(e_type_direct_from_key(e_type_unwrap(eval.type_key))); - } - if(size == 0 && eval.mode == E_Mode_Offset && (type_kind == E_TypeKind_Struct || - type_kind == E_TypeKind_Union || - type_kind == E_TypeKind_Class || - type_kind == E_TypeKind_Array)) - { - size = e_type_byte_size_from_key(e_type_unwrap(eval.type_key)); - } - if(size == 0) - { - size = KB(16); - } - Rng1U64 result = {0}; - result.min = rd_base_offset_from_eval(eval); - result.max = result.min + size; - scratch_end(scratch); - return result; -} - -internal TXT_LangKind -rd_lang_kind_from_eval_params(E_Eval eval, MD_Node *params) -{ - TXT_LangKind lang_kind = TXT_LangKind_Null; - if(eval.expr->kind == E_ExprKind_LeafFilePath) - { - lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(eval.expr->string)); - } - else - { - MD_Node *lang_node = md_child_from_string(params, str8_lit("lang"), 0); - String8 lang_kind_string = lang_node->first->string; - lang_kind = txt_lang_kind_from_extension(lang_kind_string); - } - return lang_kind; -} - -internal Arch -rd_arch_from_eval_params(E_Eval eval, MD_Node *params) -{ - Arch arch = Arch_Null; - MD_Node *arch_node = md_child_from_string(params, str8_lit("arch"), 0); - String8 arch_kind_string = arch_node->first->string; - if(str8_match(arch_kind_string, str8_lit("x64"), StringMatchFlag_CaseInsensitive)) - { - arch = Arch_x64; - } - return arch; -} - -internal Vec2S32 -rd_dim2s32_from_eval_params(E_Eval eval, MD_Node *params) -{ - Vec2S32 dim = v2s32(1, 1); - { - dim.x = rd_value_from_params_key(params, str8_lit("w")).s32; - dim.y = rd_value_from_params_key(params, str8_lit("h")).s32; - } - return dim; -} - -internal R_Tex2DFormat -rd_tex2dformat_from_eval_params(E_Eval eval, MD_Node *params) -{ - R_Tex2DFormat result = R_Tex2DFormat_RGBA8; - { - MD_Node *fmt_node = md_child_from_string(params, str8_lit("fmt"), 0); - for EachNonZeroEnumVal(R_Tex2DFormat, fmt) - { - if(str8_match(r_tex2d_format_display_string_table[fmt], fmt_node->first->string, StringMatchFlag_CaseInsensitive)) - { - result = fmt; - break; - } - } - } - return result; -} - //- rjf: eval <-> file path +internal String8 +rd_file_path_from_eval(Arena *arena, E_Eval eval) +{ + String8 result = {0}; + switch(eval.space.kind) + { + default:{}break; + case E_SpaceKind_File: + { + result = push_str8_copy(arena, e_string_from_id(eval.space.u64_0)); + }break; + case E_SpaceKind_FileSystem: + { + result = push_str8_copy(arena, e_string_from_id(eval.value.u64)); + }break; + } + return result; +} + internal String8 rd_file_path_from_eval_string(Arena *arena, String8 string) { String8 result = {0}; { Temp scratch = scratch_begin(&arena, 1); - E_Eval eval = e_eval_from_string(scratch.arena, string); - if(eval.expr->kind == E_ExprKind_LeafFilePath) - { - result = raw_from_escaped_str8(arena, eval.expr->string); - } + E_Eval eval = e_eval_from_string(string); + result = rd_file_path_from_eval(arena, eval); scratch_end(scratch); } return result; @@ -2880,218 +2388,3122 @@ rd_eval_string_from_file_path(Arena *arena, String8 string) { Temp scratch = scratch_begin(&arena, 1); String8 string_escaped = escaped_from_raw_str8(scratch.arena, string); - String8 result = push_str8f(arena, "file:\"%S\"", string_escaped); + String8 result = push_str8f(arena, "file:\"%S\".data", string_escaped); scratch_end(scratch); return result; } +//- rjf: eval -> query + +internal String8 +rd_query_from_eval_string(Arena *arena, String8 string) +{ + String8 result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + E_Expr *expr = e_parse_from_string(string).expr; + if(expr->kind == E_ExprKind_LeafIdentifier && + str8_match(expr->qualifier, str8_lit("query"), 0)) + { + result = expr->string; + } + scratch_end(scratch); + } + return result; +} + //////////////////////////////// -//~ rjf: View State Functions +//~ rjf: View Functions -//- rjf: allocation/releasing - -internal RD_View * -rd_view_alloc(void) +internal RD_Cfg * +rd_view_from_eval(RD_Cfg *parent, E_Eval eval) { - // rjf: allocate - RD_View *view = rd_state->free_view; + Temp scratch = scratch_begin(0, 0); + E_TypeKey type_key = eval.irtree.type_key; + E_Type *type = e_type_from_key(type_key); + String8 schema_name = str8_lit("watch"); + B32 type_is_visualizer = 0; + if(type->kind == E_TypeKind_Lens) { - if(!rd_view_is_nil(view)) + RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(type->name); + if(view_ui_rule != &rd_nil_view_ui_rule) { - rd_state->free_view_count -= 1; - SLLStackPop_N(rd_state->free_view, alloc_next); - U64 generation = view->generation; - MemoryZeroStruct(view); - view->generation = generation; + schema_name = type->name; + type_is_visualizer = 1; } - else - { - view = push_array(rd_state->arena, RD_View, 1); - } - view->generation += 1; } - - // rjf: initialize - view->arena = arena_alloc(); - view->spec = &rd_nil_view_rule_info; - view->project_path_arena = arena_alloc(); - view->project_path = str8_zero(); - for(U64 idx = 0; idx < ArrayCount(view->params_arenas); idx += 1) + RD_Cfg *view = rd_cfg_child_from_string_or_alloc(parent, schema_name); + rd_cfg_child_from_string_or_alloc(view, str8_lit("selected")); { - view->params_arenas[idx] = arena_alloc(); - view->params_roots[idx] = &md_nil_node; + // rjf: get expression evaluation + // TODO(rjf): we need to account for UFCS style expressions here... + E_Eval expr_eval = eval; + if(eval.expr->kind == E_ExprKind_Call && type_is_visualizer) + { + expr_eval = e_eval_from_expr(eval.expr->first->next); + } + + // rjf: get arguments to view + E_Expr **args = 0; + U64 args_count = 0; + if(type->args != 0) + { + args = type->args; + args_count = type->count; + } + + // rjf: reflect expr & arguments in cfg tree + RD_Cfg *expr_root = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + rd_cfg_new_replace(expr_root, e_full_expr_string_from_key(scratch.arena, expr_eval.key)); + { + MD_NodePtrList schemas = rd_schemas_from_name(schema_name); + U64 unnamed_order_idx = 0; + for EachIndex(arg_idx, args_count) + { + E_Expr *arg = args[arg_idx]; + String8 param_name = {0}; + E_Expr *arg_expr = arg; + if(arg->kind == E_ExprKind_Define) + { + param_name = arg->first->string; + arg_expr = arg->first->next; + } + else if(schemas.last != 0) + { + for MD_EachNode(schema_child, schemas.last->v->first) + { + MD_Node *order_tag = md_tag_from_string(schema_child, str8_lit("order"), 0); + if(order_tag != &md_nil_node) + { + U64 schema_child_order_idx = 0; + try_u64_from_str8_c_rules(order_tag->first->string, &schema_child_order_idx); + if(schema_child_order_idx == unnamed_order_idx) + { + param_name = schema_child->string; + arg_expr = arg; + break; + } + } + } + unnamed_order_idx += 1; + } + RD_Cfg *arg_root = rd_cfg_child_from_string_or_alloc(view, param_name); + rd_cfg_new_replace(arg_root, e_string_from_expr(scratch.arena, arg_expr, str8_zero())); + } + } } - view->query_cursor = view->query_mark = txt_pt(1, 1); - view->query_string_size = 0; - rd_state->allocated_view_count += 1; - DLLPushBack_NPZ(&rd_nil_view, rd_state->first_view, rd_state->last_view, view, alloc_next, alloc_prev); + scratch_end(scratch); return view; } -internal void -rd_view_release(RD_View *view) +internal RD_ViewState * +rd_view_state_from_cfg(RD_Cfg *cfg) { - DLLRemove_NPZ(&rd_nil_view, rd_state->first_view, rd_state->last_view, view, alloc_next, alloc_prev); - SLLStackPush_N(rd_state->free_view, view, alloc_next); - for(RD_View *tchild = view->first_transient, *next = 0; !rd_view_is_nil(tchild); tchild = next) + RD_ViewState *view_state = &rd_nil_view_state; + RD_CfgID id = cfg->id; + if(id != 0 && + id == rd_state->view_state_last_accessed_id && + id == rd_state->view_state_last_accessed->cfg_id) { - next = tchild->order_next; - rd_view_release(tchild); + view_state = rd_state->view_state_last_accessed; } - view->first_transient = view->last_transient = &rd_nil_view; - view->transient_view_slots_count = 0; - view->transient_view_slots = 0; - for(RD_ArenaExt *ext = view->first_arena_ext; ext != 0; ext = ext->next) + else { - arena_release(ext->arena); - } - view->first_arena_ext = view->last_arena_ext = 0; - arena_release(view->project_path_arena); - for(U64 idx = 0; idx < ArrayCount(view->params_arenas); idx += 1) - { - arena_release(view->params_arenas[idx]); - } - arena_release(view->arena); - view->generation += 1; - rd_state->allocated_view_count -= 1; - rd_state->free_view_count += 1; -} - -//- rjf: equipment - -internal void -rd_view_equip_spec(RD_View *view, RD_ViewRuleInfo *spec, String8 query, MD_Node *params) -{ - // rjf: fill params tree - for(U64 idx = 0; idx < ArrayCount(view->params_arenas); idx += 1) - { - arena_clear(view->params_arenas[idx]); - } - view->params_roots[0] = md_tree_copy(view->params_arenas[0], params); - view->params_write_gen = view->params_read_gen = 0; - - // rjf: fill query buffer - rd_view_equip_query(view, query); - - // rjf: initialize state for new view spec - { - for(RD_ArenaExt *ext = view->first_arena_ext; ext != 0; ext = ext->next) + U64 hash = d_hash_from_string(str8_struct(&id)); + U64 slot_idx = hash%rd_state->view_state_slots_count; + RD_ViewStateSlot *slot = &rd_state->view_state_slots[slot_idx]; + for(RD_ViewState *v = slot->first; v != 0; v = v->hash_next) { - arena_release(ext->arena); + if(v->cfg_id == id) + { + view_state = v; + break; + } } - for(RD_View *tchild = view->first_transient, *next = 0; !rd_view_is_nil(tchild); tchild = next) + } + if(view_state == &rd_nil_view_state) + { + view_state = rd_state->free_view_state; + if(view_state) { - next = tchild->order_next; - rd_view_release(tchild); + SLLStackPop_N(rd_state->free_view_state, hash_next); } - view->first_transient = view->last_transient = &rd_nil_view; - view->first_arena_ext = view->last_arena_ext = 0; - view->transient_view_slots_count = 0; - view->transient_view_slots = 0; - arena_clear(view->arena); - view->user_data = 0; + else + { + view_state = push_array(rd_state->arena, RD_ViewState, 1); + } + MemoryCopyStruct(view_state, &rd_nil_view_state); + U64 hash = d_hash_from_string(str8_struct(&id)); + U64 slot_idx = hash%rd_state->view_state_slots_count; + RD_ViewStateSlot *slot = &rd_state->view_state_slots[slot_idx]; + DLLPushBack_NP(slot->first, slot->last, view_state, hash_next, hash_prev); + view_state->cfg_id = id; + view_state->arena = arena_alloc(); + view_state->arena_reset_pos = arena_pos(view_state->arena); + view_state->ev_view = ev_view_alloc(); + } + if(view_state != &rd_nil_view_state) + { + view_state->last_frame_index_touched = rd_state->frame_index; + } + rd_state->view_state_last_accessed = view_state; + rd_state->view_state_last_accessed_id = id; + return view_state; +} + +typedef struct RD_WatchRowExtrasDrawData RD_WatchRowExtrasDrawData; +struct RD_WatchRowExtrasDrawData +{ + B32 breaks_from_prev; +}; + +internal UI_BOX_CUSTOM_DRAW(rd_watch_row_extras_custom_draw) +{ + RD_WatchRowExtrasDrawData *draw_data = (RD_WatchRowExtrasDrawData *)user_data; + if(draw_data->breaks_from_prev) DR_ClipScope(intersect_2f32(dr_top_clip(), box->rect)) + { + Vec4F32 shadow_color = ui_color_from_name(str8_lit("drop_shadow")); + R_Rect2DInst *inst = dr_rect(r2f32p(box->rect.x0, box->rect.y0, box->rect.x1, (box->rect.y0+box->rect.y1)/2), shadow_color, 0, 0, 0); + inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(0, 0, 0, 0); } - MemoryZeroStruct(&view->scroll_pos); - view->spec = spec; - arena_clear(view->project_path_arena); - view->project_path = push_str8_copy(view->project_path_arena, rd_cfg_path_from_src(RD_CfgSrc_Project)); - view->is_filtering = 0; - view->is_filtering_t = 0; } internal void -rd_view_equip_query(RD_View *view, String8 query) +rd_view_ui(Rng2F32 rect) { - view->query_string_size = Min(sizeof(view->query_buffer), query.size); - MemoryCopy(view->query_buffer, query.str, view->query_string_size); - view->query_cursor = view->query_mark = txt_pt(1, query.size+1); -} - -internal void -rd_view_equip_loading_info(RD_View *view, B32 is_loading, U64 progress_v, U64 progress_target) -{ - view->loading_t_target = (F32)!!is_loading; - view->loading_progress_v = progress_v; - view->loading_progress_v_target = progress_target; - if(is_loading) + ProfBeginFunction(); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *vs = rd_view_state_from_cfg(view); + String8 view_name = view->string; + String8 expr_string = rd_expr_from_cfg(view); + B32 view_is_floating = 0; + for(RD_Cfg *p = view->parent; p != &rd_nil_cfg; p = p->parent) { - view->loading_t = view->loading_t_target; + if(str8_match(p->string, str8_lit("immediate"), 0)) + { + view_is_floating = 1; + break; + } } -} - -//- rjf: user state extensions - -internal void * -rd_view_get_or_push_user_state(RD_View *view, U64 size) -{ - void *result = view->user_data; - if(result == 0) + + ////////////////////////////// + //- rjf: query extension + // + RD_Cfg *query_root = rd_cfg_child_from_string(view, str8_lit("query")); + RD_Cfg *input_root = rd_cfg_child_from_string(query_root, str8_lit("input")); + RD_Cfg *cmd_root = rd_cfg_child_from_string(query_root, str8_lit("cmd")); + String8 current_input = input_root->first->string; + B32 search_row_is_open = (vs->query_is_open); + F32 search_row_open_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "search_row_open_%p", view), + (F32)!!search_row_is_open, + .initial = (F32)!!search_row_is_open, + .epsilon = 0.01f, + .rate = rd_state->menu_animation_rate); + if(search_row_open_t > 0.001f) { - view->user_data = result = push_array(view->arena, U8, size); + String8 cmd_name = cmd_root->first->string; + RD_IconKind icon = rd_icon_kind_from_code_name(cmd_name); + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + + //- rjf: store cfg's string into view's + vs->query_string_size = Min(sizeof(vs->query_buffer), current_input.size); + MemoryCopy(vs->query_buffer, current_input.str, vs->query_string_size); + + //- rjf: clamp cursor + if(vs->query_cursor.column == 0) + { + vs->query_mark = txt_pt(1, 1); + vs->query_cursor = txt_pt(1, vs->query_string_size+1); + } + + //- rjf: determine dimensions + F32 search_row_height_target = ui_top_px_height(); + F32 search_row_height = search_row_open_t*search_row_height_target; + search_row_height = Min(search_row_height, dim_2f32(rect).y); + rect.y0 += search_row_height; + rect.y0 = floor_f32(rect.y0); + + //- rjf: build container + UI_Box *search_row = &ui_nil_box; + UI_PrefHeight(ui_px(search_row_height, 1.f)) + { + search_row = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawDropShadow, "###search"); + } + + //- rjf: build contents + UI_Parent(search_row) UI_WidthFill UI_HeightFill UI_Focus(vs->query_is_open && !vs->contents_are_focused ? UI_FocusKind_On : UI_FocusKind_Off) + RD_Font(cmd_kind_info->query.flags & RD_QueryFlag_CodeInput ? RD_FontSlot_Code : RD_FontSlot_Main) + { + if(cmd_name.size != 0) + { + UI_TextAlignment(UI_TextAlign_Center) + UI_Transparency(1-search_row_open_t) + UI_PrefWidth(ui_em(2.5f, 1.f)) + UI_TagF("weak") + RD_Font(RD_FontSlot_Icons) + ui_label(rd_icon_kind_text_table[icon == RD_IconKind_Null ? RD_IconKind_Find : icon]); + UI_Transparency(1-search_row_open_t) + RD_Font(RD_FontSlot_Main) UI_PrefWidth(ui_text_dim(1, 1)) + ui_label(rd_display_from_code_name(cmd_name)); + ui_spacer(ui_em(0.5f, 1.f)); + } + UI_Key line_edit_key = {0}; + RD_CellParams params = {0}; + { + params.flags |= !!(cmd_kind_info->query.flags & RD_QueryFlag_CodeInput) * RD_CellFlag_CodeContents; + params.flags |= RD_CellFlag_Border; + params.cursor = &vs->query_cursor; + params.mark = &vs->query_mark; + params.edit_buffer = vs->query_buffer; + params.edit_string_size_out = &vs->query_string_size; + params.edit_buffer_size = sizeof(vs->query_buffer); + params.pre_edit_value = current_input; + params.line_edit_key_out = &line_edit_key; + } + UI_Transparency(1-search_row_open_t) + { + UI_Signal sig = rd_cellf(¶ms, "###search"); +#if 0 + // TODO(rjf) + if(ui_is_focus_active()) + { + rd_set_autocomp_regs(e_eval_nil, + .ui_key = line_edit_key, + .string = str8(vs->query_buffer, vs->query_string_size), + .cursor = vs->query_cursor); + } +#endif + if(ui_pressed(sig)) + { + vs->query_is_open = 1; + vs->contents_are_focused = 0; + rd_cmd(RD_CmdKind_FocusPanel); + } + } + } + + //- rjf: commit string to view + if(input_root == &rd_nil_cfg) + { + input_root = rd_cfg_child_from_string_or_alloc(query_root, str8_lit("input")); + } + rd_cfg_new_replace(input_root, str8(vs->query_buffer, vs->query_string_size)); } - return result; -} - -internal Arena * -rd_view_push_arena_ext(RD_View *view) -{ - RD_ArenaExt *ext = push_array(view->arena, RD_ArenaExt, 1); - ext->arena = arena_alloc(); - SLLQueuePush(view->first_arena_ext, view->last_arena_ext, ext); - return ext->arena; -} - -//- rjf: param saving - -internal void -rd_view_store_param(RD_View *view, String8 key, String8 value) -{ - B32 new_copy = 0; - if(view->params_write_gen == view->params_read_gen) + + ////////////////////////////// + //- rjf: build main view container + // + UI_Box *view_container = &ui_nil_box; + UI_WidthFill UI_HeightFill { - view->params_write_gen += 1; - new_copy = 1; + view_container = ui_build_box_from_key(0, ui_key_zero()); } - Arena *new_params_arena = view->params_arenas[view->params_write_gen%ArrayCount(view->params_arenas)]; - if(new_copy) + + ////////////////////////////// + //- rjf: fill view container + // + UI_Parent(view_container) + UI_FontSize(rd_font_size()) + UI_PrefHeight(ui_px(floor_f32(ui_top_font_size()*rd_setting_f32_from_name(str8_lit("row_height"))), 1.f)) { - arena_clear(new_params_arena); - view->params_roots[view->params_write_gen%ArrayCount(view->params_arenas)] = md_tree_copy(new_params_arena, view->params_roots[view->params_read_gen%ArrayCount(view->params_arenas)]); + //////////////////////////// + //- rjf: special-case view: "getting started" + // + if(0){} + else if(str8_match(view_name, str8_lit("getting_started"), 0)) + { + Temp scratch = scratch_begin(0, 0); + ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); + UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) + UI_Padding(ui_pct(1, 0)) UI_Focus(UI_FocusKind_Null) + { + RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); + + //- rjf: icon & info + UI_Padding(ui_em(2.f, 1.f)) UI_TagF("weak") + { + //- rjf: icon + { + F32 icon_dim = ui_top_font_size()*10.f; + UI_PrefHeight(ui_px(icon_dim, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_px(icon_dim, 1.f)) + { + R_Handle texture = rd_state->icon_texture; + Vec2S32 texture_dim = r_size_from_tex2d(texture); + ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); + } + } + + //- rjf: info + UI_Padding(ui_em(2.f, 1.f)) + UI_WidthFill UI_PrefHeight(ui_em(2.f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_text_dim(10, 1)) + { + ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); + } + } + + //- rjf: targets state dependent helper + B32 helper_built = 0; + if(processes.count == 0) + { + helper_built = 1; + switch(targets.count) + { + //- rjf: user has no targets. build helper for adding them + case 0: + { + UI_PrefHeight(ui_em(3.75f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(22.f, 1.f)) + UI_CornerRadius(ui_top_font_size()/2.f) + UI_TagF("pop") + if(ui_clicked(rd_icon_buttonf(RD_IconKind_Add, 0, "Add Target"))) + { + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string); + } + }break; + + //- rjf: user has 1 target. build helper for launching it + case 1: + { + RD_Cfg *target_cfg = rd_cfg_list_first(&targets); + D_Target target = rd_target_from_cfg(scratch.arena, target_cfg); + String8 target_full_path = target.exe; + String8 target_name = str8_skip_last_slash(target_full_path); + UI_PrefHeight(ui_em(3.75f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(22.f, 1.f)) + UI_CornerRadius(ui_top_font_size()/2.f) + UI_TagF("good_pop") + { + if(ui_clicked(rd_icon_buttonf(RD_IconKind_Play, 0, "Launch %S", target_name))) + { + rd_cmd(RD_CmdKind_LaunchAndRun, .cfg = target_cfg->id); + } + ui_spacer(ui_em(1.5f, 1)); + if(ui_clicked(rd_icon_buttonf(RD_IconKind_StepInto, 0, "Step Into %S", target_name))) + { + rd_cmd(RD_CmdKind_LaunchAndStepInto, .cfg = target_cfg->id); + } + } + }break; + + //- rjf: user has N targets. + default: + { + helper_built = 0; + }break; + } + } + + //- rjf: or text + if(helper_built) + { + UI_TagF("weak") + UI_PrefHeight(ui_em(2.25f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_WidthFill + ui_labelf("- or -"); + } + + //- rjf: helper text for command lister activation + UI_TagF("weak") + UI_PrefHeight(ui_em(2.25f, 1.f)) UI_Row + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) + UI_Padding(ui_pct(1, 0)) + { + ui_labelf("use"); + UI_TextAlignment(UI_TextAlign_Center) rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_OpenPalette].string, str8_zero(), 1); + ui_labelf("to search for commands and options"); + } + } + scratch_end(scratch); + } + + //////////////////////////// + //- rjf: special-case view: pending + // + else if(str8_match(view_name, str8_lit("pending"), 0)) + { + Temp scratch = scratch_begin(0, 0); + typedef struct State State; + struct State + { + Arena *deferred_cmd_arena; + RD_CmdList deferred_cmds; + }; + State *state = rd_view_state(State); + if(state->deferred_cmd_arena == 0) + { + state->deferred_cmd_arena = rd_push_view_arena(); + } + rd_store_view_loading_info(1, 0, 0); + + // rjf: any commands sent to this view need to be deferred until loading is complete + for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) + { + RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); + switch(kind) + { + default:{}break; + case RD_CmdKind_GoToLine: + case RD_CmdKind_GoToAddress: + case RD_CmdKind_CenterCursor: + case RD_CmdKind_ContainCursor: + { + rd_cmd_list_push_new(state->deferred_cmd_arena, &state->deferred_cmds, cmd->name, cmd->regs); + }break; + } + } + + // rjf: unpack view's target expression & hash + E_Eval eval = e_eval_from_string(expr_string); + Rng1U64 range = r1u64(0, 1024); + HS_Key key = rd_key_from_eval_space_range(eval.space, range, 0); + U128 hash = hs_hash_from_key(key, 0); + + // rjf: determine if hash's blob is ready, and which viewer to use + B32 data_is_ready = 0; + String8 new_view_name = {0}; + { + HS_Scope *hs_scope = hs_scope_open(); + if(!u128_match(hash, u128_zero())) + { + String8 data = hs_data_from_hash(hs_scope, hash); + U64 num_utf8_bytes = 0; + U64 num_unknown_bytes = 0; + for(U64 idx = 0; idx < data.size && idx < range.max;) + { + UnicodeDecode decode = utf8_decode(data.str+idx, data.size-idx); + if(decode.codepoint != max_U32 && (decode.inc > 1 || + (10 <= decode.codepoint && decode.codepoint <= 13) || + (32 <= decode.codepoint && decode.codepoint <= 126))) + { + num_utf8_bytes += decode.inc; + idx += decode.inc; + } + else + { + num_unknown_bytes += 1; + idx += 1; + } + } + data_is_ready = 1; + if(num_utf8_bytes > num_unknown_bytes*4 || num_unknown_bytes == 0) + { + new_view_name = str8_lit("text"); + } + else + { + new_view_name = str8_lit("memory"); + } + } + hs_scope_close(hs_scope); + } + + // rjf: if we don't have a viewer, just use the memory viewer. + if(new_view_name.size == 0) + { + new_view_name = str8_lit("memory"); + } + + // rjf: if data is ready and we have the name of a new visualizer, + // dispatch deferred commands & change this view's string to be + // that of the new visualizer. + if(data_is_ready && new_view_name.size != 0) + { + for(RD_CmdNode *cmd_node = state->deferred_cmds.first; + cmd_node != 0; + cmd_node = cmd_node->next) + { + RD_Cmd *cmd = &cmd_node->cmd; + rd_push_cmd(cmd->name, cmd->regs); + } + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + rd_cfg_equip_string(view, new_view_name); + RD_ViewState *vs = rd_view_state_from_cfg(view); + for(RD_ArenaExt *ext = vs->first_arena_ext; ext != 0; ext = ext->next) + { + arena_release(ext->arena); + } + arena_pop_to(vs->arena, vs->arena_reset_pos); + vs->user_data = 0; + vs->first_arena_ext = vs->last_arena_ext = 0; + } + + // rjf: if we don't have a viewer, for whatever reason, then just + // close the tab. + if(data_is_ready && new_view_name.size == 0) + { + rd_cmd(RD_CmdKind_CloseTab); + } + + scratch_end(scratch); + } + + //////////////////////////// + //- rjf: watch view + // + else if(str8_match(view_name, str8_lit("watch"), 0)) + { + Temp scratch = scratch_begin(0, 0); + RD_Font(RD_FontSlot_Code) + { + if(expr_string.size == 0) + { + expr_string = push_str8f(scratch.arena, "query:config.$%I64x.watches", rd_regs()->view); + } + E_Eval eval = e_eval_from_string(expr_string); + RD_WatchViewState *ewv = rd_view_state(RD_WatchViewState); + UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); + F32 entity_hover_t_rate = rd_setting_b32_from_name(str8_lit("hover_animations")) ? (1 - pow_f32(2, (-60.f * rd_state->frame_dt))) : 1.f; + B32 is_first_frame = 0; + if(ewv->initialized == 0) + { + is_first_frame = 1; + ewv->initialized = 1; + ewv->filter_arena = rd_push_view_arena(); + ewv->text_edit_arena = rd_push_view_arena(); + } + + ////////////////////////////// + //- rjf: unpack arguments + // + EV_View *eval_view = rd_view_eval_view(); + F32 row_height_px = ui_top_px_height(); + S64 num_possible_visible_rows = (S64)(dim_2f32(rect).y/row_height_px); + F32 row_string_max_size_px = dim_2f32(rect).x; + EV_StringFlags string_flags = EV_StringFlag_ReadOnlyDisplayRules; + String8 filter = rd_view_query_input(); + Vec4F32 pop_background_rgba = {0}; + UI_TagF("pop") pop_background_rgba = ui_color_from_name(str8_lit("background")); + + ////////////////////////////// + //- rjf: whenever the filter changes, we want to reset the cursor/mark state + // + if(!str8_match(filter, ewv->last_filter, 0)) + { + MemoryZeroStruct(&ewv->cursor); + MemoryZeroStruct(&ewv->mark); + MemoryZeroStruct(&ewv->next_cursor); + MemoryZeroStruct(&ewv->next_mark); + arena_clear(ewv->filter_arena); + ewv->last_filter = push_str8_copy(ewv->filter_arena, filter); + } + + ////////////////////////////// + //- rjf: decide if root should be implicit + // + // "implicit" means -> root is automatically expanded, row depth is 1 less than the + // block tree structure would suggest. this would be used if the root is, for instance, + // the "collection of all watches", to build a watch window. but this behavior is not + // as desirable if we are just using some other expression as the root. + // + B32 implicit_root = (rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("explicit_root")) == &rd_nil_cfg); + + ////////////////////////////// + //- rjf: determine autocompletion string + // + String8 autocomplete_hint_string = ui_autocomplete_string(); + + ////////////////////////////// + //- rjf: process commands + // + for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) + { + RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); + switch(kind) + { + default:{}break; + case RD_CmdKind_Search: + case RD_CmdKind_SearchBackwards: + { + vs->query_is_open = 0; + }break; + } + } + + ////////////////////////////// + //- rjf: consume events & perform navigations/edits - calculate state + // + EV_BlockTree block_tree = {0}; + EV_BlockRangeList block_ranges = {0}; + UI_ScrollListRowBlockArray row_blocks = {0}; + Vec2S64 cursor_tbl = {0}; + Vec2S64 mark_tbl = {0}; + Rng2S64 selection_tbl = {0}; + ProfScope("consume events & perform navigations/edits - calculate state") UI_Focus(UI_FocusKind_On) + { + B32 state_dirty = 1; + B32 snap_to_cursor = 0; + B32 cursor_dirty__tbl = 0; + for(UI_Event *event = 0;;) + { + ////////////////////////// + //- rjf: state -> viz blocks + // + if(state_dirty) ProfScope("state -> viz blocks") + { + eval = e_eval_from_string(eval.string); + MemoryZeroStruct(&block_tree); + MemoryZeroStruct(&block_ranges); + if(implicit_root || is_first_frame) + { + ev_key_set_expansion(eval_view, ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); + } + block_tree = ev_block_tree_from_eval(scratch.arena, eval_view, filter, eval); + block_ranges = ev_block_range_list_from_tree(scratch.arena, &block_tree); + if(implicit_root && block_ranges.first != 0) + { + block_ranges.count -= 1; + block_ranges.first = block_ranges.first->next; + } + } + + ////////////////////////// + //- rjf: block ranges -> ui row blocks + // + ProfScope("block ranges -> ui row blocks") + { + UI_ScrollListRowBlockChunkList row_block_chunks = {0}; + for(EV_BlockRangeNode *n = block_ranges.first; n != 0; n = n->next) + { + UI_ScrollListRowBlock block = {0}; + block.row_count = dim_1u64(n->v.range); + block.item_count = n->v.block->viz_expand_info.single_item ? 1 : dim_1u64(n->v.range); + ui_scroll_list_row_block_chunk_list_push(scratch.arena, &row_block_chunks, 256, &block); + } + row_blocks = ui_scroll_list_row_block_array_from_chunk_list(scratch.arena, &row_block_chunks); + } + + ////////////////////////// + //- rjf: conclude state update + // + if(state_dirty) + { + state_dirty = 0; + } + + ////////////////////////////// + //- rjf: 2D table coordinates * blocks -> stable cursor state + // + if(cursor_dirty__tbl) + { + cursor_dirty__tbl = 0; + struct + { + RD_WatchPt *pt_state; + Vec2S64 pt_tbl; + } + points[] = + { + {&ewv->cursor, cursor_tbl}, + {&ewv->mark, mark_tbl}, + }; + for(U64 point_idx = 0; point_idx < ArrayCount(points); point_idx += 1) + { + EV_Key last_key = points[point_idx].pt_state->key; + EV_Key last_parent_key = points[point_idx].pt_state->parent_key; + points[point_idx].pt_state[0] = rd_watch_pt_from_tbl(&block_ranges, points[point_idx].pt_tbl); + if(ev_key_match(ev_key_zero(), points[point_idx].pt_state->key) && points[point_idx].pt_tbl.y != 0) + { + points[point_idx].pt_state->key = last_parent_key; + EV_ExpandNode *node = ev_expand_node_from_key(eval_view, last_parent_key); + for(EV_ExpandNode *n = node; n != 0; n = n->parent) + { + points[point_idx].pt_state->key = n->key; + if(n->expanded == 0) + { + break; + } + } + } + if(point_idx == 0 && + (!ev_key_match(ewv->cursor.key, last_key) || + !ev_key_match(ewv->cursor.parent_key, last_parent_key))) + { + ewv->text_editing = 0; + } + } + ewv->next_cursor = ewv->cursor; + ewv->next_mark = ewv->mark; + } + + ////////////////////////// + //- rjf: stable cursor state * blocks -> 2D table coordinates + // + EV_WindowedRowList mark_rows = {0}; + Rng2S64 cursor_tbl_range = {0}; + { + // rjf: compute 2d table coordinates + cursor_tbl = rd_tbl_from_watch_pt(&block_ranges, ewv->cursor); + mark_tbl = rd_tbl_from_watch_pt(&block_ranges, ewv->mark); + + // rjf: compute legal coordinate range, given selection-defining row + Rng1S64 cursor_x_range = {0}; + { + EV_Row *row = ev_row_from_num(scratch.arena, eval_view, &block_ranges, mark_tbl.y); + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + cursor_x_range = r1s64(0, (S64)row_info.cells.count-1); + } + cursor_tbl_range = r2s64(v2s64(cursor_x_range.min, 0), v2s64(cursor_x_range.max, block_tree.total_item_count - implicit_root)); + + // rjf: clamp x positions of cursor/mark tbl + for EachEnumVal(Axis2, axis) + { + cursor_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), cursor_tbl.v[axis]); + mark_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), mark_tbl.v[axis]); + } + + // rjf: form selection range table coordinates + selection_tbl = r2s64p(Min(cursor_tbl.x, mark_tbl.x), Min(cursor_tbl.y, mark_tbl.y), + Max(cursor_tbl.x, mark_tbl.x), Max(cursor_tbl.y, mark_tbl.y)); + } + + ////////////////////////// + //- rjf: [table] snap to cursor + // + if(snap_to_cursor) + { + Rng1S64 global_vnum_range = r1s64(1, block_tree.total_row_count+1); + if(contains_1s64(global_vnum_range, cursor_tbl.y)) + { + UI_ScrollPt *scroll_pt = &scroll_pos.y; + + //- rjf: compute visible row range + Rng1S64 visible_row_num_range = r1s64(scroll_pt->idx + 1 - !!(scroll_pt->off < 0), + scroll_pt->idx + 1 + num_possible_visible_rows); + + //- rjf: compute cursor row range from cursor item + Rng1S64 cursor_visibility_row_num_range = {0}; + cursor_visibility_row_num_range.min = ev_vnum_from_num(&block_ranges, cursor_tbl.y) - 1; + cursor_visibility_row_num_range.max = cursor_visibility_row_num_range.min + 3; + + //- rjf: compute deltas & apply + S64 min_delta = Min(0, cursor_visibility_row_num_range.min-visible_row_num_range.min); + S64 max_delta = Max(0, cursor_visibility_row_num_range.max-visible_row_num_range.max); + S64 new_num = (S64)scroll_pt->idx + 1 + min_delta + max_delta; + new_num = clamp_1s64(global_vnum_range, new_num); + if(new_num > 0) + { + U64 new_idx = (U64)(new_num - 1); + ui_scroll_pt_target_idx(scroll_pt, new_idx); + } + } + } + + ////////////////////////////// + //- rjf: apply cursor/mark rugpull change + // + B32 cursor_rugpull = 0; + if(!rd_watch_pt_match(ewv->cursor, ewv->next_cursor)) + { + cursor_rugpull = 1; + ewv->cursor = ewv->next_cursor; + ewv->mark = ewv->next_mark; + } + + ////////////////////////// + //- rjf: grab next event, if any - otherwise exit the loop, as we now have + // the most up-to-date state + // + B32 next_event_good = ui_next_event(&event); + if(!cursor_rugpull && (!next_event_good || !ui_is_focus_active())) + { + break; + } + UI_Event dummy_evt = zero_struct; + UI_Event *evt = &dummy_evt; + if(next_event_good) + { + evt = event; + } + B32 taken = 0; + + ////////////////////////////// + //- rjf: consume query-completion events, if this view is being used as a lister + // + { + if(evt->kind == UI_EventKind_Press && + evt->slot == UI_EventActionSlot_Accept && + selection_tbl.min.y == selection_tbl.max.y && + (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg)) + { + RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); + RD_Cfg *cmd = rd_cfg_child_from_string(query, str8_lit("cmd")); + String8 cmd_name = cmd->first->string; + + // rjf: if we have no selection, just pick the first row + EV_Row *row = 0; + if(selection_tbl.min.y == 0 && selection_tbl.max.y == 0) + { + row = ev_row_from_num(scratch.arena, eval_view, &block_ranges, 1); + } + + // rjf: if we do have a selection, compute that row + else + { + row = ev_row_from_num(scratch.arena, eval_view, &block_ranges, selection_tbl.min.y); + } + + // rjf: use row to complete query + if(row->eval.expr != &e_expr_nil) + { + taken = 1; + E_Eval eval = row->eval; + + // rjf: if we have a specific command we are trying to complete, then + // fill registers based on this row's evaluation. + if(cmd_name.size != 0) switch(eval.space.kind) + { + default: + { + U64 vaddr = eval.value.u64; + CTRL_Entity *process = rd_ctrl_entity_from_eval_space(eval.space); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + U64 voff = ctrl_voff_from_vaddr(module, vaddr); + { + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); + String8 name = {0}; + if(name.size == 0) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); + name.str = rdi_name_from_procedure(rdi, procedure, &name.size); + } + if(name.size == 0) + { + RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); + name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &name.size); + } + if(name.size != 0) + { + rd_cmd(RD_CmdKind_CompleteQuery, .string = name); + } + di_scope_close(scope); + } + }break; + case E_SpaceKind_File: + case E_SpaceKind_FileSystem: + { + E_Type *type = e_type_from_key(eval.irtree.type_key); + String8 file = rd_file_path_from_eval(scratch.arena, eval); + if(str8_match(type->name, str8_lit("folder"), 0)) + { + String8 new_input_string = push_str8f(scratch.arena, "%S/", file); + rd_cmd(RD_CmdKind_UpdateQuery, .string = new_input_string); + } + else + { + rd_cmd(RD_CmdKind_CompleteQuery, .file_path = file); + } + }break; + case RD_EvalSpaceKind_MetaCfg: + { + RD_Cfg *cfg = rd_cfg_from_eval_space(eval.space); + rd_cmd(RD_CmdKind_CompleteQuery, .cfg = cfg->id); + }break; + case RD_EvalSpaceKind_MetaCtrlEntity: + { + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); + RD_RegsScope(.ctrl_entity = entity->handle) + { + if(0){} + else if(entity->kind == CTRL_EntityKind_Thread) { rd_regs()->thread = entity->handle; } + else if(entity->kind == CTRL_EntityKind_Module) { rd_regs()->module = entity->handle; } + else if(entity->kind == CTRL_EntityKind_Process) { rd_regs()->process = entity->handle; } + else if(entity->kind == CTRL_EntityKind_Machine) { rd_regs()->machine = entity->handle; } + rd_cmd(RD_CmdKind_CompleteQuery); + } + }break; + case RD_EvalSpaceKind_MetaUnattachedProcess: + { + U64 pid = eval.value.u128.u64[0]; + rd_cmd(RD_CmdKind_CompleteQuery, .pid = pid); + }break; + case RD_EvalSpaceKind_MetaCmd: + { + String8 cmd_name = rd_cmd_name_from_eval(eval); + rd_cmd(RD_CmdKind_CompleteQuery, .cmd_name = cmd_name); + }break; + case RD_EvalSpaceKind_MetaTheme: + { + String8 name = e_string_from_id(eval.value.u64); + rd_cmd(RD_CmdKind_CompleteQuery, .string = name); + }break; + } + + // rjf: if we do not have a specific command, then we can just + // pick a sensible default based on what was selected. + if(cmd_name.size == 0) + { + B32 did_cmd = 1; + switch(eval.space.kind) + { + default: + { + String8 name = {0}; + { + U64 vaddr = eval.value.u64; + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + U64 voff = ctrl_voff_from_vaddr(module, vaddr); + { + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); + if(name.size == 0) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); + name.str = rdi_name_from_procedure(rdi, procedure, &name.size); + } + if(name.size == 0) + { + RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); + name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &name.size); + } + di_scope_close(scope); + } + } + if(name.size != 0) + { + rd_cmd(RD_CmdKind_GoToName, .string = name); + } + else + { + rd_cmd(RD_CmdKind_PushQuery, .expr = e_string_from_expr(scratch.arena, eval.expr, str8_zero())); + } + }break; + case E_SpaceKind_File: + case E_SpaceKind_FileSystem: + { + String8 file = rd_file_path_from_eval(scratch.arena, eval); + rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = file, .vaddr = 0); + }break; + case RD_EvalSpaceKind_MetaCfg: + { + RD_Cfg *cfg = rd_cfg_from_eval_space(eval.space); + if(str8_match(cfg->string, str8_lit("recent_file"), 0)) + { + rd_cmd(RD_CmdKind_Switch, .cfg = cfg->id); + } + else if(str8_match(cfg->string, str8_lit("recent_project"), 0)) + { + rd_cmd(RD_CmdKind_OpenRecentProject, .cfg = cfg->id); + } + else if(e_type_kind_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)) == E_TypeKind_Set) + { + rd_cmd(RD_CmdKind_PushQuery, .expr = e_full_expr_string_from_key(scratch.arena, eval.key)); + } + else + { + did_cmd = 0; + } + }break; + case RD_EvalSpaceKind_MetaQuery: + { + rd_cmd(RD_CmdKind_PushQuery, .expr = e_full_expr_string_from_key(scratch.arena, eval.key)); + }break; + case RD_EvalSpaceKind_MetaUnattachedProcess: + { + U64 pid = eval.value.u128.u64[0]; + }break; + case RD_EvalSpaceKind_MetaCmd: + { + String8 cmd_name = rd_cmd_name_from_eval(eval); + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name); + }break; + case RD_EvalSpaceKind_MetaCtrlEntity: + { + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); + rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:control.%S", ctrl_string_from_handle(scratch.arena, entity->handle))); + }break; + } + if(did_cmd) + { + rd_cmd(RD_CmdKind_CompleteQuery); + } + else + { + taken = 0; + } + } + } + } + } + + ////////////////////////// + //- rjf: begin editing on some operations + // + if(!ewv->text_editing && + (evt->kind == UI_EventKind_Text || + evt->flags & UI_EventFlag_Paste || + (evt->kind == UI_EventKind_Press && evt->slot == UI_EventActionSlot_Edit)) && + selection_tbl.min.x == selection_tbl.max.x && + (selection_tbl.min.y != 0 || selection_tbl.max.y != 0)) + { + Vec2S64 selection_dim = dim_2s64(selection_tbl); + arena_clear(ewv->text_edit_arena); + ewv->text_edit_state_slots_count = u64_up_to_pow2(selection_dim.y+1); + ewv->text_edit_state_slots_count = Max(ewv->text_edit_state_slots_count, 64); + ewv->text_edit_state_slots = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState*, ewv->text_edit_state_slots_count); + EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); + EV_WindowedRowNode *row_node = rows.first; + B32 any_edits_started = 0; + for(S64 y = selection_tbl.min.y; row_node != 0 && y <= selection_tbl.max.y; y += 1, row_node = row_node->next) + { + EV_Row *row = &row_node->row; + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + S64 cell_x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, cell_x += 1) + { + if(cell_x < selection_tbl.min.x || selection_tbl.max.x < cell_x) + { + continue; + } + RD_WatchRowCellInfo cell_info = rd_info_from_watch_row_cell(scratch.arena, row, string_flags & (~EV_StringFlag_ReadOnlyDisplayRules), &row_info, cell, ui_top_font(), ui_top_font_size(), row_string_max_size_px); + if(cell_info.flags & RD_WatchCellFlag_CanEdit) + { + any_edits_started = 1; + String8 string = {0}; + if(cell_info.flags & RD_WatchCellFlag_NoEval) + { + string = cell->eval.string; + } + else + { + string = dr_string_from_fstrs(scratch.arena, &cell_info.eval_fstrs); + } + string.size = Min(string.size, sizeof(ewv->dummy_text_edit_state.input_buffer)); + RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; + U64 hash = ev_hash_from_key(pt.key); + U64 slot_idx = hash%ewv->text_edit_state_slots_count; + RD_WatchViewTextEditState *edit_state = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState, 1); + SLLStackPush_N(ewv->text_edit_state_slots[slot_idx], edit_state, pt_hash_next); + edit_state->pt = pt; + edit_state->cursor = txt_pt(1, string.size+1); + edit_state->mark = txt_pt(1, 1); + edit_state->input_size = string.size; + MemoryCopy(edit_state->input_buffer, string.str, string.size); + edit_state->initial_size = string.size; + MemoryCopy(edit_state->initial_buffer, string.str, string.size); + } + } + } + ewv->text_editing = any_edits_started; + } + + ////////////////////////// + //- rjf: [table] do cell-granularity multi-cursor 'accept' operations (expansions / etc.); if + // cannot apply to multi-cursor, then just don't take the event + // + if(!ewv->text_editing && evt->slot == UI_EventActionSlot_Accept && + (selection_tbl.min.y != 0 || selection_tbl.max.y != 0) && + (selection_tbl.max.y - selection_tbl.min.y > 0)) + { + EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); + EV_WindowedRowNode *row_node = rows.first; + if(row_node != 0) + { + taken = 1; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row_node != 0; y += 1, row_node = row_node->next) + { + // rjf: unpack row info + EV_Row *row = &row_node->row; + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + + // rjf: loop through X selections and perform operations for each + for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) + { +#if 0 // TODO(rjf): @cfg (multicursor watch window press operations) + //- rjf: determine operation for this cell + typedef enum OpKind + { + OpKind_Null, + OpKind_DoExpand, + } + OpKind; + OpKind kind = OpKind_Null; + switch(row_kind) + { + default:{}break; + case RD_WatchViewRowKind_Normal: + { + RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); + switch(col->kind) + { + default:{}break; + case RD_WatchViewColumnKind_Expr: {kind = OpKind_DoExpand;}break; + } + }break; + case RD_WatchViewRowKind_PrettyEntityControls: + if((!rd_entity_is_nil(row_info.collection_entity) || row_info.collection_ctrl_entity != &ctrl_entity_nil) && selection_tbl.min.x == 1 && selection_tbl.max.x == 1) + { + kind = OpKind_DoExpand; + }break; + } + + //- rjf: perform operation + switch(kind) + { + default:{taken = 0;}break; + case OpKind_DoExpand: + if(ev_row_is_expandable(row)) + { + B32 is_expanded = ev_expansion_from_key(eval_view, row->key); + ev_key_set_expansion(eval_view, row->block->key, row->key, !is_expanded); + }break; + } +#endif + } + } + } + } + + ////////////////////////// + //- rjf: [text] apply textual edits + // + if(ewv->text_editing) + { + B32 editing_complete = ((evt->kind == UI_EventKind_Press && (evt->slot == UI_EventActionSlot_Cancel || evt->slot == UI_EventActionSlot_Accept)) || + (evt->kind == UI_EventKind_Navigate && evt->delta_2s32.y != 0) || + cursor_rugpull); + rd_state->text_edit_mode = 1; + if(editing_complete || + ((evt->kind == UI_EventKind_Edit || + evt->kind == UI_EventKind_Navigate || + evt->kind == UI_EventKind_Text) && + evt->delta_2s32.y == 0)) + { + taken = 1; + EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); + EV_WindowedRowNode *row_node = rows.first; + for(S64 y = selection_tbl.min.y; row_node != 0 && y <= selection_tbl.max.y; y += 1, row_node = row_node->next) + { + EV_Row *row = &row_node->row; + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + S64 cell_x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, cell_x += 1) + { + if(cell_x < selection_tbl.min.x || selection_tbl.max.x < cell_x) + { + continue; + } + RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; + RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt); + String8 string = str8(edit_state->input_buffer, edit_state->input_size); + UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); + + // rjf: copy + if(op.flags & UI_TxtOpFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y) + { + os_set_clipboard_text(op.copy); + } + + // rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op + if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) + { + String8 autocomplete_string = ui_autocomplete(); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; + String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_string); + new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size); + MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); + edit_state->input_size = new_string.size; + edit_state->cursor = edit_state->mark = txt_pt(1, 1+autocomp_cursor_info->replaced_range.min+autocomplete_string.size); + string = str8(edit_state->input_buffer, edit_state->input_size); + op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); + } + + // rjf: cancel? -> revert to initial string + if(editing_complete && evt->slot == UI_EventActionSlot_Cancel) + { + string = str8(edit_state->initial_buffer, edit_state->initial_size); + } + + // rjf: obtain edited string + String8 new_string = string; + if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) + { + new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(op.range.min.column, op.range.max.column), op.replace); + } + + // rjf: commit to edit state + new_string.size = Min(new_string.size, sizeof(edit_state->input_buffer)); + MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); + edit_state->input_size = new_string.size; + edit_state->cursor = op.cursor; + edit_state->mark = op.mark; + + // rjf: commit edited cell string - first try to commit eval value, if that path is + // enabled on this cell, next try to commit expression string, if that path is enabled + if(cell->kind == RD_WatchCellKind_Eval) + { + if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) + { + RD_Cfg *cfg = row_info.group_cfg_child; + String8 child_key = {0}; // str8_lit("expression"); + if(cfg == &rd_nil_cfg && editing_complete && new_string.size != 0) + { + RD_Cfg *new_cfg_parent = row_info.group_cfg_parent; + if(new_cfg_parent != &rd_nil_cfg) + { + child_key = str8_zero(); + } + if(new_cfg_parent == &rd_nil_cfg) + { + RD_CfgList all_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, row_info.group_cfg_name); + new_cfg_parent = rd_cfg_list_last(&all_cfgs)->parent; + } + if(new_cfg_parent == &rd_nil_cfg) + { + new_cfg_parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + } + cfg = rd_cfg_new(new_cfg_parent, row_info.group_cfg_name); + state_dirty = 1; + snap_to_cursor = 1; + } + if(cfg != &rd_nil_cfg) + { + RD_Cfg *expr = child_key.size != 0 ? rd_cfg_child_from_string_or_alloc(cfg, child_key) : cfg; + rd_cfg_new_replace(expr, new_string); + } + } + else + { + B32 should_commit_asap = editing_complete; + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg) + { + should_commit_asap = 1; + } + else if(evt->slot != UI_EventActionSlot_Cancel) + { + should_commit_asap = editing_complete; + } + if(should_commit_asap) + { + B32 success = 0; + success = rd_commit_eval_value_string(cell->eval, new_string); + state_dirty = 1; + if(!success) + { + log_user_error(str8_lit("Could not commit value successfully.")); + } + } + } + } + } + } + } + if(editing_complete) + { + ewv->text_editing = 0; + } + } + + ////////////////////////// + //- rjf: [table] do cell-granularity copies + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Copy) + { + taken = 1; + String8List strs = {0}; + EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); + EV_WindowedRowNode *row_node = rows.first; + for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row_node != 0; y += 1, row_node = row_node->next) + { + EV_Row *row = &row_node->row; + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + S64 cell_x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, cell_x += 1) + { + if(cell_x < selection_tbl.min.x || selection_tbl.max.x < cell_x) + { + continue; + } + RD_WatchRowCellInfo cell_info = rd_info_from_watch_row_cell(scratch.arena, row, string_flags, &row_info, cell, ui_top_font(), ui_top_font_size(), row_string_max_size_px); + String8List cell_strings = {0}; + str8_list_push(scratch.arena, &cell_strings, dr_string_from_fstrs(scratch.arena, &cell_info.expr_fstrs)); + str8_list_push(scratch.arena, &cell_strings, dr_string_from_fstrs(scratch.arena, &cell_info.eval_fstrs)); + String8 cell_string = str8_list_join(scratch.arena, &cell_strings, &(StringJoin){.sep = str8_lit(" ")}); + cell_string = str8_skip_chop_whitespace(cell_string); + U64 comma_pos = str8_find_needle(cell_string, 0, str8_lit(","), 0); + if(selection_tbl.min.x != selection_tbl.max.x || selection_tbl.min.y != selection_tbl.max.y) + { + str8_list_pushf(scratch.arena, &strs, "%s%S%s%s", + comma_pos < cell_string.size ? "\"" : "", + cell_string, + comma_pos < cell_string.size ? "\"" : "", + cell_x+1 <= selection_tbl.max.x ? "," : ""); + } + else + { + str8_list_push(scratch.arena, &strs, cell_string); + } + } + if(y+1 <= selection_tbl.max.y) + { + str8_list_push(scratch.arena, &strs, str8_lit("\n")); + } + } + String8 string = str8_list_join(scratch.arena, &strs, 0); + os_set_clipboard_text(string); + } + + ////////////////////////// + //- rjf: [table] do cell-granularity deletions + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Delete) + { + taken = 1; + state_dirty = 1; + snap_to_cursor = 1; + RD_CfgList cfgs_to_remove = {0}; + RD_WatchPt next_cursor_pt = {0}; + B32 next_cursor_set = 0; + EV_WindowedRowList rows = ev_rows_from_num_range(scratch.arena, eval_view, &block_ranges, r1u64(selection_tbl.min.y, selection_tbl.max.y+1)); + EV_WindowedRowNode *row_node = rows.first; + for(S64 y = selection_tbl.min.y; row_node != 0 && y <= selection_tbl.max.y; y += 1, row_node = row_node->next) + { + EV_Row *row = &row_node->row; + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + S64 cell_x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, cell_x += 1) + { + if(cell_x < selection_tbl.min.x || selection_tbl.max.x < cell_x) + { + continue; + } + RD_WatchPt pt = {row->block->key, row->key, rd_id_from_watch_cell(cell)}; + if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) + { + RD_Cfg *cfg = row_info.group_cfg_child; + if(cfg != &rd_nil_cfg) + { + rd_cfg_list_push(scratch.arena, &cfgs_to_remove, cfg); + U64 deleted_num = ev_block_num_from_id(row->block, row->key.child_id); + if(deleted_num != 0) + { + EV_Key parent_key = row->block->parent->key; + EV_Key key = row->block->key; + U64 fallback_id_prev = ev_block_id_from_num(row->block, deleted_num-1); + U64 fallback_id_next = ev_block_id_from_num(row->block, deleted_num+1); + if(fallback_id_next != 0) + { + parent_key = row->block->key; + key = ev_key_make(row->key.parent_hash, fallback_id_next); + } + else if(fallback_id_prev != 0) + { + parent_key = row->block->key; + key = ev_key_make(row->key.parent_hash, fallback_id_prev); + } + RD_WatchPt new_pt = {parent_key, key, pt.cell_id}; + next_cursor_pt = new_pt; + next_cursor_set = 1; + state_dirty = 1; + } + } + } + else + { + rd_commit_eval_value_string(cell->eval, str8_zero()); + } + } + } + for(RD_CfgNode *n = cfgs_to_remove.first; n != 0; n = n->next) + { + rd_cfg_release(n->v); + } + if(next_cursor_set) + { + ewv->cursor = ewv->mark = ewv->next_cursor = ewv->next_mark = next_cursor_pt; + } + } + + ////////////////////////// + //- rjf: [table] apply deltas to cursor & mark + // + if(!ewv->text_editing && !(evt->flags & UI_EventFlag_Delete) && !(evt->flags & UI_EventFlag_Reorder)) + { + B32 cursor_tbl_min_is_empty_selection[Axis2_COUNT] = {0, 1}; + Vec2S32 delta = evt->delta_2s32; + if(evt->flags & UI_EventFlag_PickSelectSide && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) + { + if(delta.x > 0 || delta.y > 0) + { + cursor_tbl.x = selection_tbl.max.x; + cursor_tbl.y = selection_tbl.max.y; + } + else if(delta.x < 0 || delta.y < 0) + { + cursor_tbl.x = selection_tbl.min.x; + cursor_tbl.y = selection_tbl.min.y; + } + } + if(evt->flags & UI_EventFlag_ZeroDeltaOnSelect && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) + { + MemoryZeroStruct(&delta); + } + B32 moved = 1; + switch(evt->delta_unit) + { + default:{moved = 0;}break; + case UI_EventDeltaUnit_Char: + { + for EachEnumVal(Axis2, axis) + { + cursor_tbl.v[axis] += delta.v[axis]; + if(cursor_tbl.v[axis] < cursor_tbl_range.min.v[axis]) + { + cursor_tbl.v[axis] = cursor_tbl_range.max.v[axis]; + } + if(cursor_tbl.v[axis] > cursor_tbl_range.max.v[axis]) + { + cursor_tbl.v[axis] = cursor_tbl_range.min.v[axis]; + } + cursor_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), cursor_tbl.v[axis]); + } + }break; + case UI_EventDeltaUnit_Word: + case UI_EventDeltaUnit_Line: + case UI_EventDeltaUnit_Page: + { + cursor_tbl.x = (delta.x>0 ? (cursor_tbl_range.max.x) : + delta.x<0 ? (cursor_tbl_range.min.x + !!cursor_tbl_min_is_empty_selection[Axis2_X]) : + cursor_tbl.x); + cursor_tbl.y += ((delta.y>0 ? +(num_possible_visible_rows-3) : + delta.y<0 ? -(num_possible_visible_rows-3) : + 0)); + cursor_tbl.y = clamp_1s64(r1s64(cursor_tbl_range.min.y + !!cursor_tbl_min_is_empty_selection[Axis2_Y], + cursor_tbl_range.max.y), + cursor_tbl.y); + }break; + case UI_EventDeltaUnit_Whole: + { + for EachEnumVal(Axis2, axis) + { + cursor_tbl.v[axis] = (delta.v[axis]>0 ? cursor_tbl_range.max.v[axis] : delta.v[axis]<0 ? cursor_tbl_range.min.v[axis] + !!cursor_tbl_min_is_empty_selection[axis] : cursor_tbl.v[axis]); + } + }break; + } + if(moved) + { + taken = 1; + cursor_dirty__tbl = 1; + snap_to_cursor = 1; + } + } + + ////////////////////////// + //- rjf: [table] stick table mark to cursor if needed + // + if(!ewv->text_editing) + { + if(taken && !(evt->flags & UI_EventFlag_KeepMark)) + { + mark_tbl = cursor_tbl; + } + } + + ////////////////////////// + //- rjf: [table] do cell-granularity reorders + // + if(!ewv->text_editing && evt->flags & UI_EventFlag_Reorder) + { + taken = 1; + if(filter.size == 0) + { + // rjf: determine blocks of each endpoint of the table selection + EV_Block *selection_endpoint_blocks[2] = + { + ev_block_range_from_num(&block_ranges, selection_tbl.min.y).block, + ev_block_range_from_num(&block_ranges, selection_tbl.max.y).block, + }; + + // rjf: pick shallowest block within which we can do reordering + U64 selection_depths[2] = + { + ev_depth_from_block(selection_endpoint_blocks[0]), + ev_depth_from_block(selection_endpoint_blocks[1]), + }; + EV_Block *selection_block = (selection_depths[1] < selection_depths[0] + ? selection_endpoint_blocks[1] + : selection_endpoint_blocks[0]); + + // rjf: find selection keys within the block in which we are doing reordering + EV_Key selection_keys_in_block[2] = {0}; + { + for EachElement(idx, selection_endpoint_blocks) + { + EV_Block *endpoint_block = selection_endpoint_blocks[idx]; + if(endpoint_block == selection_block) + { + selection_keys_in_block[idx] = ev_key_from_num(&block_ranges, selection_tbl.v[idx].y); + } + else + { + for(;endpoint_block->parent != selection_block && endpoint_block != &ev_nil_block;) + { + endpoint_block = endpoint_block->parent; + } + if(endpoint_block->parent == selection_block) + { + selection_keys_in_block[idx] = endpoint_block->key; + } + } + } + EV_Key fallback_key = {0}; + for EachElement(idx, selection_endpoint_blocks) + { + if(!ev_key_match(selection_keys_in_block[idx], ev_key_zero())) + { + fallback_key = selection_keys_in_block[idx]; + } + } + for EachElement(idx, selection_endpoint_blocks) + { + if(ev_key_match(selection_keys_in_block[idx], ev_key_zero())) + { + selection_keys_in_block[idx] = fallback_key; + } + } + } + + // rjf: determine collection info for the block + String8 group_cfg_name = {0}; + { + E_IRTreeAndType block_irtree = selection_block->eval.irtree; + E_TypeKey block_type_key = e_type_key_unwrap(block_irtree.type_key, E_TypeUnwrapFlag_AllDecorative); + E_TypeKind block_type_kind = e_type_kind_from_key(block_type_key); + if(block_type_kind == E_TypeKind_Set) + { + E_Type *block_type = e_type_from_key(block_type_key); + group_cfg_name = rd_singular_from_code_name_plural(block_type->name); + if(group_cfg_name.size == 0) + { + group_cfg_name = block_type->name; + } + } + } + + // rjf: map selection endpoints to cfgs + RD_Cfg *first_cfg = &rd_nil_cfg; + RD_Cfg *last_cfg = &rd_nil_cfg; + if(group_cfg_name.size != 0) + { + first_cfg = rd_cfg_from_id(selection_keys_in_block[0].child_id); + last_cfg = rd_cfg_from_id(selection_keys_in_block[1].child_id); + } + + // rjf: reorder + if(first_cfg != &rd_nil_cfg && last_cfg != &rd_nil_cfg) + { + RD_Cfg *first_cfg_prev = &rd_nil_cfg; + RD_Cfg *last_cfg_next = &rd_nil_cfg; + for(RD_Cfg *prev = first_cfg->prev; prev != &rd_nil_cfg; prev = prev->prev) + { + if(str8_match(prev->string, first_cfg->string, 0)) + { + first_cfg_prev = prev; + break; + } + } + for(RD_Cfg *next = last_cfg->next; next != &rd_nil_cfg; next = next->next) + { + if(str8_match(next->string, last_cfg->string, 0)) + { + last_cfg_next = next; + break; + } + } + if(evt->delta_2s32.y < 0 && first_cfg != &rd_nil_cfg && first_cfg_prev != &rd_nil_cfg) + { + state_dirty = 1; + snap_to_cursor = 1; + RD_Cfg *parent = first_cfg_prev->parent; + rd_cfg_unhook(parent, first_cfg_prev); + rd_cfg_insert_child(parent, last_cfg, first_cfg_prev); + } + if(evt->delta_2s32.y > 0 && last_cfg != &rd_nil_cfg && last_cfg_next != &rd_nil_cfg) + { + state_dirty = 1; + snap_to_cursor = 1; + RD_Cfg *parent = last_cfg_next->parent; + rd_cfg_unhook(parent, last_cfg_next); + rd_cfg_insert_child(parent, first_cfg_prev, last_cfg_next); + } + } + } + } + + ////////////////////////// + //- rjf: consume event, if taken + // + if(taken && evt != &dummy_evt) + { + ui_eat_event(evt); + } + } + } + + ////////////////////////////// + //- rjf: autocomplete watches -> feed autocompletion info forward + // + if(rd_watch_pt_match(ewv->cursor, ewv->mark) && + rd_cfg_child_from_string(view, str8_lit("autocomplete")) != &rd_nil_cfg) + { + U64 row_num = ev_num_from_key(&block_ranges, ewv->cursor.key); + EV_Row *row = ev_row_from_num(scratch.arena, rd_view_eval_view(), &block_ranges, row_num); + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + RD_WatchCell *cell = row_info.cells.first; + if(cell != 0) + { + RD_WatchRowCellInfo cell_info = rd_info_from_watch_row_cell(scratch.arena, row, 0, &row_info, cell, ui_top_font(), ui_top_font_size(), dim_2f32(rect).y); + String8 string = dr_string_from_fstrs(ui_build_arena(), &cell_info.eval_fstrs); + if(string.size != 0) + { + ui_set_autocomplete_string(string); + } + } + } + + ////////////////////////////// + //- rjf: build ui + // + B32 pressed = 0; + ProfScope("build ui") + { + Vec2F32 rect_dim = dim_2f32(rect); + F32 contents_width_px = (rect_dim.x - floor_f32(ui_bottom_font_size()*1.5f)); + Rng1S64 visible_row_rng = {0}; + UI_ScrollListParams scroll_list_params = {0}; + { + scroll_list_params.flags = UI_ScrollListFlag_All; + scroll_list_params.row_height_px = row_height_px; + scroll_list_params.dim_px = rect_dim; + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, 0)); + scroll_list_params.item_range = r1s64(0, block_tree.total_row_count - !!implicit_root); + scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; + scroll_list_params.row_blocks = row_blocks; + } + UI_BoxFlags disabled_flags = ui_top_flags(); + if(d_ctrl_targets_running()) + { + disabled_flags |= UI_BoxFlag_Disabled; + } + UI_ScrollListSignal scroll_list_sig = {0}; + UI_Focus(UI_FocusKind_On) + UI_ScrollList(&scroll_list_params, &scroll_pos.y, + 0, + 0, + &visible_row_rng, + &scroll_list_sig) + UI_Focus(UI_FocusKind_Null) + { + ui_set_next_pref_height(ui_children_sum(1)); + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *table = ui_build_box_from_string(0, str8_lit("table")); + UI_Parent(table) + { + Vec2F32 scroll_list_view_off_px = ui_top_parent()->parent->view_off; + + //////////////////////// + //- rjf: viz blocks -> rows + // + EV_WindowedRowList rows = {0}; + { + rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, &block_ranges, r1u64(visible_row_rng.min+1, visible_row_rng.max+2)); + } + + //////////////////////// + //- rjf: rows -> row infos + // + RD_WatchRowInfo *row_infos = push_array(scratch.arena, RD_WatchRowInfo, rows.count); + { + U64 idx = 0; + for(EV_WindowedRowNode *row_node = rows.first; row_node != 0; row_node = row_node->next, idx += 1) + { + EV_Row *row = &row_node->row; + row_infos[idx] = rd_watch_row_info_from_row(scratch.arena, row); + } + } + + //////////////////////// + //- rjf: build boundaries + // + B32 cell_pcts_are_dirty = 0; + ProfScope("build boundaries") + { + U64 idx = 0; + U64 boundary_start_idx = 0; + EV_Row *last_row = 0; + RD_WatchRowInfo *last_row_info = 0; + for(EV_WindowedRowNode *row_node = rows.first;; row_node = row_node->next, idx += 1) + { + //- rjf: determine if this row breaks the topology + B32 is_new_topology = (row_node == 0); + if(row_node != 0 && last_row_info != 0) + { + EV_Row *row = &row_node->row; + RD_WatchRowInfo *row_info = &row_infos[idx]; + for(RD_WatchCell *last_cell = last_row_info->cells.first, *this_cell = row_info->cells.first;; + last_cell = last_cell->next, this_cell = this_cell->next) + { + if(last_cell == 0 && this_cell == 0) + { + break; + } + if((last_cell == 0 && this_cell != 0) || (last_cell != 0 && this_cell == 0)) + { + is_new_topology = 1; + break; + } + if(rd_id_from_watch_cell(last_cell) != rd_id_from_watch_cell(this_cell)) + { + is_new_topology = 1; + break; + } + } + } + + //- rjf: if we reached a new topology, or the end -> build boundaries for all cell separations + if(is_new_topology) + { + EV_Row *row = last_row; + RD_WatchRowInfo *row_info = last_row_info; + F32 row_width_px = contents_width_px; + if(row_info != 0) + { + U64 row_hash = ev_hash_from_key(row->key); + F32 cell_x_px = 0; + U64 cell_idx = 0; + for(RD_WatchCell *cell = row_info->cells.first; cell != 0 && cell->next != 0; cell = cell->next, cell_idx += 1) + { + if(cell->pct == 0 || cell->next->pct == 0) + { + continue; + } + U64 cell_id = rd_id_from_watch_cell(cell); + F32 cell_width_px = cell->px + cell->pct * row_width_px; + F32 next_cell_x_px = cell_x_px + cell_width_px; + { + Rng2F32 rect = r2f32p(next_cell_x_px - ui_top_font_size()*0.4f, + boundary_start_idx*row_height_px, + next_cell_x_px + ui_top_font_size()*0.4f, + idx*row_height_px); + UI_Rect(rect) UI_HoverCursor(OS_Cursor_LeftRight) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_Floating, "boundary_%I64x_%I64x", row_hash, cell_id); + UI_Signal sig = ui_signal_from_box(box); + if(ui_dragging(sig)) + { + typedef struct DragData DragData; + struct DragData + { + F32 min_pct; + F32 max_pct; + }; + if(ui_pressed(sig)) + { + DragData drag_data = {cell->pct, cell->next->pct}; + ui_store_drag_struct(&drag_data); + } + DragData *drag_data = ui_get_drag_struct(DragData); + F32 min_pct__pre = drag_data->min_pct; + F32 max_pct__pre = drag_data->max_pct; + F32 min_px__pre = min_pct__pre*row_width_px; + F32 max_px__pre = max_pct__pre*row_width_px; + F32 min_px__post = min_px__pre + ui_drag_delta().x; + F32 max_px__post = max_px__pre - ui_drag_delta().x; + F32 min_pct__post = min_px__post/row_width_px; + F32 max_pct__post = max_px__post/row_width_px; + if(min_pct__post < 0.05f) + { + min_pct__post = 0.05f; + max_pct__post = (min_pct__pre + max_pct__pre) - min_pct__post; + } + if(max_pct__post < 0.05f) + { + max_pct__post = 0.05f; + min_pct__post = (min_pct__pre + max_pct__pre) - max_pct__post; + } + if(ui_double_clicked(sig)) + { + F32 default_sum = cell->default_pct + cell->next->default_pct; + F32 current_sum = min_pct__pre + max_pct__pre;; + min_pct__post = current_sum * (cell->default_pct / default_sum); + max_pct__post = current_sum * (cell->next->default_pct / default_sum); + ui_kill_action(); + } + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string_or_alloc(view, row_info->cell_style_key); + RD_Cfg *min_cfg = &rd_nil_cfg; + RD_Cfg *max_cfg = &rd_nil_cfg; + { + RD_Cfg *pct_child = style->first; + U64 c_idx = 0; + for(RD_WatchCell *c = row_info->cells.first; c != 0; c = c->next, c_idx += 1) + { + if(pct_child == &rd_nil_cfg) + { + pct_child = rd_cfg_newf(style, "%f", c->pct); + } + if(c_idx == cell_idx) + { + min_cfg = pct_child; + } + if(c_idx == cell_idx+1) + { + max_cfg = pct_child; + } + pct_child = pct_child->next; + } + rd_cfg_equip_stringf(min_cfg, "%f", min_pct__post); + rd_cfg_equip_stringf(max_cfg, "%f", max_pct__post); + cell_pcts_are_dirty = 1; + } + } + } + } + cell_x_px = next_cell_x_px; + } + } + boundary_start_idx = idx; + } + + //- rjf: advance + if(row_node == 0) + { + break; + } + else + { + last_row = &row_node->row; + last_row_info = &row_infos[idx]; + } + } + } + + //////////////////////// + //- rjf: if cell widths are dirty -> recompute row infos + // + if(cell_pcts_are_dirty) + { + U64 idx = 0; + for(EV_WindowedRowNode *row_node = rows.first; row_node != 0; row_node = row_node->next, idx += 1) + { + EV_Row *row = &row_node->row; + row_infos[idx] = rd_watch_row_info_from_row(scratch.arena, row); + } + } + + //////////////////////// + //- rjf: do drag/drops + // + if(rd_drag_is_active()) + { + Vec2F32 rect_dim = dim_2f32(rect); + ui_set_next_rect(r2f32p(0, 0, rect_dim.x, rect_dim.y)); + UI_Box *drop_target = ui_build_box_from_stringf(UI_BoxFlag_DropSite|UI_BoxFlag_Floating, "watch_%I64x_drop", rd_regs()->view); + UI_Signal sig = ui_signal_from_box(drop_target); + if(ui_key_match(ui_drop_hot_key(), drop_target->key)) + { + Vec2F32 drag_pos = sub_2f32(ui_mouse(), rect.p0); + RD_RegSlot drag_slot = rd_state->drag_drop_regs_slot; + RD_Regs *drag_regs = rd_state->drag_drop_regs; + + //- rjf: obtain best fit for target block & prev-row for this drag + EV_Block *drag_block = &ev_nil_block; + U64 best_prev_row_block_num = 0; + F32 best_prev_row_y = 0; + { + F32 best_prev_row_distance = inf32(); + U64 local_row_idx = 0; + F32 row_y = 0; + for(EV_WindowedRowNode *row_node = rows.first; row_node != 0; row_node = row_node->next, local_row_idx += 1) + { + // rjf: unpack row + EV_Row *row = &row_node->row; + F32 row_height = row_height_px*row->visual_size; + RD_WatchRowInfo *row_info = &row_infos[local_row_idx]; + E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key); + + // rjf: determine if this row's block is good for the current drag/drop + B32 block_is_good_for_drop = 0; + if(drag_slot == RD_RegSlot_Expr && block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches)) + { + block_is_good_for_drop = (drag_regs->cfg == 0 || (drag_regs->cfg != row_info->group_cfg_child->id)); + } + + // rjf: if this block is good, then test this row/block & grab if appropriate + if(block_is_good_for_drop) + { + if(drag_block == &ev_nil_block && row_y <= drag_pos.y && drag_pos.y <= row_y + row_height) + { + drag_block = row->block; + } + F32 row_distance = abs_f32(drag_pos.y - row_y); + if(row_distance <= best_prev_row_distance) + { + U64 row_num = ev_block_num_from_id(row->block, row->key.child_id); + best_prev_row_block_num = row_num-1; + best_prev_row_distance = row_distance; + best_prev_row_y = row_y; + drag_block = row->block; + } + } + row_y += row_height; + } + } + + //- rjf: unpack block/previous row info + B32 drag_target_is_good = 0; + RD_Cfg *drag_parent_cfg = &rd_nil_cfg; + RD_Cfg *drag_prev_cfg = &rd_nil_cfg; + if(drag_block != &ev_nil_block) + { + EV_Key prev_row_key = ev_key_make(ev_hash_from_key(drag_block->key), ev_block_id_from_num(drag_block, best_prev_row_block_num)); + U64 prev_row_num = ev_num_from_key(&block_ranges, prev_row_key); + EV_Row *prev_row = ev_row_from_num(scratch.arena, eval_view, &block_ranges, prev_row_num); + RD_WatchRowInfo prev_row_info = rd_watch_row_info_from_row(scratch.arena, prev_row); + drag_parent_cfg = rd_cfg_from_eval_space(drag_block->eval.space); + drag_prev_cfg = prev_row_info.group_cfg_child; + if(drag_regs->cfg == 0 || drag_prev_cfg->id != drag_regs->cfg) + { + drag_target_is_good = 1; + } + } + + //- rjf: drop + if(drag_target_is_good && rd_drag_drop() && drag_parent_cfg != &rd_nil_cfg) + { + switch(drag_slot) + { + default:{}break; + case RD_RegSlot_Expr: + { + RD_Cfg *cfg = rd_cfg_from_id(drag_regs->cfg); + if(cfg != &rd_nil_cfg) + { + rd_cfg_unhook(cfg->parent, cfg); + } + if(cfg == &rd_nil_cfg) + { + cfg = rd_cfg_alloc(); + rd_cfg_equip_stringf(cfg, "watch"); + rd_cfg_new(cfg, drag_regs->expr); + } + rd_cfg_insert_child(drag_parent_cfg, drag_prev_cfg, cfg); + }break; + } + } + + //- rjf: draw drop position + if(drag_target_is_good) + { + DR_Bucket *bucket = dr_bucket_make(); + DR_BucketScope(bucket) UI_TagF("pop") + { + Vec4F32 color = ui_color_from_name(str8_lit("background")); + Rng2F32 drop_line_rect = r2f32p(rect.x0, + rect.y0 + best_prev_row_y - ui_top_font_size()*0.5f, + rect.x1, + rect.y0 + best_prev_row_y + ui_top_font_size()*0.5f); + R_Rect2DInst *inst = dr_rect(drop_line_rect, color, 0, 0, 1.f); + inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, 0); + } + ui_box_equip_draw_bucket(drop_target, bucket); + } + } + } + + //////////////////////// + //- rjf: build table + // + ProfScope("build table") + { + F32 row_y_px = rect.y0; + U64 local_row_idx = 0; + U64 global_row_idx = rows.count_before_semantic; + RD_WatchRowInfo last_row_info = {0}; + for(EV_WindowedRowNode *row_node = rows.first; + row_node != 0; + (row_y_px += row_height_px * (row_node->row.visual_size), + row_node = row_node->next, + global_row_idx += 1, + local_row_idx += 1)) + { + //////////////////////// + //- rjf: unpack row info + // + ProfBegin("unpack row info"); + EV_Row *row = &row_node->row; + RD_WatchRowInfo *row_info = &row_infos[local_row_idx]; + U64 row_hash = ev_hash_from_key(row->key); + U64 row_depth = ev_depth_from_block(row->block); + B32 row_selected = (selection_tbl.min.y <= global_row_idx+1 && global_row_idx+1 <= selection_tbl.max.y); + B32 row_expanded = ev_expansion_from_key(eval_view, row->key); + B32 next_row_expanded = row_expanded; + B32 row_is_expandable = row_info->can_expand; + if(implicit_root && row_depth > 0) + { + row_depth -= 1; + } + ProfEnd(); + + //////////////////////// + //- rjf: determine if this row fits the last row's topology + // + B32 row_matches_last_row_topology = 1; + if(row_node != rows.first) + { + for(RD_WatchCell *last_cell = last_row_info.cells.first, *this_cell = row_info->cells.first;; + last_cell = last_cell->next, this_cell = this_cell->next) + { + if(last_cell == 0 && this_cell == 0) + { + break; + } + if((last_cell == 0 && this_cell != 0) || (last_cell != 0 && this_cell == 0)) + { + row_matches_last_row_topology = 0; + break; + } + if(rd_id_from_watch_cell(last_cell) != rd_id_from_watch_cell(this_cell)) + { + row_matches_last_row_topology = 0; + break; + } + } + } + + //////////////////////// + //- rjf: store last row's info, for next iteration + // + last_row_info = *row_info; + + //////////////////////// + //- rjf: determine row's flags & color palette + // + ProfBegin("determine row's flags & color palette"); + UI_BoxFlags row_flags = UI_BoxFlag_DisableFocusOverlay; + { + if(global_row_idx & 1) + { + ui_set_next_tag(str8_lit("alt")); + row_flags |= UI_BoxFlag_DrawBackground; + } + if(!row_matches_last_row_topology) + { + row_flags |= UI_BoxFlag_DrawSideTop; + } + } + ProfEnd(); + + //////////////////////// + //- rjf: build row box + // + ui_set_next_flags(disabled_flags); + ui_set_next_pref_width(ui_px(contents_width_px, 1.f)); + ui_set_next_pref_height(ui_px(row_height_px*row->visual_size, 1.f)); + ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); + UI_Box *row_box = ui_build_box_from_stringf(row_flags|((!row_node->next)*UI_BoxFlag_DrawSideBottom)|UI_BoxFlag_Clickable, "row_%I64x", row_hash); + RD_WatchRowExtrasDrawData *row_draw_data = push_array(ui_build_arena(), RD_WatchRowExtrasDrawData, 1); + row_draw_data->breaks_from_prev = !row_matches_last_row_topology; + ui_box_equip_custom_draw(row_box, rd_watch_row_extras_custom_draw, row_draw_data); + + ////////////////////// + //- rjf: build row contents + // + RD_RegsScope(.module = row_info->module->handle) UI_Parent(row_box) + { + //////////////////// + //- rjf: draw start of cache lines in expansions + // + if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && row_info->view_ui_rule == &rd_nil_view_ui_rule) + { + CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row->eval.space); + if(space_entity->kind == CTRL_EntityKind_Process) + { + U64 row_offset = row->eval.value.u64; + if((row->eval.irtree.mode == E_Mode_Offset || row->eval.irtree.mode == E_Mode_Null) && + row_offset%64 == 0 && row_depth > 0) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(0); + ui_set_next_fixed_height(ui_top_font_size()*0.2f); + ui_set_next_tag(str8_lit("pop")); + ui_build_box_from_key(UI_BoxFlag_Floating|UI_BoxFlag_DrawBackground, ui_key_zero()); + } + } + } + + ////////////// + //- rjf: draw mid-row cache line boundaries in expansions + // + if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && row_info->view_ui_rule == &rd_nil_view_ui_rule) + { + CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row->eval.space); + if(space_entity->kind == CTRL_EntityKind_Process && + (row->eval.irtree.mode == E_Mode_Offset || row->eval.irtree.mode == E_Mode_Null) && + row->eval.value.u64%64 != 0 && + row_depth > 0 && + !row_expanded) + { + U64 next_off = (row->eval.value.u64 + e_type_byte_size_from_key(row->eval.irtree.type_key)); + if(next_off%64 != 0 && row->eval.value.u64/64 < next_off/64) + { + ui_set_next_fixed_x(0); + ui_set_next_fixed_y(row_height_px - ui_top_font_size()*0.5f); + ui_set_next_fixed_height(ui_top_font_size()*1.f); + ui_set_next_tag(str8_lit("pop")); + ui_set_next_transparency(0.5f); + ui_build_box_from_key(UI_BoxFlag_Floating|UI_BoxFlag_DrawBackground, ui_key_zero()); + } + } + } + + ////////////// + //- rjf: build all cells + // + S64 cell_x = 0; + F32 cell_x_px = 0; + for(RD_WatchCell *cell = row_info->cells.first; cell != 0; cell = cell->next, cell_x += 1) + { + if(row_depth > 0) { ui_push_tagf("weak"); } + + //////////// + //- rjf: unpack cell info + // + F32 cell_width_px = cell->px + cell->pct * (dim_2f32(rect).x - floor_f32(ui_top_font_size()*1.5f)); + F32 next_cell_x_px = cell_x_px + cell_width_px; + F32 cell_width_strictness = 0.f; + if(cell->px != 0) + { + cell_width_strictness = 1.f; + } + F32 visual_row_string_max_size_px = cell_width_px * 1.5f; + if(cell->flags & RD_WatchCellFlag_Expr && !(cell->flags & RD_WatchCellFlag_NoEval)) + { + visual_row_string_max_size_px /= 2.f; + } + U64 cell_id = rd_id_from_watch_cell(cell); + RD_WatchPt cell_pt = {row->block->key, row->key, cell_id}; + RD_WatchViewTextEditState *cell_edit_state = rd_watch_view_text_edit_state_from_pt(ewv, cell_pt); + B32 cell_selected = (row_selected && selection_tbl.min.x <= cell_x && cell_x <= selection_tbl.max.x); + RD_WatchRowCellInfo cell_info = rd_info_from_watch_row_cell(scratch.arena, row, string_flags, row_info, cell, ui_top_font(), ui_top_font_size(), visual_row_string_max_size_px); + E_TypeKey cell_type_key = cell->eval.irtree.type_key; + E_Type *cell_type = e_type_from_key(cell_type_key); + E_Eval cell_value_eval = e_value_eval_from_eval(cell->eval); + B32 cell_toggled = (cell_value_eval.value.u64 != 0); + B32 next_cell_toggled = cell_toggled; + + //////////////////////// + //- rjf: determine if cell evaluation's data is fresh and/or bad + // + ProfBegin("determine if cell evaluation's data is fresh and/or bad"); + B32 cell_is_fresh = 0; + B32 cell_is_bad = 0; + if(!(cell_info.flags & RD_WatchCellFlag_NoEval)) + { + switch(cell->eval.irtree.mode) + { + default:{}break; + case E_Mode_Offset: + { + CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(cell->eval.space); + if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && space_entity->kind == CTRL_EntityKind_Process) + { + U64 size = e_type_byte_size_from_key(cell->eval.irtree.type_key); + size = Min(size, 64); + Rng1U64 vaddr_rng = r1u64(cell->eval.value.u64, cell->eval.value.u64+size); + CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, space_entity->handle, vaddr_rng, rd_state->frame_eval_memread_endt_us); + for(U64 idx = 0; idx < (slice.data.size+63)/64; idx += 1) + { + if(slice.byte_changed_flags[idx] != 0) + { + cell_is_fresh = 1; + } + if(slice.byte_bad_flags[idx] != 0) + { + cell_is_bad = 1; + } + } + } + }break; + } + } + ProfEnd(); + + //////////// + //- rjf: compute slider parameters + // + E_Value cell_slider_min = zero_struct; + E_Value cell_slider_max = zero_struct; + E_TypeKind slider_value_type_kind = E_TypeKind_Null; + F32 cell_slider_value = 0.f; + if(str8_match(cell_type->name, str8_lit("range1"), 0) && cell_type->args != 0 && cell_type->count >= 2) + { + E_Key min_key = e_key_from_expr(cell_type->args[0]); + E_Key max_key = e_key_from_expr(cell_type->args[1]); + E_ParentKey(cell->eval.key) + { + E_TypeKey slider_value_type = e_type_key_unwrap(cell_type->direct_type_key, E_TypeUnwrapFlag_AllDecorative); + slider_value_type_kind = e_type_kind_from_key(slider_value_type); + String8 slider_type_name = e_type_string_from_key(scratch.arena, slider_value_type); + cell_slider_min = e_value_from_key(e_key_wrapf(min_key, "(%S)$", slider_type_name)); + cell_slider_max = e_value_from_key(e_key_wrapf(max_key, "(%S)$", slider_type_name)); + } + } + switch(slider_value_type_kind) + { + default: + if(e_type_kind_is_integer(slider_value_type_kind)) + { + cell_slider_value = ((F32)(cell_value_eval.value.s64 - cell_slider_min.s64)) / (cell_slider_max.s64 - cell_slider_min.s64); + }break; + case E_TypeKind_F32: + { + cell_slider_value = (cell_value_eval.value.f32 - cell_slider_min.f32) / (cell_slider_max.f32 - cell_slider_min.f32); + }break; + case E_TypeKind_F64: + { + cell_slider_value = (F32)((cell_value_eval.value.f64 - cell_slider_min.f64) / (cell_slider_max.f64 - cell_slider_min.f64)); + }break; + } + F32 next_cell_slider_value = cell_slider_value; + + //////////// + //- rjf: determine cell's palette + // + Vec4F32 cell_background_color_override = {0}; + { + if(cell_info.cfg->id == rd_get_hover_regs()->cfg && + rd_state->hover_regs_slot == RD_RegSlot_Cfg) + { + RD_Cfg *cfg = cell_info.cfg; + Vec4F32 rgba = rd_color_from_cfg(cfg); + rgba.w *= 0.05f; + if(rgba.w == 0) + { + rgba = pop_background_rgba; + rgba.w *= 0.5f; + } + rgba.w *= ui_anim(ui_key_from_stringf(ui_key_zero(), "###cfg_hover_t_%p", cfg), 1.f, .rate = entity_hover_t_rate); + cell_background_color_override = rgba; + } + else if(ctrl_handle_match(cell_info.entity->handle, rd_get_hover_regs()->ctrl_entity) && + rd_state->hover_regs_slot == RD_RegSlot_CtrlEntity) + { + CTRL_Entity *entity = cell_info.entity; + Vec4F32 rgba = rd_color_from_ctrl_entity(entity); + rgba.w *= 0.05f; + if(rgba.w == 0) + { + rgba = pop_background_rgba; + rgba.w *= 0.5f; + } + rgba.w *= ui_anim(ui_key_from_stringf(ui_key_zero(), "###entity_hover_t_%p", entity), 1.f, .rate = entity_hover_t_rate); + cell_background_color_override = rgba; + } + else if(cell_is_fresh) + { + UI_TagF(".") UI_TagF("fresh") + { + cell_background_color_override = ui_color_from_name(str8_lit("background")); + } + } + else if(cell_is_bad) + { + UI_TagF(".") UI_TagF("bad_pop") + { + cell_background_color_override = ui_color_from_name(str8_lit("background")); + cell_background_color_override.w *= 0.2f; + } + } + } + + //////////// + //- rjf: build cell container + // + UI_Box *cell_box = &ui_nil_box; + UI_PrefWidth(ui_px(cell_width_px, cell_width_strictness)) + { + ui_set_next_fixed_height(floor_f32(row->visual_size * row_height_px)); + cell_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideLeft, "cell_%I64x_%I64x", row_hash, cell_id); + } + + //////////// + //- rjf: build cell contents + // + RD_Cfg *cell_view = &rd_nil_cfg; + B32 revert_cell = 0; + UI_Signal sig = {0}; + ProfScope("build cell contents") + UI_Parent(cell_box) + UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) + UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) + RD_Font(RD_FontSlot_Code) + UI_TagF("weak") + { + //- rjf: cell has hook? -> build ui by calling hook + if(cell->kind == RD_WatchCellKind_ViewUI && cell_info.view_ui_rule != &rd_nil_view_ui_rule) + { + RD_Cfg *root = rd_immediate_cfg_from_keyf("view%I64x_%I64x", rd_regs()->view, row_hash); + cell_view = rd_view_from_eval(root, cell->eval); + Rng2F32 cell_rect = r2f32p(cell_x_px, row_y_px, next_cell_x_px, row_y_px + row_height_px*(row_node->visual_size_skipped + row->visual_size + row_node->visual_size_chopped)); + ui_set_next_fixed_y(-1.f * (row_node->visual_size_skipped) * row_height_px); + ui_set_next_fixed_height((row_node->visual_size_skipped + row->visual_size + row_node->visual_size_chopped) * row_height_px); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable|UI_BoxFlag_FloatingY, "###val_%I64x", row_hash); + UI_Parent(box) + RD_RegsScope(.view = cell_view->id, .file_path = rd_file_path_from_eval(scratch.arena, cell->eval)) + UI_PermissionFlags(UI_PermissionFlag_Clicks|UI_PermissionFlag_ScrollX) + UI_Flags(0) + { + // rjf: 'pull out' button + UI_Signal pull_out_sig = {0}; + UI_TagF(".") UI_TagF("tab") UI_Rect(r2f32p(floor_f32(ui_top_font_size()*1.5f), + floor_f32(ui_top_font_size()*1.5f), + floor_f32(ui_top_font_size()*1.5f + ui_top_font_size()*3.f), + floor_f32(ui_top_font_size()*1.5f + ui_top_font_size()*3.f))) + UI_CornerRadius(floor_f32(ui_top_font_size()*1.5f)) + UI_TextAlignment(UI_TextAlign_Center) + RD_Font(RD_FontSlot_Icons) + UI_FontSize(floor_f32(ui_top_font_size()*0.9f)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_Floating| + UI_BoxFlag_DrawText| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects, + "%S###pull_out", + rd_icon_kind_text_table[RD_IconKind_Window]); + pull_out_sig = ui_signal_from_box(box); + } + if(ui_hovering(pull_out_sig)) UI_Tooltip RD_Font(RD_FontSlot_Main) + { + ui_state->tooltip_anchor_key = pull_out_sig.box->key; + ui_labelf("Pull Out As New Tab"); + } + if(ui_dragging(pull_out_sig) && !contains_2f32(pull_out_sig.box->rect, ui_mouse())) + { + rd_drag_begin(RD_RegSlot_View); + } + + // rjf: loading animation container + UI_Box *loading_overlay_container = &ui_nil_box; + UI_Parent(box) UI_WidthFill UI_HeightFill + { + loading_overlay_container = ui_build_box_from_key(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + } + + // rjf: view ui contents + E_ParentKey(cell->eval.key) + { + cell_info.view_ui_rule->ui(cell->eval, cell_rect); + } + + // rjf: loading fill + UI_Parent(loading_overlay_container) + { + RD_ViewState *vs = rd_view_state_from_cfg(cell_view); + rd_loading_overlay(cell_rect, vs->loading_t, vs->loading_progress_v, vs->loading_progress_v_target); + } + } + sig = ui_signal_from_box(box); + } + + //- rjf: cell is call stack frame? -> build arrow if this is the selected frame, otherwise leave empty + else if(cell->kind == RD_WatchCellKind_CallStackFrame) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%I64x_%I64x", cell_id, row_hash); + sig = ui_signal_from_box(box); + if(ctrl_handle_match(row_info->callstack_thread->handle, rd_base_regs()->thread) && + row_info->callstack_unwind_index == rd_base_regs()->unwind_count && + row_info->callstack_inline_depth == rd_base_regs()->inline_depth) + { + UI_Parent(box) UI_Flags(0) UI_TextAlignment(UI_TextAlign_Center) + { + Vec4F32 color = rd_color_from_ctrl_entity(row_info->callstack_thread); + RD_Font(RD_FontSlot_Icons) + UI_Flags(UI_BoxFlag_DisableTextTrunc) + UI_TextColor(color) + ui_label(rd_icon_kind_text_table[RD_IconKind_RightArrow]); + } + } + } + + //- rjf: build general cell + else + { + // rjf: compute visual params + ProfBegin("compute visual params"); + B32 cell_has_fancy_editors = (!(cell->flags & RD_WatchCellFlag_NoEval)); + B32 is_button = !!(cell_info.flags & RD_WatchCellFlag_Button); + B32 has_background = !!(cell_info.flags & RD_WatchCellFlag_Background); + B32 is_toggle_switch = (cell_has_fancy_editors && cell->eval.irtree.mode != E_Mode_Null && e_type_kind_from_key(e_type_key_unwrap(cell->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)) == E_TypeKind_Bool); + B32 is_slider = (cell_has_fancy_editors && cell->eval.irtree.mode != E_Mode_Null && cell_type->kind == E_TypeKind_Lens && str8_match(cell_type->name, str8_lit("range1"), 0)); + B32 is_activated_on_single_click = !!(cell_info.flags & RD_WatchCellFlag_ActivateWithSingleClick); + B32 is_non_code = !!(cell_info.flags & RD_WatchCellFlag_IsNonCode); + String8 ghost_text = {0}; + if(cell_selected && ewv->text_editing && cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) + { + is_non_code = 0; + is_button = 0; + is_activated_on_single_click = 0; + } + ProfEnd(); + + // rjf: determine query needle + String8 needle = rd_view_query_input(); + if(cell->eval.space.kind == E_SpaceKind_FileSystem) + { + needle = str8_skip_last_slash(needle); + } + + // rjf: form cell build parameters + UI_Key line_edit_key = {0}; + RD_CellParams cell_params = {0}; + ProfScope("form cell build parameters") + { + E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key); + B32 cells_are_editable = !!(block_type->flags & E_TypeFlag_EditableChildren); + + // rjf: set up base parameters + cell_params.flags = (RD_CellFlag_KeyboardClickable|RD_CellFlag_NoBackground|RD_CellFlag_CodeContents); + cell_params.depth = (cell->flags & RD_WatchCellFlag_Indented ? row_depth : 0); + cell_params.cursor = &cell_edit_state->cursor; + cell_params.mark = &cell_edit_state->mark; + cell_params.edit_buffer = cell_edit_state->input_buffer; + cell_params.edit_buffer_size = sizeof(cell_edit_state->input_buffer); + cell_params.edit_string_size_out = &cell_edit_state->input_size; + cell_params.line_edit_key_out = &line_edit_key; + cell_params.expanded_out = &next_row_expanded; + cell_params.search_needle = needle; + cell_params.meta_fstrs = cell_info.expr_fstrs; + cell_params.value_fstrs = cell_info.eval_fstrs; + if(row_height_px > ui_top_font_size()*3.5f) + { + cell_params.description = cell_info.description; + } + if(cell_selected && ewv->text_editing && cell->flags & RD_WatchCellFlag_NoEval) + { + MemoryZeroStruct(&cell_params.meta_fstrs); + MemoryZeroStruct(&cell_params.description); + } + + // rjf: extra edit button for meta-cfg strings + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg) + { + cell_params.flags |= RD_CellFlag_EmptyEditButton; + } + + // rjf: extra revert button for non-default meta-cfgs + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg && + !(cell->flags & RD_WatchCellFlag_NoEval)) + { + RD_Cfg *cfg = rd_cfg_from_eval_space(cell->eval.space); + String8 child_key = e_string_from_id(cell->eval.space.u64s[1]); + RD_Cfg *child_cfg = rd_cfg_child_from_string(cfg, child_key); + if(child_cfg != &rd_nil_cfg) + { + MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + if(schemas.count != 0) + { + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; md_node_is_nil(child_schema) && n != 0; n = n->next) + { + child_schema = md_child_from_string(n->v, child_key, 0); + } + if((md_node_has_tag(child_schema, str8_lit("override"), 0) || + md_node_has_tag(child_schema, str8_lit("default"), 0)) && + !md_node_has_tag(child_schema, str8_lit("no_revert"), 0)) + { + cell_params.flags |= RD_CellFlag_RevertButton; + cell_params.revert_out = &revert_cell; + } + } + } + } + + // rjf: apply expander (or substitute space) + if(!ewv->text_editing || !cell_selected || row_depth > 0) + { + if(row_is_expandable && cell == row_info->cells.first) + { + cell_params.flags |= RD_CellFlag_Expander; + } + else if(cells_are_editable && row_depth == !implicit_root && cell == row_info->cells.first) + { + cell_params.flags |= RD_CellFlag_ExpanderPlaceholder; + } + else if(row_depth != 0 && cell == row_info->cells.first) + { + cell_params.flags |= RD_CellFlag_ExpanderSpace; + } + } + + // rjf: apply blank cell ghost text + if(row_info->cells.first == row_info->cells.last && + cells_are_editable && + row->eval.expr == &e_expr_nil) + { + ghost_text = str8_lit("Expression"); + is_non_code = (!cell_selected || !ewv->text_editing); + cell_params.flags &= ~(RD_CellFlag_Expander|RD_CellFlag_ExpanderSpace|RD_CellFlag_ExpanderPlaceholder); + } + + // rjf: apply single-click-activation + if(is_activated_on_single_click) + { + cell_params.flags |= RD_CellFlag_SingleClickActivate; + } + + // rjf: apply code styles + if(is_non_code) + { + cell_params.flags &= ~RD_CellFlag_CodeContents; + } + + // rjf: apply button styles + if(is_button) + { + cell_params.flags |= RD_CellFlag_Button; + cell_params.flags &= ~RD_CellFlag_NoBackground; + if(row_depth == 0) + { + cell_params.flags &= ~RD_CellFlag_ExpanderSpace; + } + } + + // rjf: apply background + if(has_background) + { + cell_params.flags &= ~RD_CellFlag_NoBackground; + } + + // rjf: apply toggle-switch + if(is_toggle_switch) + { + cell_params.flags |= RD_CellFlag_ToggleSwitch; + cell_params.toggled_out = &next_cell_toggled; + } + + // rjf: apply slider + if(is_slider) + { + cell_params.flags |= RD_CellFlag_Slider; + cell_params.slider_value_out = &next_cell_slider_value; + } + + // rjf: apply bindings + if(cell->px == 0 && cell->eval.space.kind == RD_EvalSpaceKind_MetaCmd) + { + cell_params.flags |= RD_CellFlag_Bindings; + cell_params.bindings_name = rd_cmd_name_from_eval(cell->eval); + } + + // rjf: apply background override + if(cell_background_color_override.w != 0) + { + cell_params.flags &= ~RD_CellFlag_NoBackground; + } + } + + // rjf: build + if(cell_background_color_override.w != 0) + { + ui_push_background_color(cell_background_color_override); + } + UI_TextAlignment(cell->px != 0 ? UI_TextAlign_Center : UI_TextAlign_Left) + RD_Font(is_non_code ? RD_FontSlot_Main : RD_FontSlot_Code) + { + sig = rd_cellf(&cell_params, "%S###%I64x_row_%I64x", ghost_text, cell_x, row_hash); + } + if(cell_background_color_override.w != 0) + { + ui_pop_background_color(); + } + if(ui_is_focus_active() && + selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y && + txt_pt_match(cell_edit_state->cursor, cell_edit_state->mark)) + { + String8 input = str8(cell_edit_state->input_buffer, cell_edit_state->input_size); + rd_set_autocomp_regs(cell->eval, .ui_key = line_edit_key, .string = input, .cursor = cell_edit_state->cursor); + } + } + } + + //////////// + //- rjf: handle interactions + // + { + // rjf: hover -> rich hover cfgs + if(ui_hovering(sig) && cell_info.cfg != &rd_nil_cfg) + { + RD_RegsScope(.cfg = cell_info.cfg->id, .no_rich_tooltip = 1) rd_set_hover_regs(RD_RegSlot_Cfg); + } + + // rjf: hover -> rich hover entities + if(ui_hovering(sig) && cell_info.entity != &ctrl_entity_nil) + { + RD_RegsScope(.ctrl_entity = cell_info.entity->handle, .no_rich_tooltip = 1) rd_set_hover_regs(RD_RegSlot_CtrlEntity); + } + + // rjf: hover -> rich hover commands (mini only) + if(ui_hovering(sig) && cell_info.cmd_name.size != 0 && cell->px != 0) + { + RD_RegsScope(.cmd_name = cell_info.cmd_name, .ui_key = sig.box->key) rd_set_hover_regs(RD_RegSlot_CmdName); + } + + // rjf: dragging -> drag/drop + if(ui_dragging(sig) && !contains_2f32(sig.box->rect, ui_mouse()) && + (!cell_selected || !ewv->text_editing)) + { + if(cell->eval.space.kind == E_SpaceKind_FileSystem) + { + String8 file_path = rd_file_path_from_eval(scratch.arena, cell->eval); + RD_RegsScope(.file_path = file_path) rd_drag_begin(RD_RegSlot_FilePath); + } + else if(cell_info.cfg != &rd_nil_cfg) + { + RD_RegsScope(.cfg = cell_info.cfg->id) rd_drag_begin(RD_RegSlot_Cfg); + } + else if(cell_info.entity != &ctrl_entity_nil) + { + RD_RegsScope(.ctrl_entity = cell_info.entity->handle) switch(cell_info.entity->kind) + { + default:{rd_drag_begin(RD_RegSlot_CtrlEntity);}break; + case CTRL_EntityKind_Machine:{RD_RegsScope(.machine = cell_info.entity->handle) rd_drag_begin(RD_RegSlot_Machine);}break; + case CTRL_EntityKind_Process:{RD_RegsScope(.process = cell_info.entity->handle) rd_drag_begin(RD_RegSlot_Process);}break; + case CTRL_EntityKind_Module:{RD_RegsScope(.module = cell_info.entity->handle) rd_drag_begin(RD_RegSlot_Module);}break; + case CTRL_EntityKind_Thread:{RD_RegsScope(.thread = cell_info.entity->handle) rd_drag_begin(RD_RegSlot_Thread);}break; + } + } + else if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity || + cell->eval.space.kind == E_SpaceKind_FileSystem || + cell->eval.space.kind == E_SpaceKind_File || + cell->eval.space.kind == E_SpaceKind_Null) + { + RD_RegsScope(.expr = e_full_expr_string_from_key(scratch.arena, cell->eval.key)) + { + if(cell->flags & RD_WatchCellFlag_Expr) + { + rd_regs()->cfg = row_info->group_cfg_child->id; + } + rd_drag_begin(RD_RegSlot_Expr); + } + } + } + + // rjf: (normally) single-click -> move selection here + if(!(cell_info.flags & RD_WatchCellFlag_ActivateWithSingleClick) && ui_pressed(sig)) + { + ewv->next_cursor = ewv->next_mark = cell_pt; + pressed = 1; + } + + // rjf: reversion + if(revert_cell && cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg) + { + RD_Cfg *cfg = rd_cfg_from_eval_space(cell->eval.space); + String8 child_key = e_string_from_id(cell->eval.space.u64s[1]); + rd_cfg_release(rd_cfg_child_from_string(cfg, child_key)); + } + + // rjf: activation (double-click normally, or single-clicks with special buttons) + if((!(cell_info.flags & RD_WatchCellFlag_ActivateWithSingleClick) && ui_double_clicked(sig)) || + ((cell_info.flags & RD_WatchCellFlag_ActivateWithSingleClick) && ui_clicked(sig)) || + sig.f & UI_SignalFlag_KeyboardPressed) + { + // rjf: kill if a double-clickable cell + if(!(cell_info.flags & RD_WatchCellFlag_ActivateWithSingleClick)) + { + ui_kill_action(); + } + + // rjf: cell w/ a visualizer hook? -> + // if keyboard: open in tab, if within tab + // if double-click: focus this visualizer (via edit) + if(cell->kind == RD_WatchCellKind_ViewUI && + cell_info.view_ui_rule != &rd_nil_view_ui_rule && + cell_view != &rd_nil_cfg) + { + if(!view_is_floating && sig.f & UI_SignalFlag_KeyboardPressed) + { + rd_cfg_unhook(cell_view->parent, cell_view); + rd_cfg_insert_child(view->parent, view, cell_view); + rd_cmd(RD_CmdKind_FocusTab, .tab = cell_view->id); + } + else if(sig.f & UI_SignalFlag_DoubleClicked) + { + ewv->next_cursor = ewv->next_mark = cell_pt; + if(!rd_watch_pt_match(ewv->cursor, cell_pt) && ewv->text_editing) + { + rd_cmd(RD_CmdKind_Accept); + } + rd_cmd(RD_CmdKind_Edit); + } + } + + // rjf: this watch window is a lister? -> move cursor & edit or accept + else if(rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg || + rd_cfg_child_from_string(view, str8_lit("autocomplete")) != &rd_nil_cfg) + { + ewv->next_cursor = ewv->next_mark = cell_pt; + if(cell_info.flags & RD_WatchCellFlag_CanEdit) + { + // TODO(rjf): @hack - we really want navigations to be event-like, but we need + // to insert a dumb no-op here so that the "rugpull" cursor move can take effect + // before the edit command we are queueing up... + rd_cmd(RD_CmdKind_Edit); + rd_cmd(RD_CmdKind_Edit); + } + else + { + rd_cmd(RD_CmdKind_Edit); + ewv->next_cursor = ewv->next_mark = cell_pt; + rd_cmd(RD_CmdKind_Accept); + } + } + + // rjf: has a command name? -> push command + else if(cell_info.cmd_name.size != 0) + { + String8 cmd_name = cell_info.cmd_name; + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(row->eval.space); + RD_Cfg *cfg = rd_cfg_from_eval_space(row->eval.space); + if(cfg == &rd_nil_cfg) + { + cfg = rd_cfg_from_eval_space(row->block->eval.space); + } + if(entity == &ctrl_entity_nil) + { + entity = rd_ctrl_entity_from_eval_space(row->eval.space); + } + RD_RegsScope(.cfg = cfg->id, .ctrl_entity = entity->handle) + { + if(cfg != &rd_nil_cfg) + { + RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, cfg); + RD_PanelNode *parent_panel_node = rd_panel_node_from_tree_cfg(panels.root, cfg->parent); + if(parent_panel_node != &rd_nil_panel_node) + { + rd_regs()->tab = rd_regs()->view = cfg->id; + } + } + if(!(cmd_kind_info->query.flags & RD_QueryFlag_Required) || + (cmd_kind_info->query.slot == RD_RegSlot_Cfg && cfg != &rd_nil_cfg) || + (cmd_kind_info->query.slot == RD_RegSlot_CtrlEntity && entity != &ctrl_entity_nil)) + { + rd_push_cmd(cell_info.cmd_name, rd_regs()); + } + else + { + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_name); + } + } + } + + // rjf: row has callstack info? -> select unwind + else if(row_info->callstack_thread != &ctrl_entity_nil) + { + rd_cmd(RD_CmdKind_SelectThread, .thread = row_info->callstack_thread->handle); + rd_cmd(RD_CmdKind_SelectUnwind, + .unwind_count = row_info->callstack_unwind_index, + .inline_depth = row_info->callstack_inline_depth); + } + + // rjf: can edit? -> begin editing + else if(!(sig.f & UI_SignalFlag_KeyboardPressed) && cell_info.flags & RD_WatchCellFlag_CanEdit) + { + ewv->next_cursor = ewv->next_mark = cell_pt; + if(!rd_watch_pt_match(ewv->cursor, cell_pt)) + { + // TODO(rjf): see above @hack + rd_cmd(RD_CmdKind_Edit); + } + rd_cmd(RD_CmdKind_Edit); + } + + // rjf: can expand? -> expand + else if(sig.f & UI_SignalFlag_KeyboardPressed && row_is_expandable) + { + next_row_expanded = !row_expanded; + } + + // rjf: can't edit, but has address info? -> go to address + else if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + { + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(cell->eval.space); + CTRL_Entity *process = ctrl_process_from_entity(entity); + if(process != &ctrl_entity_nil) + { + U64 vaddr = cell->eval.value.u64; + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + U64 voff = ctrl_voff_from_vaddr(module, vaddr); + D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); + String8 file_path = {0}; + TxtPt pt = {0}; + if(lines.first != 0) + { + file_path = lines.first->v.file_path; + pt = lines.first->v.pt; + rd_cmd(RD_CmdKind_FindCodeLocation, + .process = process->handle, + .vaddr = vaddr, + .file_path = file_path, + .cursor = pt); + } + } + } + + // rjf: can't edit, but has cfg? -> find or select + else if(cell_info.cfg != &rd_nil_cfg) + { + RD_Cfg *cfg = cell_info.cfg; + RD_Location loc = rd_location_from_cfg(cfg); + if(loc.file_path.size != 0) + { + rd_cmd(RD_CmdKind_FindCodeLocation, .vaddr = 0, .file_path = loc.file_path, .cursor = loc.pt); + } + else if(loc.expr.size != 0) + { + U64 value = e_value_from_string(loc.expr).u64; + rd_cmd(RD_CmdKind_FindCodeLocation, .vaddr = value); + } + else if(str8_match(cfg->string, str8_lit("target"), 0) && sig.event_flags & OS_Modifier_Ctrl) + { + rd_cmd(RD_CmdKind_EnableCfg, .cfg = cfg->id); + } + else if(str8_match(cfg->string, str8_lit("target"), 0)) + { + rd_cmd(RD_CmdKind_SelectCfg, .cfg = cfg->id); + } + } + + // rjf: can't edit, but has thread? -> select + else if(cell_info.entity->kind == CTRL_EntityKind_Thread) + { + rd_cmd(RD_CmdKind_SelectThread, .thread = cell_info.entity->handle); + } + + // rjf: other cases, but this watch window is floating, and this has a cfg/entity? -> push query + else if(view_is_floating && (cell_info.entity != &ctrl_entity_nil || cell_info.cfg != &rd_nil_cfg)) + { + rd_cmd(RD_CmdKind_PushQuery, .expr = e_full_expr_string_from_key(scratch.arena, cell->eval.key)); + } + } + + // rjf: hovering with inheritance string -> show tooltip + if(ui_hovering(sig) && cell_info.inheritance_tooltip.size != 0) UI_Tooltip + { + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) UI_TextPadding(0) + { + ui_labelf("Inherited from "); + RD_Font(RD_FontSlot_Code) rd_code_label(1.f, 0, ui_color_from_name(str8_lit("code_default")), cell_info.inheritance_tooltip); + } + } + + // rjf: hovering with error tooltip -> show tooltip + if(ui_hovering(sig) && cell_info.error_tooltip.size != 0) UI_Tooltip + { + UI_PrefWidth(ui_children_sum(1)) rd_error_label(cell_info.error_tooltip); + } + } + + //////////// + //- rjf: commit toggle changes + // + if(next_cell_toggled != cell_toggled) + { + rd_commit_eval_value_string(cell->eval, next_cell_toggled ? str8_lit("1") : str8_lit("0")); + } + + //////////// + //- rjf: commit slider changes + // + if(next_cell_slider_value != cell_slider_value) + { + String8 new_value_string = {0}; + switch(slider_value_type_kind) + { + default: + if(e_type_kind_is_integer(slider_value_type_kind)) + { + S64 new_value = (S64)((next_cell_slider_value * (cell_slider_max.s64 - cell_slider_min.s64)) + cell_slider_min.s64); + new_value = Clamp(cell_slider_min.s64, new_value, cell_slider_max.s64); + new_value_string = push_str8f(scratch.arena, "%I64d", new_value); + }break; + case E_TypeKind_F32: + { + F32 new_value = (next_cell_slider_value * (cell_slider_max.f32 - cell_slider_min.f32)) + cell_slider_min.f32; + new_value = Clamp(cell_slider_min.f32, new_value, cell_slider_max.f32); + new_value_string = push_str8f(scratch.arena, "%f", new_value); + }break; + case E_TypeKind_F64: + { + F64 new_value = (F64)((next_cell_slider_value * (cell_slider_max.f64 - cell_slider_min.f64)) + cell_slider_min.f64); + new_value = Clamp(cell_slider_min.f64, new_value, cell_slider_max.f64); + new_value_string = push_str8f(scratch.arena, "%f", new_value); + }break; + } + rd_commit_eval_value_string(cell->eval, new_value_string); + } + + //////////// + //- rjf: bump x pixel coordinate + // + cell_x_px = next_cell_x_px; + + if(row_depth > 0) { ui_pop_tag(); } + } + } + + ////////////////////// + //- rjf: commit expansion state changes + // + if(next_row_expanded != row_expanded) + { + if(!ev_key_match(ev_key_root(), row->key)) + { + ev_key_set_expansion(eval_view, row->block->key, row->key, next_row_expanded); + } + } + } + } + } + } + } + + ////////////////////////////// + //- rjf: general table-wide press logic + // + if(pressed) + { + rd_cmd(RD_CmdKind_FocusPanel); + } + + ////////////////////////////// + //- rjf: disable query if text editing is occurring + // + vs->contents_are_focused = ewv->text_editing; + + rd_store_view_scroll_pos(scroll_pos); + } + scratch_end(scratch); + } + + //////////////////////////// + //- rjf: visualizer hook + // + else + { + Temp scratch = scratch_begin(0, 0); + RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(view_name); + E_Eval expr_eval = e_eval_from_string(expr_string); + + // rjf: peek presses, steal focus from query bar + for(UI_Event *evt = 0; ui_next_event(&evt);) + { + if(evt->kind == UI_EventKind_Press && contains_2f32(rect, evt->pos)) + { + vs->contents_are_focused = 1; + break; + } + } + + // rjf: 'pull out' button, if floating + if(view_is_floating) + { + UI_Signal pull_out_sig = {0}; + UI_TagF(".") UI_TagF("tab") UI_Rect(r2f32p(floor_f32(ui_top_font_size()*1.5f), + floor_f32(ui_top_font_size()*1.5f), + floor_f32(ui_top_font_size()*1.5f + ui_top_font_size()*3.f), + floor_f32(ui_top_font_size()*1.5f + ui_top_font_size()*3.f))) + UI_CornerRadius(floor_f32(ui_top_font_size()*1.5f)) + UI_TextAlignment(UI_TextAlign_Center) + RD_Font(RD_FontSlot_Icons) + UI_FontSize(floor_f32(ui_top_font_size()*0.9f)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_Floating| + UI_BoxFlag_DrawText| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects, + "%S###pull_out", + rd_icon_kind_text_table[RD_IconKind_Window]); + pull_out_sig = ui_signal_from_box(box); + } + if(ui_dragging(pull_out_sig) && !contains_2f32(pull_out_sig.box->rect, ui_mouse())) + { + rd_drag_begin(RD_RegSlot_View); + } + if(ui_hovering(pull_out_sig)) UI_Tooltip RD_Font(RD_FontSlot_Main) + { + ui_state->tooltip_anchor_key = pull_out_sig.box->key; + ui_labelf("Pull Out As New Tab"); + } + } + + // rjf: build ui via hook + E_ParentKey(expr_eval.key) + { + view_ui_rule->ui(expr_eval, rect); + } + + scratch_end(scratch); + } } - MD_Node *new_params_root = view->params_roots[view->params_write_gen%ArrayCount(view->params_arenas)]; - if(md_node_is_nil(new_params_root)) + + //////////////////////////// + //- rjf: catchall completion controls + // + if(vs->query_is_open) UI_Focus(UI_FocusKind_On) { - new_params_root = view->params_roots[view->params_write_gen%ArrayCount(view->params_arenas)] = md_push_node(new_params_arena, MD_NodeKind_Main, 0, str8_zero(), str8_zero(), 0); + if(ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Cancel)) + { + vs->query_is_open = 0; + vs->query_string_size = 0; + } + if(ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Accept)) + { + String8 cmd_name = rd_view_query_cmd(); + String8 input = rd_view_query_input(); + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + RD_RegsScope() + { + rd_regs_fill_slot_from_string(cmd_kind_info->query.slot, input); + rd_cmd(RD_CmdKind_CompleteQuery); + } + } } - MD_Node *key_node = md_child_from_string(new_params_root, key, 0); - if(md_node_is_nil(key_node)) - { - String8 key_copy = push_str8_copy(new_params_arena, key); - key_node = md_push_node(new_params_arena, MD_NodeKind_Main, MD_NodeFlag_Identifier, key_copy, key_copy, 0); - md_node_push_child(new_params_root, key_node); - } - key_node->first = key_node->last = &md_nil_node; - String8 value_copy = push_str8_copy(new_params_arena, value); - MD_TokenizeResult value_tokenize = md_tokenize_from_text(new_params_arena, value_copy); - MD_ParseResult value_parse = md_parse_from_text_tokens(new_params_arena, str8_zero(), value_copy, value_tokenize.tokens); - for MD_EachNode(child, value_parse.root->first) - { - child->parent = key_node; - } - key_node->first = value_parse.root->first; - key_node->last = value_parse.root->last; -} - -internal void -rd_view_store_paramf(RD_View *view, String8 key, char *fmt, ...) -{ - Temp scratch = scratch_begin(0, 0); - va_list args; - va_start(args, fmt); - String8 string = push_str8fv(scratch.arena, fmt, args); - rd_view_store_param(view, key, string); - va_end(args); - scratch_end(scratch); + + vs->last_frame_index_built = rd_state->frame_index; + ProfEnd(); } //////////////////////////////// @@ -3102,33 +5514,147 @@ rd_view_store_paramf(RD_View *view, String8 key, char *fmt, ...) internal Arena * rd_view_arena(void) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - return view->arena; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + return view_state->arena; } internal UI_ScrollPt2 rd_view_scroll_pos(void) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - return view->scroll_pos; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + return view_state->scroll_pos; +} + +internal EV_View * +rd_view_eval_view(void) +{ + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + return view_state->ev_view; } internal String8 -rd_view_expr_string(void) +rd_view_query_cmd(void) { - // TODO(rjf): @entity_simplification filter and expr string need to be different - RD_View *view = rd_view_from_handle(rd_regs()->view); - String8 expr_string = str8(view->query_buffer, view->query_string_size); - return expr_string; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); + RD_Cfg *cmd = rd_cfg_child_from_string(query, str8_lit("cmd")); + String8 string = cmd->first->string; + return string; } internal String8 -rd_view_filter(void) +rd_view_query_input(void) { - // TODO(rjf): @entity_simplification filter and expr string need to be different - RD_View *view = rd_view_from_handle(rd_regs()->view); - String8 filter = str8(view->query_buffer, view->query_string_size); - return filter; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); + RD_Cfg *input = rd_cfg_child_from_string(query, str8_lit("input")); + String8 string = input->first->string; + return string; +} + +internal String8 +rd_view_setting_from_name(String8 name) +{ + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + String8 result = rd_cfg_child_from_string(view, name)->first->string; + if(result.size == 0) + { + result = rd_default_setting_from_names(view->string, name); + } + return result; +} + +internal E_Value +rd_view_setting_value_from_name(String8 name) +{ + String8 expr = rd_view_setting_from_name(name); + E_Eval eval = e_eval_from_string(expr); + E_Value result = e_value_eval_from_eval(eval).value; + return result; +} + +internal B32 +rd_view_setting_b32_from_name(String8 name) +{ + String8 string = rd_view_setting_from_name(name); + B32 result = !!e_value_from_stringf("raw((bool)(%S))", string).u64; + return result; +} + +internal U64 +rd_view_setting_u64_from_name(String8 name) +{ + String8 string = rd_view_setting_from_name(name); + U64 result = e_value_from_stringf("raw((uint64)(%S))", string).u64; + return result; +} + +internal F32 +rd_view_setting_f32_from_name(String8 name) +{ + String8 string = rd_view_setting_from_name(name); + F32 result = e_value_from_stringf("raw((float32)(%S))", string).f32; + return result; +} + +//- rjf: evaluation & tag (a view's 'call') parameter extraction + +internal TXT_LangKind +rd_lang_kind_from_eval(E_Eval eval) +{ + TXT_LangKind lang_kind = TXT_LangKind_Null; + Temp scratch = scratch_begin(0, 0); + String8 file_path = rd_file_path_from_eval(scratch.arena, eval); + if(file_path.size != 0) + { + lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(file_path)); + } + scratch_end(scratch); + return lang_kind; +} + +internal Arch +rd_arch_from_eval(E_Eval eval) +{ + // rjf: try implicitly from either `eval` itself, or from context + CTRL_Entity *ctrl_entity = rd_ctrl_entity_from_eval_space(eval.space); + CTRL_Entity *process = ctrl_process_from_entity(ctrl_entity); + if(process == &ctrl_entity_nil) + { + process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); + } + Arch arch = process->arch; + if(arch == Arch_Null) + { + arch = arch_from_context(); + } + + // rjf: try arch arguments + E_Type *type = e_type_from_key(eval.irtree.type_key); + if(type->kind == E_TypeKind_Lens) + { + for EachIndex(idx, type->count) + { + E_Expr *arg = type->args[idx]; + { + String8 arg_arch_string = arg->string; + if(arg->kind == E_ExprKind_Define && str8_match(arg->first->string, str8_lit("arch"), 0)) + { + arg_arch_string = arg->first->next->string; + } + if(str8_match(arg->first->next->string, str8_lit("x64"), 0)) + { + arch = Arch_x64; + break; + } + } + } + } + + return arch; } //- rjf: pushing/attaching view resources @@ -3136,17 +5662,24 @@ rd_view_filter(void) internal void * rd_view_state_by_size(U64 size) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - void *result = rd_view_get_or_push_user_state(view, size); - return result; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + if(view_state->user_data == 0) + { + view_state->user_data = push_array(view_state->arena, U8, size); + } + return view_state->user_data; } internal Arena * rd_push_view_arena(void) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - Arena *result = rd_view_push_arena_ext(view); - return result; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + RD_ArenaExt *ext = push_array(view_state->arena, RD_ArenaExt, 1); + ext->arena = arena_alloc(); + SLLQueuePush(view_state->first_arena_ext, view_state->last_arena_ext, ext); + return ext->arena; } //- rjf: storing view-attached state @@ -3154,38 +5687,39 @@ rd_push_view_arena(void) internal void rd_store_view_expr_string(String8 string) { - // TODO(rjf): @entity_simplification filter and expr string need to be different - RD_View *view = rd_view_from_handle(rd_regs()->view); - rd_view_equip_query(view, string); -} - -internal void -rd_store_view_filter(String8 string) -{ - // TODO(rjf): @entity_simplification filter and expr string need to be different - RD_View *view = rd_view_from_handle(rd_regs()->view); - rd_view_equip_query(view, string); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + rd_cfg_new_replace(expr, string); } internal void rd_store_view_loading_info(B32 is_loading, U64 progress_u64, U64 progress_u64_target) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - rd_view_equip_loading_info(view, is_loading, progress_u64, progress_u64_target); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + view_state->loading_t_target = (F32)!!is_loading; + view_state->loading_progress_v = progress_u64; + view_state->loading_progress_v_target = progress_u64_target; + if(view_state->last_frame_index_built+1 < rd_state->frame_index) + { + view_state->loading_t = view_state->loading_t_target; + } } internal void rd_store_view_scroll_pos(UI_ScrollPt2 pos) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - view->scroll_pos = pos; + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *view_state = rd_view_state_from_cfg(view); + view_state->scroll_pos = pos; } internal void rd_store_view_param(String8 key, String8 value) { - RD_View *view = rd_view_from_handle(rd_regs()->view); - rd_view_store_param(view, key, value); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *child = rd_cfg_child_from_string_or_alloc(view, key); + rd_cfg_new_replace(child, value); } internal void @@ -3201,231 +5735,197 @@ rd_store_view_paramf(String8 key, char *fmt, ...) } //////////////////////////////// -//~ rjf: Expand-Keyed Transient View Functions +//~ rjf: Window Functions -internal RD_TransientViewNode * -rd_transient_view_node_from_ev_key(RD_View *owner_view, EV_Key key) +internal String8 +rd_push_window_title(Arena *arena) { - if(owner_view->transient_view_slots_count == 0) - { - owner_view->transient_view_slots_count = 256; - owner_view->transient_view_slots = push_array(owner_view->arena, RD_TransientViewSlot, owner_view->transient_view_slots_count); - } - U64 hash = ev_hash_from_key(key); - U64 slot_idx = hash%owner_view->transient_view_slots_count; - RD_TransientViewSlot *slot = &owner_view->transient_view_slots[slot_idx]; - RD_TransientViewNode *node = 0; - for(RD_TransientViewNode *n = slot->first; n != 0; n = n->next) - { - if(ev_key_match(n->key, key)) - { - node = n; - n->last_frame_index_touched = rd_state->frame_index; - break; - } - } - if(node == 0) - { - if(!owner_view->free_transient_view_node) - { - owner_view->free_transient_view_node = push_array(rd_state->arena, RD_TransientViewNode, 1); - } - node = owner_view->free_transient_view_node; - SLLStackPop(owner_view->free_transient_view_node); - DLLPushBack(slot->first, slot->last, node); - node->key = key; - node->view = rd_view_alloc(); - node->initial_params_arena = arena_alloc(); - node->first_frame_index_touched = node->last_frame_index_touched = rd_state->frame_index; - DLLPushBack_NPZ(&rd_nil_view, owner_view->first_transient, owner_view->last_transient, node->view, order_next, order_prev); - } - return node; + String8 result = push_str8f(arena, "%S - %s", str8_skip_last_slash(rd_state->project_path), BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ")"); + return result; } -//////////////////////////////// -//~ rjf: Panel State Functions - -internal RD_Panel * -rd_panel_alloc(RD_Window *ws) +internal RD_Cfg * +rd_window_from_cfg(RD_Cfg *cfg) { - RD_Panel *panel = ws->free_panel; - if(!rd_panel_is_nil(panel)) + RD_Cfg *result = &rd_nil_cfg; + for(RD_Cfg *c = cfg; c != &rd_nil_cfg; c = c->parent) { - SLLStackPop(ws->free_panel); - U64 generation = panel->generation; - MemoryZeroStruct(panel); - panel->generation = generation; - } - else - { - panel = push_array(ws->arena, RD_Panel, 1); - } - panel->first = panel->last = panel->next = panel->prev = panel->parent = &rd_nil_panel; - panel->first_tab_view = panel->last_tab_view = &rd_nil_view; - panel->generation += 1; - MemoryZeroStruct(&panel->animated_rect_pct); - return panel; -} - -internal void -rd_panel_release(RD_Window *ws, RD_Panel *panel) -{ - rd_panel_release_all_views(panel); - SLLStackPush(ws->free_panel, panel); - panel->generation += 1; -} - -internal void -rd_panel_release_all_views(RD_Panel *panel) -{ - for(RD_View *view = panel->first_tab_view, *next = 0; !rd_view_is_nil(view); view = next) - { - next = view->order_next; - rd_view_release(view); - } - panel->first_tab_view = panel->last_tab_view = &rd_nil_view; - panel->selected_tab_view = rd_handle_zero(); - panel->tab_view_count = 0; -} - -//////////////////////////////// -//~ rjf: Window State Functions - -internal RD_Window * -rd_window_open(Vec2F32 size, OS_Handle preferred_monitor, RD_CfgSrc cfg_src) -{ - RD_Window *window = rd_state->free_window; - if(window != 0) - { - SLLStackPop(rd_state->free_window); - U64 gen = window->gen; - MemoryZeroStruct(window); - window->gen = gen; - } - else - { - window = push_array(rd_state->arena, RD_Window, 1); - } - window->gen += 1; - window->frames_alive = 0; - window->cfg_src = cfg_src; - window->arena = arena_alloc(); - { - String8 title = str8_lit_comp(BUILD_TITLE_STRING_LITERAL); - window->os = os_window_open(size, OS_WindowFlag_CustomBorder, title); - } - window->r = r_window_equip(window->os); - window->ui = ui_state_alloc(); - window->ctx_menu_arena = arena_alloc(); - window->ctx_menu_regs = push_array(window->ctx_menu_arena, RD_Regs, 1); - window->ctx_menu_input_buffer_size = KB(4); - window->ctx_menu_input_buffer = push_array(window->arena, U8, window->ctx_menu_input_buffer_size); - window->drop_completion_arena = arena_alloc(); - window->hover_eval_arena = arena_alloc(); - window->autocomp_lister_params_arena = arena_alloc(); - window->free_panel = &rd_nil_panel; - window->root_panel = rd_panel_alloc(window); - window->focused_panel = window->root_panel; - window->query_cmd_arena = arena_alloc(); - window->query_view_stack_top = &rd_nil_view; - window->last_dpi = os_dpi_from_window(window->os); - for EachEnumVal(RD_SettingCode, code) - { - if(rd_setting_code_default_is_per_window_table[code]) + if(c->parent->parent == rd_state->root_cfg && str8_match(c->string, str8_lit("window"), 0)) { - window->setting_vals[code] = rd_setting_code_default_val_table[code]; - } - } - window->setting_vals[RD_SettingCode_MainFontSize].s32 = window->setting_vals[RD_SettingCode_MainFontSize].s32 * (window->last_dpi / 96.f); - window->setting_vals[RD_SettingCode_CodeFontSize].s32 = window->setting_vals[RD_SettingCode_CodeFontSize].s32 * (window->last_dpi / 96.f); - window->setting_vals[RD_SettingCode_MainFontSize].s32 = ClampBot(window->setting_vals[RD_SettingCode_MainFontSize].s32, rd_setting_code_default_val_table[RD_SettingCode_MainFontSize].s32); - window->setting_vals[RD_SettingCode_CodeFontSize].s32 = ClampBot(window->setting_vals[RD_SettingCode_CodeFontSize].s32, rd_setting_code_default_val_table[RD_SettingCode_CodeFontSize].s32); - OS_Handle zero_monitor = {0}; - if(!os_handle_match(zero_monitor, preferred_monitor)) - { - os_window_set_monitor(window->os, preferred_monitor); - } - if(rd_state->first_window == 0) RD_RegsScope(.window = rd_handle_from_window(window)) - { - RD_FontSlot english_font_slots[] = {RD_FontSlot_Main, RD_FontSlot_Code}; - RD_FontSlot icon_font_slot = RD_FontSlot_Icons; - for(U64 idx = 0; idx < ArrayCount(english_font_slots); idx += 1) - { - Temp scratch = scratch_begin(0, 0); - RD_FontSlot slot = english_font_slots[idx]; - String8 sample_text = str8_lit("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890~!@#$%^&*()-_+=[{]}\\|;:'\",<.>/?"); - fnt_push_run_from_string(scratch.arena, - rd_font_from_slot(slot), - rd_font_size_from_slot(RD_FontSlot_Code), - 0, 0, 0, - sample_text); - fnt_push_run_from_string(scratch.arena, - rd_font_from_slot(slot), - rd_font_size_from_slot(RD_FontSlot_Main), - 0, 0, 0, - sample_text); - scratch_end(scratch); - } - for(RD_IconKind icon_kind = RD_IconKind_Null; icon_kind < RD_IconKind_COUNT; icon_kind = (RD_IconKind)(icon_kind+1)) - { - Temp scratch = scratch_begin(0, 0); - fnt_push_run_from_string(scratch.arena, - rd_font_from_slot(icon_font_slot), - rd_font_size_from_slot(icon_font_slot), - 0, 0, FNT_RasterFlag_Smooth, - rd_icon_kind_text_table[icon_kind]); - fnt_push_run_from_string(scratch.arena, - rd_font_from_slot(icon_font_slot), - rd_font_size_from_slot(RD_FontSlot_Main), - 0, 0, FNT_RasterFlag_Smooth, - rd_icon_kind_text_table[icon_kind]); - fnt_push_run_from_string(scratch.arena, - rd_font_from_slot(icon_font_slot), - rd_font_size_from_slot(RD_FontSlot_Code), - 0, 0, FNT_RasterFlag_Smooth, - rd_icon_kind_text_table[icon_kind]); - scratch_end(scratch); - } - } - DLLPushBack(rd_state->first_window, rd_state->last_window, window); - return window; -} - -internal RD_Window * -rd_window_from_os_handle(OS_Handle os) -{ - RD_Window *result = 0; - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) - { - if(os_handle_match(w->os, os)) - { - result = w; + result = c; break; } } return result; } +internal RD_WindowState * +rd_window_state_from_cfg(RD_Cfg *cfg) +{ + //- rjf: unpack + RD_Cfg *window_cfg = rd_window_from_cfg(cfg); + RD_CfgID id = window_cfg->id; + + //- rjf: scan for existing window + RD_WindowState *ws = &rd_nil_window_state; + if(id != 0 && + id == rd_state->window_state_last_accessed_id && + id == rd_state->window_state_last_accessed->cfg_id) + { + ws = rd_state->window_state_last_accessed; + } + else + { + U64 hash = d_hash_from_string(str8_struct(&id)); + U64 slot_idx = hash%rd_state->window_state_slots_count; + RD_WindowStateSlot *slot = &rd_state->window_state_slots[slot_idx]; + for(RD_WindowState *w = slot->first; w != 0; w = w->hash_next) + { + if(w->cfg_id == id) + { + ws = w; + break; + } + } + } + + //- rjf: allocate/open new window if one was not found + if(window_cfg != &rd_nil_cfg && ws == &rd_nil_window_state) + { + Temp scratch = scratch_begin(0, 0); + + // rjf: unpack configuration options + B32 has_pos = 0; + Vec2F32 pos = {0}; + Vec2F32 size = {0}; + OS_Handle preferred_monitor = {0}; + { + RD_Cfg *pos_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("pos")); + has_pos = (pos_cfg != &rd_nil_cfg); + RD_Cfg *size_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("size")); + RD_Cfg *monitor_cfg = rd_cfg_child_from_string(window_cfg, str8_lit("monitor")); + pos.x = (F32)f64_from_str8(pos_cfg->first->string); + pos.y = (F32)f64_from_str8(pos_cfg->first->next->string); + size.x = (F32)f64_from_str8(size_cfg->first->string); + size.y = (F32)f64_from_str8(size_cfg->first->next->string); + OS_HandleArray monitors = os_push_monitors_array(scratch.arena); + for EachIndex(idx, monitors.count) + { + String8 monitor_name = os_name_from_monitor(scratch.arena, monitors.v[idx]); + if(str8_match(monitor_name, monitor_cfg->first->string, StringMatchFlag_CaseInsensitive)) + { + preferred_monitor = monitors.v[idx]; + break; + } + } + } + + // rjf: allocate window + ws = rd_state->free_window_state; + if(ws != 0) + { + SLLStackPop_N(rd_state->free_window_state, order_next); + } + else + { + ws = push_array_no_zero(rd_state->arena, RD_WindowState, 1); + } + MemoryZeroStruct(ws); + + // rjf: fill out window + ws->cfg_id = id; + ws->arena = arena_alloc(); + { + String8 title = rd_push_window_title(scratch.arena); + ws->os = os_window_open(r2f32p(pos.x, pos.y, pos.x+size.x, pos.y+size.y), (!has_pos*OS_WindowFlag_UseDefaultPosition)|OS_WindowFlag_CustomBorder, title); + } + ws->r = r_window_equip(ws->os); + ws->ui = ui_state_alloc(); + ws->drop_completion_arena = arena_alloc(); + ws->query_arena = arena_alloc(); + ws->hover_eval_arena = arena_alloc(); + ws->autocomp_arena = arena_alloc(); + ws->last_dpi = os_dpi_from_window(ws->os); + OS_Handle zero_monitor = {0}; + if(!os_handle_match(zero_monitor, preferred_monitor)) + { + os_window_set_monitor(ws->os, preferred_monitor); + } + if(rd_cfg_child_from_string(window_cfg, str8_lit("fullscreen")) != &rd_nil_cfg) + { + os_window_set_fullscreen(ws->os, 1); + } + if(rd_cfg_child_from_string(window_cfg, str8_lit("maximized")) != &rd_nil_cfg) + { + os_window_set_maximized(ws->os, 1); + } + + // rjf: hook up window links + U64 hash = d_hash_from_string(str8_struct(&id)); + U64 slot_idx = hash%rd_state->window_state_slots_count; + RD_WindowStateSlot *slot = &rd_state->window_state_slots[slot_idx]; + DLLPushBack_NPZ(&rd_nil_window_state, rd_state->first_window_state, rd_state->last_window_state, ws, order_next, order_prev); + DLLPushBack_NP(slot->first, slot->last, ws, hash_next, hash_prev); + + scratch_end(scratch); + } + + //- rjf: touch window for this frame + if(ws != &rd_nil_window_state) + { + ws->last_frame_index_touched = rd_state->frame_index; + } + + rd_state->window_state_last_accessed_id = ws->cfg_id; + rd_state->window_state_last_accessed = ws; + return ws; +} + +internal RD_WindowState * +rd_window_state_from_os_handle(OS_Handle os) +{ + RD_WindowState *ws = &rd_nil_window_state; + { + for(RD_WindowState *w = rd_state->first_window_state; + w != &rd_nil_window_state; + w = w->order_next) + { + if(os_handle_match(w->os, os)) + { + ws = w; + break; + } + } + } + return ws; +} + #if COMPILER_MSVC && !BUILD_DEBUG #pragma optimize("", off) #endif internal void -rd_window_frame(RD_Window *ws) +rd_window_frame(void) { + Temp scratch = scratch_begin(0, 0); ProfBeginFunction(); ////////////////////////////// - //- rjf: unpack context + //- rjf: @window_frame_part unpack context // - B32 window_is_focused = os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc; - B32 popup_open = rd_state->popup_active; - B32 query_is_open = !rd_view_is_nil(ws->query_view_stack_top); - B32 hover_eval_is_open = (!popup_open && - ws->hover_eval_string.size != 0 && - ws->hover_eval_first_frame_idx+20 < ws->hover_eval_last_frame_idx && - rd_state->frame_index-ws->hover_eval_last_frame_idx < 20); - if(!window_is_focused || popup_open) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window)); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + B32 window_is_focused = (os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc); + B32 popup_is_open = (rd_state->popup_active); + B32 query_is_open = (ws->query_is_active); + U64 hover_eval_open_delay_us = 400000; + B32 hover_eval_is_open = (!popup_is_open && + !query_is_open && + ws->hover_eval_string.size != 0 && + ws->hover_eval_firstt_us+hover_eval_open_delay_us < ws->hover_eval_lastt_us && + rd_state->time_in_us - ws->hover_eval_lastt_us < hover_eval_open_delay_us); + if(!window_is_focused || popup_is_open) { ws->menu_bar_key_held = 0; } @@ -3433,146 +5933,295 @@ rd_window_frame(RD_Window *ws) ui_select_state(ws->ui); ////////////////////////////// - //- rjf: panels with no selected tabs? -> select. - // panels with selected tabs? -> ensure they have active tabs. + //- rjf: @window_frame_part fill panel/view interaction registers + // + rd_regs()->panel = panel_tree.focused->cfg->id; + rd_regs()->tab = panel_tree.focused->selected_tab->id; + rd_regs()->view = panel_tree.focused->selected_tab->id; + + ////////////////////////////// + //- rjf: @window_frame_part compute window's theme // - for(RD_Panel *panel = ws->root_panel; - !rd_panel_is_nil(panel); - panel = rd_panel_rec_depth_first_pre(panel).next) { - if(!rd_panel_is_nil(panel->first)) + HS_Scope *hs_scope = hs_scope_open(); + + //- rjf: try to find theme settings from the project, then the user. + RD_CfgList colors_cfgs = {0}; + RD_Cfg *theme_parents[] = { - continue; - } - RD_View *view = rd_selected_tab_from_panel(panel); - if(rd_view_is_nil(view)) + rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")), + rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")) + }; + RD_Cfg *theme_cfgs[] = { - for(RD_View *tab = panel->first_tab_view; !rd_view_is_nil(tab); tab = tab->order_next) + &rd_nil_cfg, + &rd_nil_cfg, + }; + for EachIndex(idx, ArrayCount(theme_parents)) + { + RD_Cfg *parent_cfg = theme_parents[idx]; + if(theme_cfgs[idx] == &rd_nil_cfg) { - if(!rd_view_is_project_filtered(tab)) + RD_Cfg *possible_theme_cfg = rd_cfg_child_from_string(parent_cfg, str8_lit("theme")); + if(possible_theme_cfg != &rd_nil_cfg) { - panel->selected_tab_view = rd_handle_from_view(tab); - break; + theme_cfgs[idx] = possible_theme_cfg; + } + } + for(RD_Cfg *child = parent_cfg->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("theme_color"), 0)) + { + rd_cfg_list_push_front(scratch.arena, &colors_cfgs, child); } } } - if(!rd_view_is_nil(view)) + + //- rjf: choose which theme cfg to use + RD_Cfg *theme_cfg = theme_cfgs[1]; + if(rd_setting_b32_from_name(str8_lit("use_project_theme"))) { - B32 found = 0; - for(RD_View *tab = panel->first_tab_view; !rd_view_is_nil(tab); tab = tab->order_next) + theme_cfg = theme_cfgs[0]; + if(theme_cfg == &rd_nil_cfg) { - if(rd_view_is_project_filtered(tab)) {continue;} - if(tab == view) + theme_cfg = theme_cfgs[1]; + } + } + + //- rjf: map the theme config to the associated tree (either from a preset, or from a file) + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme_cfg->first->string); + if(colors_cfgs.count == 0 && theme_tree == &md_nil_node) + { + theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; + } + + //- rjf: build tasks for color applications - each task comprises of a metadesk + // tree, describing the color patterns + typedef struct ThemeTask ThemeTask; + struct ThemeTask + { + ThemeTask *next; + MD_Node *tree; + }; + ThemeTask start_task = {0, theme_tree}; + ThemeTask *first_task = &start_task; + ThemeTask *last_task = first_task; + { + for(RD_CfgNode *n = colors_cfgs.first; n != 0; n = n->next) + { + ThemeTask *t = push_array(scratch.arena, ThemeTask, 1); + SLLQueuePushFront(first_task, last_task, t); + t->tree = md_tree_from_string(scratch.arena, rd_string_from_cfg_tree(scratch.arena, str8_zero(), n->v)); + } + } + + //- rjf: apply theme tasks, build each color pattern for this window's + // structured theme + typedef struct ThemePatternNode ThemePatternNode; + struct ThemePatternNode + { + ThemePatternNode *next; + UI_ThemePattern pattern; + }; + ThemePatternNode *first_pattern = 0; + ThemePatternNode *last_pattern = 0; + U64 pattern_count = 0; + for(ThemeTask *t = first_task; t != 0; t = t->next) + { + MD_Node *tree_root = t->tree; + for(MD_Node *n = tree_root; !md_node_is_nil(n); n = md_node_rec_depth_first_pre(n, tree_root).next) + { + if(str8_match(n->string, str8_lit("theme_color"), 0)) { - found = 1; + MD_Node *tags_child = md_child_from_string(n, str8_lit("tags"), 0); + MD_Node *value_child = md_child_from_string(n, str8_lit("value"), 0); + U8 split_char = ' '; + String8List tags = str8_split(scratch.arena, tags_child->first->string, &split_char, 1, 0); + U32 color_u32 = e_value_from_stringf("raw(%S)", value_child->first->string).u32; + Vec4F32 color_linear = linear_from_srgba(rgba_from_u32(color_u32)); + ThemePatternNode *node = push_array(scratch.arena, ThemePatternNode, 1); + node->pattern.tags = str8_array_from_list(rd_frame_arena(), &tags); + node->pattern.linear = color_linear; + SLLQueuePush(first_pattern, last_pattern, node); + pattern_count += 1; } } - if(!found) + } + + //- rjf: convert to final pattern array + ws->theme = push_array(rd_frame_arena(), UI_Theme, 1); + ws->theme->patterns_count = pattern_count; + ws->theme->patterns = push_array(rd_frame_arena(), UI_ThemePattern, ws->theme->patterns_count); + { + U64 idx = 0; + for(ThemePatternNode *n = first_pattern; n != 0; n = n->next, idx += 1) { - panel->selected_tab_view = rd_handle_zero(); + ws->theme->patterns[idx] = n->pattern; } } + + hs_scope_close(hs_scope); + } + + ////////////////////////////// + //- rjf: @window_frame_part compute window's font raster flags + // + { + ws->font_slot_raster_flags[RD_FontSlot_Icons] = FNT_RasterFlag_Smooth; + ws->font_slot_raster_flags[RD_FontSlot_Main] = (rd_setting_b32_from_name(str8_lit("smooth_ui_text"))*FNT_RasterFlag_Smooth)|(rd_setting_b32_from_name(str8_lit("hint_ui_text"))*FNT_RasterFlag_Hinted); + ws->font_slot_raster_flags[RD_FontSlot_Code] = (rd_setting_b32_from_name(str8_lit("smooth_code_text"))*FNT_RasterFlag_Smooth)|(rd_setting_b32_from_name(str8_lit("hint_code_text"))*FNT_RasterFlag_Hinted); + } + + ////////////////////////////// + //- rjf: @window_frame_part pre-emptively rasterize common glyphs on the first frame + // + if(rd_state->first_window_state == ws && rd_state->last_window_state == ws && ws->frames_alive == 0) + { + F32 font_size = rd_font_size(); + RD_FontSlot english_font_slots[] = {RD_FontSlot_Main, RD_FontSlot_Code}; + RD_FontSlot icon_font_slot = RD_FontSlot_Icons; + for(U64 idx = 0; idx < ArrayCount(english_font_slots); idx += 1) + { + Temp scratch = scratch_begin(0, 0); + RD_FontSlot slot = english_font_slots[idx]; + String8 sample_text = str8_lit("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890~!@#$%^&*()-_+=[{]}\\|;:'\",<.>/?"); + fnt_run_from_string(rd_font_from_slot(slot), + font_size, + 0, 0, 0, + sample_text); + fnt_run_from_string(rd_font_from_slot(slot), + font_size, + 0, 0, 0, + sample_text); + scratch_end(scratch); + } + for(RD_IconKind icon_kind = RD_IconKind_Null; icon_kind < RD_IconKind_COUNT; icon_kind = (RD_IconKind)(icon_kind+1)) + { + Temp scratch = scratch_begin(0, 0); + fnt_run_from_string(rd_font_from_slot(icon_font_slot), + font_size, + 0, 0, FNT_RasterFlag_Smooth, + rd_icon_kind_text_table[icon_kind]); + fnt_run_from_string(rd_font_from_slot(icon_font_slot), + font_size, + 0, 0, FNT_RasterFlag_Smooth, + rd_icon_kind_text_table[icon_kind]); + fnt_run_from_string(rd_font_from_slot(icon_font_slot), + font_size, + 0, 0, FNT_RasterFlag_Smooth, + rd_icon_kind_text_table[icon_kind]); + scratch_end(scratch); + } } ////////////////////////////// - //- rjf: fill panel/view interaction registers - // - rd_regs()->panel = rd_handle_from_panel(ws->focused_panel); - rd_regs()->view = ws->focused_panel->selected_tab_view; - - ////////////////////////////// - //- rjf: compute ui palettes from theme + //- rjf: @window_frame_part commit window's position/status to underlying cfg tree // { - RD_Theme *current = &rd_state->cfg_theme; - for EachEnumVal(RD_PaletteCode, code) + Temp scratch = scratch_begin(0, 0); + B32 is_fullscreen = os_window_is_fullscreen(ws->os); + B32 is_maximized = os_window_is_maximized(ws->os); + B32 is_minimized = os_window_is_minimized(ws->os); + if(is_fullscreen) { - ws->cfg_palettes[code].null = v4f32(1, 0, 1, 1); - ws->cfg_palettes[code].cursor = current->colors[RD_ThemeColor_Cursor]; - ws->cfg_palettes[code].selection = current->colors[RD_ThemeColor_SelectionOverlay]; + rd_cfg_child_from_string_or_alloc(window, str8_lit("fullscreen")); } - ws->cfg_palettes[RD_PaletteCode_Base].background = current->colors[RD_ThemeColor_BaseBackground]; - ws->cfg_palettes[RD_PaletteCode_Base].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_Base].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_Base].border = current->colors[RD_ThemeColor_BaseBorder]; - ws->cfg_palettes[RD_PaletteCode_MenuBar].background = current->colors[RD_ThemeColor_MenuBarBackground]; - ws->cfg_palettes[RD_PaletteCode_MenuBar].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_MenuBar].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_MenuBar].border = current->colors[RD_ThemeColor_MenuBarBorder]; - ws->cfg_palettes[RD_PaletteCode_Floating].background = current->colors[RD_ThemeColor_FloatingBackground]; - ws->cfg_palettes[RD_PaletteCode_Floating].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_Floating].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_Floating].border = current->colors[RD_ThemeColor_FloatingBorder]; - ws->cfg_palettes[RD_PaletteCode_ImplicitButton].background = current->colors[RD_ThemeColor_ImplicitButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_ImplicitButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_ImplicitButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_ImplicitButton].border = current->colors[RD_ThemeColor_ImplicitButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_PlainButton].background = current->colors[RD_ThemeColor_PlainButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_PlainButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_PlainButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_PlainButton].border = current->colors[RD_ThemeColor_PlainButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_PositivePopButton].background = current->colors[RD_ThemeColor_PositivePopButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_PositivePopButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_PositivePopButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_PositivePopButton].border = current->colors[RD_ThemeColor_PositivePopButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_NegativePopButton].background = current->colors[RD_ThemeColor_NegativePopButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_NegativePopButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_NegativePopButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_NegativePopButton].border = current->colors[RD_ThemeColor_NegativePopButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_NeutralPopButton].background = current->colors[RD_ThemeColor_NeutralPopButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_NeutralPopButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_NeutralPopButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_NeutralPopButton].border = current->colors[RD_ThemeColor_NeutralPopButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_ScrollBarButton].background = current->colors[RD_ThemeColor_ScrollBarButtonBackground]; - ws->cfg_palettes[RD_PaletteCode_ScrollBarButton].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_ScrollBarButton].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_ScrollBarButton].border = current->colors[RD_ThemeColor_ScrollBarButtonBorder]; - ws->cfg_palettes[RD_PaletteCode_Tab].background = current->colors[RD_ThemeColor_TabBackground]; - ws->cfg_palettes[RD_PaletteCode_Tab].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_Tab].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_Tab].border = current->colors[RD_ThemeColor_TabBorder]; - ws->cfg_palettes[RD_PaletteCode_TabInactive].background = current->colors[RD_ThemeColor_TabBackgroundInactive]; - ws->cfg_palettes[RD_PaletteCode_TabInactive].text = current->colors[RD_ThemeColor_Text]; - ws->cfg_palettes[RD_PaletteCode_TabInactive].text_weak = current->colors[RD_ThemeColor_TextWeak]; - ws->cfg_palettes[RD_PaletteCode_TabInactive].border = current->colors[RD_ThemeColor_TabBorderInactive]; - ws->cfg_palettes[RD_PaletteCode_DropSiteOverlay].background = current->colors[RD_ThemeColor_DropSiteOverlay]; - ws->cfg_palettes[RD_PaletteCode_DropSiteOverlay].text = current->colors[RD_ThemeColor_DropSiteOverlay]; - ws->cfg_palettes[RD_PaletteCode_DropSiteOverlay].text_weak = current->colors[RD_ThemeColor_DropSiteOverlay]; - ws->cfg_palettes[RD_PaletteCode_DropSiteOverlay].border = current->colors[RD_ThemeColor_DropSiteOverlay]; - if(rd_setting_val_from_code(RD_SettingCode_OpaqueBackgrounds).s32) + else { - for EachEnumVal(RD_PaletteCode, code) + rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("fullscreen"))); + } + if(is_maximized) + { + rd_cfg_child_from_string_or_alloc(window, str8_lit("maximized")); + } + else + { + rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("maximized"))); + } + + //- rjf: commit position + Rng2F32 window_rect = os_rect_from_window(ws->os); + if(!is_fullscreen && !is_maximized && !is_minimized) + { + Vec2F32 pos = window_rect.p0; + RD_Cfg *pos_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("pos")); + if((S32)pos.x != (S32)f64_from_str8(pos_root->first->string) || + (S32)pos.y != (S32)f64_from_str8(pos_root->last->string)) { - if(ws->cfg_palettes[code].background.x != 0 || - ws->cfg_palettes[code].background.y != 0 || - ws->cfg_palettes[code].background.z != 0) + RD_Cfg *x = pos_root->first; + if(x == &rd_nil_cfg) { - ws->cfg_palettes[code].background.w = 1; + x= rd_cfg_alloc(); + rd_cfg_insert_child(pos_root, &rd_nil_cfg, x); } + RD_Cfg *y = x->next; + if(y == &rd_nil_cfg) + { + y = rd_cfg_alloc(); + rd_cfg_insert_child(pos_root, x, y); + } + rd_cfg_equip_stringf(x, "%i", (S32)pos.x); + rd_cfg_equip_stringf(y, "%i", (S32)pos.y); } } + + //- rjf: commit size + if(!is_fullscreen && !is_maximized && !is_minimized) + { + Vec2F32 size = dim_2f32(window_rect); + RD_Cfg *size_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("size")); + if((S32)size.x != (S32)f64_from_str8(size_root->first->string) || + (S32)size.y != (S32)f64_from_str8(size_root->last->string)) + { + RD_Cfg *width = size_root->first; + if(width == &rd_nil_cfg) + { + width = rd_cfg_alloc(); + rd_cfg_insert_child(size_root, &rd_nil_cfg, width); + } + RD_Cfg *height = width->next; + if(height == &rd_nil_cfg) + { + height = rd_cfg_alloc(); + rd_cfg_insert_child(size_root, width, height); + } + rd_cfg_equip_stringf(width, "%i", (S32)size.x); + rd_cfg_equip_stringf(height, "%i", (S32)size.y); + } + } + + //- rjf: commit monitor + if(!is_minimized) + { + OS_Handle monitor = os_monitor_from_window(ws->os); + String8 monitor_name = os_name_from_monitor(scratch.arena, monitor); + RD_Cfg *monitor_root = rd_cfg_child_from_string_or_alloc(window, str8_lit("monitor")); + if(!str8_match(monitor_root->first->string, monitor_name, 0)) + { + rd_cfg_new_replace(monitor_root, monitor_name); + } + } + scratch_end(scratch); } ////////////////////////////// - //- rjf: build UI + //- rjf: @window_frame_part build UI // - UI_Box *autocomp_box = &ui_nil_box; - UI_Box *hover_eval_box = &ui_nil_box; + UI_Box *lister_box = &ui_nil_box; ProfScope("build UI") { //////////////////////////// - //- rjf: set up + //- rjf: @window_ui_part set up // { - // rjf: gather font info - FNT_Tag main_font = rd_font_from_slot(RD_FontSlot_Main); - F32 main_font_size = rd_font_size_from_slot(RD_FontSlot_Main); - FNT_Tag icon_font = rd_font_from_slot(RD_FontSlot_Icons); + // rjf: get top-level font size info + F32 top_level_font_size = 0; + RD_RegsScope(.view = 0, .tab = 0) top_level_font_size = rd_font_size(); // rjf: build icon info UI_IconInfo icon_info = {0}; { - icon_info.icon_font = icon_font; + icon_info.icon_font = rd_font_from_slot(RD_FontSlot_Icons); icon_info.icon_kind_text_map[UI_IconKind_RightArrow] = rd_icon_kind_text_table[RD_IconKind_RightScroll]; icon_info.icon_kind_text_map[UI_IconKind_DownArrow] = rd_icon_kind_text_table[RD_IconKind_DownScroll]; icon_info.icon_kind_text_map[UI_IconKind_LeftArrow] = rd_icon_kind_text_table[RD_IconKind_LeftScroll]; @@ -3585,143 +6234,164 @@ rd_window_frame(RD_Window *ws) icon_info.icon_kind_text_map[UI_IconKind_CheckFilled] = rd_icon_kind_text_table[RD_IconKind_CheckFilled]; } - // rjf: build widget palette info - UI_WidgetPaletteInfo widget_palette_info = {0}; - { - widget_palette_info.tooltip_palette = rd_palette_from_code(RD_PaletteCode_Floating); - widget_palette_info.ctx_menu_palette = rd_palette_from_code(RD_PaletteCode_Floating); - widget_palette_info.scrollbar_palette = rd_palette_from_code(RD_PaletteCode_ScrollBarButton); - } - // rjf: build animation info UI_AnimationInfo animation_info = {0}; { - if(rd_setting_val_from_code(RD_SettingCode_HoverAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_HotAnimations;} - if(rd_setting_val_from_code(RD_SettingCode_PressAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_ActiveAnimations;} - if(rd_setting_val_from_code(RD_SettingCode_FocusAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_FocusAnimations;} - if(rd_setting_val_from_code(RD_SettingCode_TooltipAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_TooltipAnimations;} - if(rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_ContextMenuAnimations;} - if(rd_setting_val_from_code(RD_SettingCode_ScrollingAnimations).s32) {animation_info.flags |= UI_AnimationInfoFlag_ScrollingAnimations;} + animation_info.hot_animation_rate = rd_state->catchall_animation_rate; + animation_info.active_animation_rate = rd_state->catchall_animation_rate; + animation_info.focus_animation_rate = 1.f; + animation_info.tooltip_animation_rate = rd_state->tooltip_animation_rate; + animation_info.menu_animation_rate = rd_state->menu_animation_rate; + animation_info.scroll_animation_rate = rd_state->scrolling_animation_rate; } // rjf: begin & push initial stack values - ui_begin_build(ws->os, &ws->ui_events, &icon_info, &widget_palette_info, &animation_info, rd_state->frame_dt, rd_state->frame_dt); - ui_push_font(main_font); - ui_push_font_size(main_font_size); - ui_push_text_padding(main_font_size*0.3f); - ui_push_pref_width(ui_em(20.f, 1)); - ui_push_pref_height(ui_em(2.75f, 1.f)); - ui_push_palette(rd_palette_from_code(RD_PaletteCode_Base)); + ui_begin_build(ws->os, &ws->ui_events, &icon_info, ws->theme, &animation_info, rd_state->frame_dt, rd_state->frame_dt); + ui_push_font(rd_font_from_slot(RD_FontSlot_Main)); + ui_push_font_size(top_level_font_size); + ui_push_text_padding(floor_f32(ui_top_font_size()*0.3f)); + ui_push_pref_width(ui_px(floor_f32(ui_top_font_size()*20.f), 1.f)); + ui_push_pref_height(ui_px(floor_f32(ui_top_font_size()*3.f), 1.f)); ui_push_blur_size(10.f); FNT_RasterFlags text_raster_flags = 0; - if(rd_setting_val_from_code(RD_SettingCode_SmoothUIText).s32) {text_raster_flags |= FNT_RasterFlag_Smooth;} - if(rd_setting_val_from_code(RD_SettingCode_HintUIText).s32) {text_raster_flags |= FNT_RasterFlag_Hinted;} + if(rd_setting_b32_from_name(str8_lit("smooth_ui_text"))) {text_raster_flags |= FNT_RasterFlag_Smooth;} + if(rd_setting_b32_from_name(str8_lit("hint_ui_text"))) {text_raster_flags |= FNT_RasterFlag_Hinted;} ui_push_text_raster_flags(text_raster_flags); } //////////////////////////// - //- rjf: calculate top-level rectangles + //- rjf: @window_ui_part calculate code color slot RGBAs + // + for EachEnumVal(RD_CodeColorSlot, s) + { + ws->theme_code_colors[s] = ui_color_from_name(rd_code_color_slot_name_table[s]); + } + + //////////////////////////// + //- rjf: @window_ui_part calculate top-level rectangles/sizes // Rng2F32 window_rect = os_client_rect_from_window(ws->os); Vec2F32 window_rect_dim = dim_2f32(window_rect); - Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x+1, window_rect.y0+ui_top_pref_height().value); - Rng2F32 bottom_bar_rect = r2f32p(window_rect.x0, window_rect_dim.y - ui_top_pref_height().value, window_rect.x0+window_rect_dim.x, window_rect.y0+window_rect_dim.y); + F32 top_bar_dim_px = floor_f32(ui_top_font_size()*3.f); + Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x+1, window_rect.y0+top_bar_dim_px); + Rng2F32 bottom_bar_rect = r2f32p(window_rect.x0, window_rect_dim.y - top_bar_dim_px, window_rect.x0+window_rect_dim.x, window_rect.y0+window_rect_dim.y); Rng2F32 content_rect = r2f32p(window_rect.x0, top_bar_rect.y1, window_rect.x0+window_rect_dim.x, bottom_bar_rect.y0); F32 window_edge_px = os_dpi_from_window(ws->os)*0.035f; content_rect = pad_2f32(content_rect, -window_edge_px); //////////////////////////// - //- rjf: truncated string hover + //- rjf: @window_ui_part truncated string hover // if(ui_string_hover_active()) UI_Tooltip { Temp scratch = scratch_begin(0, 0); - String8 string = ui_string_hover_string(scratch.arena); - DR_FancyRunList runs = ui_string_hover_runs(scratch.arena); + DR_FStrList fstrs = ui_string_hover_fstrs(scratch.arena); UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_string_fancy_runs(box, string, &runs); + ui_box_equip_display_fstrs(box, &fstrs); scratch_end(scratch); } //////////////////////////// - //- rjf: rich hover, drag/drop tooltips + //- rjf: @window_ui_part rich hover / drag/drop tooltips // - if(rd_state->hover_regs_slot != RD_RegSlot_Null || - (rd_state->drag_drop_regs_slot != RD_RegSlot_Null && rd_drag_is_active())) + if((rd_state->hover_regs_slot != RD_RegSlot_Null && !rd_state->hover_regs->no_rich_tooltip) || (rd_state->drag_drop_regs_slot != RD_RegSlot_Null && rd_drag_is_active())) { Temp scratch = scratch_begin(0, 0); RD_RegSlot slot = ((rd_state->drag_drop_regs_slot != RD_RegSlot_Null && rd_drag_is_active()) ? rd_state->drag_drop_regs_slot : rd_state->hover_regs_slot); RD_Regs *regs = (((rd_state->drag_drop_regs_slot != RD_RegSlot_Null && rd_drag_is_active()) ? rd_state->drag_drop_regs : rd_state->hover_regs)); CTRL_Entity *ctrl_entity = &ctrl_entity_nil; - RD_Palette(RD_PaletteCode_Floating) switch(slot) + ui_state->tooltip_anchor_key = regs->ui_key; + ui_state->tooltip_can_overflow_window = rd_drag_is_active(); + switch(slot) { default:{}break; //////////////////////// - //- rjf: frontend entity tooltips + //- rjf: command tooltips // - case RD_RegSlot_Entity: + case RD_RegSlot_CmdName: + UI_Tooltip + { + String8 cmd_name = regs->cmd_name; + DR_FStrList fstrs = rd_title_fstrs_from_code_name(scratch.arena, cmd_name); + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(5, 1)) + { + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(box, &fstrs); + rd_cmd_binding_buttons(cmd_name, str8_zero(), 0); + } + }break; + + //////////////////////// + //- rjf: file path tooltips + // + case RD_RegSlot_FilePath: + UI_Tooltip + { + FileProperties props = os_properties_from_file_path(regs->file_path); + ui_set_next_pref_width(ui_children_sum(1)); + UI_Row + { + RD_Font(RD_FontSlot_Icons) ui_label(rd_icon_kind_text_table[props.flags & FilePropertyFlag_IsFolder ? RD_IconKind_FolderClosedFilled : RD_IconKind_FileOutline]); + ui_label(regs->file_path); + } + }break; + + //////////////////////// + //- rjf: cfg tooltips + // + case RD_RegSlot_Cfg: UI_Tooltip { // rjf: unpack - RD_Entity *entity = rd_entity_from_handle(regs->entity); - DR_FancyStringList fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, rd_rgba_from_theme_color(RD_ThemeColor_TextWeak), ui_top_font_size()); + RD_Cfg *cfg = rd_cfg_from_id(regs->cfg); + DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, cfg); // rjf: title UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(5, 1)) { UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &fstrs); - } - - // rjf: temporary target -> display - if(entity->kind == RD_EntityKind_Target && entity->cfg_src == RD_CfgSrc_CommandLine) - { - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_label(str8_lit("Specified on the command line; will not be saved.")); + ui_box_equip_display_fstrs(box, &fstrs); } }break; //////////////////////// //- rjf: control entity tooltips // - case RD_RegSlot_Machine: {ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->machine); }goto ctrl_entity_tooltip; - case RD_RegSlot_Process: {ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->process); }goto ctrl_entity_tooltip; - case RD_RegSlot_Module: {ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->module); }goto ctrl_entity_tooltip; - case RD_RegSlot_Thread: {ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->thread); }goto ctrl_entity_tooltip; - case RD_RegSlot_CtrlEntity:{ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->ctrl_entity); }goto ctrl_entity_tooltip; + case RD_RegSlot_Machine: {ctrl_entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, regs->machine); }goto ctrl_entity_tooltip; + case RD_RegSlot_Process: {ctrl_entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, regs->process); }goto ctrl_entity_tooltip; + case RD_RegSlot_Module: {ctrl_entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, regs->module); }goto ctrl_entity_tooltip; + case RD_RegSlot_Thread: {ctrl_entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, regs->thread); }goto ctrl_entity_tooltip; + case RD_RegSlot_CtrlEntity:{ctrl_entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, regs->ctrl_entity); }goto ctrl_entity_tooltip; ctrl_entity_tooltip:; UI_Tooltip { // rjf: unpack - DI_Scope *di_scope = di_scope_open(); Arch arch = ctrl_entity->arch; String8 arch_str = string_from_arch(arch); - DR_FancyStringList fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ctrl_entity, - rd_rgba_from_theme_color(RD_ThemeColor_TextWeak), - ui_top_font_size(), 0); + DR_FStrList fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ctrl_entity, 0); // rjf: title UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(5, 1)) { UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &fstrs); + ui_box_equip_display_fstrs(box, &fstrs); ui_spacer(ui_em(0.5f, 1.f)); UI_FontSize(ui_top_font_size() - 1.f) UI_CornerRadius(ui_top_font_size()*0.5f) - RD_Palette(RD_PaletteCode_NeutralPopButton) { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_label(arch_str); + UI_TagF("weak") UI_FlagsAdd(UI_BoxFlag_DrawBorder) ui_label(arch_str); ui_spacer(ui_em(0.5f, 1.f)); if(ctrl_entity->kind == CTRL_EntityKind_Thread || ctrl_entity->kind == CTRL_EntityKind_Process) { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_labelf("ID: %i", (U32)ctrl_entity->id); + UI_TagF("weak") UI_FlagsAdd(UI_BoxFlag_DrawBorder) ui_labelf("ID: %i", (U32)ctrl_entity->id); } } } // rjf: debug info status - if(ctrl_entity->kind == CTRL_EntityKind_Module) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + if(ctrl_entity->kind == CTRL_EntityKind_Module) UI_TagF("weak") { DI_Scope *di_scope = di_scope_open(); DI_Key dbgi_key = ctrl_dbgi_key_from_module(ctrl_entity); @@ -3742,119 +6412,110 @@ rd_window_frame(RD_Window *ws) } // rjf: unwind - if(ctrl_entity->kind == CTRL_EntityKind_Thread) + if(ctrl_entity->kind == CTRL_EntityKind_Thread) RD_Font(RD_FontSlot_Code) { + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + Vec4F32 code_color = ui_color_from_name(str8_lit("code_default")); + Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(ctrl_entity); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &base_unwind); - if(rich_unwind.concrete_frame_count != 0) + B32 call_stack_high_priority = ctrl_handle_match(ctrl_entity->handle, rd_base_regs()->thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, ctrl_entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + if(call_stack.frames_count != 0) { ui_spacer(ui_em(1.5f, 1.f)); } - for(U64 idx = 0; idx < rich_unwind.concrete_frame_count; idx += 1) + EV_StringParams string_params = {EV_StringFlag_ReadOnlyDisplayRules, .radix = 16}; + String8 thread_handle_string = ctrl_string_from_handle(scratch.arena, ctrl_entity->handle); + for(U64 idx = 0; idx < 16; idx += 1) { - CTRL_CallStackFrame *f = &rich_unwind.frames[idx]; - RDI_Parsed *rdi = f->rdi; - RDI_Procedure *procedure = f->procedure; - U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - String8 module_name = module == &ctrl_entity_nil ? str8_lit("???") : str8_skip_last_slash(module->string); - - // rjf: inline frames - for(CTRL_CallStackInlineFrame *fin = f->last_inline_frame; fin != 0; fin = fin->prev) - UI_PrefWidth(ui_children_sum(1)) UI_Row + E_Eval rip_eval = e_eval_from_stringf("query:control.%S.call_stack[%I64u]", thread_handle_string, idx); + if(rip_eval.irtree.mode != E_Mode_Value) { - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, fin->inline_site->name_string_idx, &name.size); - name.size = Min(512, name.size); - UI_TextAlignment(UI_TextAlign_Left) RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(12.f, 1)) ui_labelf("0x%I64x", rip_vaddr); - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_label(str8_lit("[inlined]")); - if(name.size != 0) - { - RD_Font(RD_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1)) - { - rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - } - } - else - { - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name); - } + break; } - - // rjf: concrete frame - UI_PrefWidth(ui_children_sum(1)) UI_Row + String8 rip_value_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, ui_top_font(), ui_top_font_size(), ui_top_font_size()*40.f, rip_eval); + rd_code_label(1, 0, code_color, rip_value_string); + } + ctrl_scope_close(ctrl_scope); + } + + }break; + + //////////////////////// + //- rjf: expression tooltips + // + case RD_RegSlot_Expr: + UI_Tooltip RD_Font(RD_FontSlot_Code) + { + ui_set_next_pref_width(ui_children_sum(1)); + UI_Row + { + rd_code_label(1.f, 0, ui_color_from_name(str8_lit("text")), rd_state->drag_drop_regs->expr); + E_Eval eval = e_eval_from_string(rd_state->drag_drop_regs->expr); + if(eval.irtree.mode != E_Mode_Null) + { + EV_StringParams string_params = {.flags = EV_StringFlag_ReadOnlyDisplayRules, .radix = 10}; + String8 value_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, ui_top_font(), ui_top_font_size(), ui_top_font_size()*20.f, eval); + if(value_string.size != 0) { - String8 name = {0}; - name.str = rdi_name_from_procedure(rdi, procedure, &name.size); - name.size = Min(512, name.size); - UI_TextAlignment(UI_TextAlign_Left) RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(12.f, 1)) ui_labelf("0x%I64x", rip_vaddr); - if(name.size != 0) - { - RD_Font(RD_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1)) - { - rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - } - } - else - { - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name); - } + ui_spacer(ui_em(2.f, 1.f)); + rd_code_label(1.f, 0, ui_color_from_name(str8_lit("text")), value_string); } } } - - di_scope_close(di_scope); }break; } scratch_end(scratch); } //////////////////////////// - //- rjf: drag/drop visualization tooltips + //- rjf: @window_ui_part drag/drop visualization tooltips // if(rd_drag_is_active() && window_is_focused) RD_RegsScope(.window = rd_state->drag_drop_regs->window, .panel = rd_state->drag_drop_regs->panel, + .tab = 0, .view = rd_state->drag_drop_regs->view) { Temp scratch = scratch_begin(0, 0); - RD_Panel *panel = rd_panel_from_handle(rd_state->drag_drop_regs->panel); - RD_Entity *entity = rd_entity_from_handle(rd_state->drag_drop_regs->entity); - RD_View *view = rd_view_from_handle(rd_state->drag_drop_regs->view); + RD_Cfg *view = rd_cfg_from_id(rd_state->drag_drop_regs->view); { //- rjf: tab dragging - if(rd_state->drag_drop_regs_slot == RD_RegSlot_View && !rd_view_is_nil(view)) + if(rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &rd_nil_cfg) { + RD_Cfg *immediate_parent = &rd_nil_cfg; + for(RD_Cfg *p = view->parent; p != &rd_nil_cfg; p = p->parent) + { + if(str8_match(p->parent->string, str8_lit("immediate"), 0)) + { + immediate_parent = p->parent; + break; + } + } + if(immediate_parent != &rd_nil_cfg) + { + rd_cfg_child_from_string_or_alloc(immediate_parent, str8_lit("hot")); + } UI_Size main_width = ui_top_pref_width(); UI_Size main_height = ui_top_pref_height(); UI_TextAlign main_text_align = ui_top_text_alignment(); - RD_Palette(RD_PaletteCode_Tab) - UI_Tooltip + UI_Tooltip UI_PrefWidth(main_width) UI_PrefHeight(main_height) UI_TextAlignment(main_text_align) { + ui_state->tooltip_can_overflow_window = 1; ui_set_next_pref_width(ui_em(60.f, 1.f)); ui_set_next_pref_height(ui_em(40.f, 1.f)); ui_set_next_child_layout_axis(Axis2_Y); UI_Box *container = ui_build_box_from_key(0, ui_key_zero()); UI_Parent(container) { - UI_Row + UI_Row UI_PrefWidth(ui_text_dim(10, 1)) { - RD_IconKind icon_kind = rd_icon_kind_from_view(view); - DR_FancyStringList fstrs = rd_title_fstrs_from_view(scratch.arena, view, ui_top_palette()->text, ui_top_palette()->text_weak, ui_top_font_size()); - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_PrefWidth(ui_em(2.5f, 1.f)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_label(rd_icon_kind_text_table[icon_kind]); - UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(name_box, &fstrs); - } + DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, view); + UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(name_box, &fstrs); } ui_set_next_pref_width(ui_pct(1, 0)); ui_set_next_pref_height(ui_pct(1, 0)); @@ -3862,8 +6523,7 @@ rd_window_frame(RD_Window *ws) UI_Box *view_preview_container = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "###view_preview_container"); UI_Parent(view_preview_container) UI_Focus(UI_FocusKind_Off) UI_WidthFill { - RD_ViewRuleUIFunctionType *view_ui = view->spec->ui; - view_ui(str8(view->query_buffer, view->query_string_size), view->params_roots[view->params_read_gen%ArrayCount(view->params_roots)], view_preview_container->rect); + rd_view_ui(view_preview_container->rect); } } } @@ -3873,12 +6533,12 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: developer menu + //- rjf: @window_ui_part developer menu // if(ws->dev_menu_is_open) RD_Font(RD_FontSlot_Code) { ui_set_next_flags(UI_BoxFlag_ViewScrollY|UI_BoxFlag_AllowOverflowY|UI_BoxFlag_ViewClamp); - UI_PaneF(r2f32p(30, 30, 30+ui_top_font_size()*100, ui_top_font_size()*150), "###dev_ctx_menu") + UI_PaneF(r2f32p(30, 30, 30+ui_top_font_size()*100, ui_top_font_size()*60), "###dev_ctx_menu") { //- rjf: capture if(!ProfIsCapturing() && ui_clicked(ui_buttonf("Begin Profiler Capture###prof_cap"))) @@ -3923,11 +6583,11 @@ rd_window_frame(RD_Window *ws) ui_divider(ui_em(1.f, 1.f)); ui_label(regs_info[idx].name); RD_Regs *regs = regs_info[idx].regs; -#define Handle(name) ui_labelf("%s: [0x%I64x, 0x%I64x]", #name, (regs->name).u64[0], (regs->name).u64[1]) - Handle(window); - Handle(panel); - Handle(view); -#undef Handle +#define ID(name) ui_labelf("%s: $0x%I64x", #name, (regs->name)) + ID(window); + ID(panel); + ID(view); +#undef ID #define Handle(name) ui_labelf("%s: [0x%I64x, 0x%I64x]", #name, (regs->name).machine_id, (regs->name).dmn_handle.u64[0]) Handle(machine); Handle(process); @@ -3939,7 +6599,7 @@ rd_window_frame(RD_Window *ws) ui_labelf("mark: (L:%I64d, C:%I64d)", regs->mark.line, regs->mark.column); ui_labelf("unwind_count: %I64u", regs->unwind_count); ui_labelf("inline_depth: %I64u", regs->inline_depth); - ui_labelf("text_key: [0x%I64x, 0x%I64x]", regs->text_key.u64[0], regs->text_key.u64[1]); + ui_labelf("text_key: [0x%I64x / 0x%I64x:0x%I64x]", regs->text_key.root.u64[0], regs->text_key.id.u128[0].u64[0], regs->text_key.id.u128[0].u64[1]); ui_labelf("lang_kind: '%S'", txt_extension_from_lang_kind(regs->lang_kind)); ui_labelf("vaddr_range: [0x%I64x, 0x%I64x)", regs->vaddr_range.min, regs->vaddr_range.max); ui_labelf("voff_range: [0x%I64x, 0x%I64x)", regs->voff_range.min, regs->voff_range.max); @@ -3948,17 +6608,17 @@ rd_window_frame(RD_Window *ws) ui_divider(ui_em(1.f, 1.f)); //- rjf: draw per-window stats - for(RD_Window *window = rd_state->first_window; window != 0; window = window->next) + for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) { // rjf: calc ui hash chain length F64 avg_ui_hash_chain_length = 0; { F64 chain_count = 0; F64 chain_length_sum = 0; - for(U64 idx = 0; idx < ws->ui->box_table_size; idx += 1) + for(U64 idx = 0; idx < w->ui->box_table_size; idx += 1) { F64 chain_length = 0; - for(UI_Box *b = ws->ui->box_table[idx].hash_first; !ui_box_is_nil(b); b = b->hash_next) + for(UI_Box *b = w->ui->box_table[idx].hash_first; !ui_box_is_nil(b); b = b->hash_next) { chain_length += 1; } @@ -3973,13 +6633,13 @@ rd_window_frame(RD_Window *ws) ui_labelf("Target Hz: %.2f", 1.f/rd_state->frame_dt); ui_labelf("Ctrl Run Index: %I64u", ctrl_run_gen()); ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_mem_gen()); - ui_labelf("Window %p", window); + ui_labelf("Window %p", w); ui_set_next_pref_width(ui_children_sum(1)); ui_set_next_pref_height(ui_children_sum(1)); UI_Row { ui_spacer(ui_em(2.f, 1.f)); - ui_labelf("Box Count: %I64u", window->ui->last_build_box_count); + ui_labelf("Box Count: %I64u", w->ui->last_build_box_count); } ui_set_next_pref_width(ui_children_sum(1)); ui_set_next_pref_height(ui_children_sum(1)); @@ -3991,663 +6651,17 @@ rd_window_frame(RD_Window *ws) } ui_divider(ui_em(1.f, 1.f)); - - //- rjf: draw entity tree -#if 0 - RD_EntityRec rec = {0}; - S32 indent = 0; - UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("Entity Tree:"); - for(RD_Entity *e = rd_entity_root(); !rd_entity_is_nil(e); e = rec.next) - { - ui_set_next_pref_width(ui_children_sum(1)); - ui_set_next_pref_height(ui_children_sum(1)); - UI_Row - { - ui_spacer(ui_em(2.f*indent, 1.f)); - RD_Entity *dst = rd_entity_from_handle(e->entity_handle); - if(!rd_entity_is_nil(dst)) - { - ui_labelf("[link] %S -> %S", e->string, dst->string); - } - else - { - ui_labelf("%S: %S", d_entity_kind_display_string_table[e->kind], e->string); - } - } - rec = rd_entity_rec_depth_first_pre(e, rd_entity_root()); - indent += rec.push_count; - indent -= rec.pop_count; - } -#endif } } //////////////////////////// - //- rjf: top-level registers context menu - // - RD_Palette(RD_PaletteCode_Floating) UI_CtxMenu(rd_state->ctx_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - Temp scratch = scratch_begin(0, 0); - RD_Regs *regs = ws->ctx_menu_regs; - RD_RegSlot slot = ws->ctx_menu_regs_slot; - CTRL_Entity *ctrl_entity = &ctrl_entity_nil; - { - switch(slot) - { - default:{}break; - - ////////////////////// - //- rjf: source code locations - // - case RD_RegSlot_Cursor: - { - // TODO(rjf): with new registers-based commands, all of this can be deduplicated with the - // command-based path, but I am holding off on that until post 0.9.12 - these should be - // able to just all push commands for their corresponding actions - // - TXT_Scope *txt_scope = txt_scope_open(); - HS_Scope *hs_scope = hs_scope_open(); - TxtRng range = txt_rng(regs->cursor, regs->mark); - D_LineList lines = regs->lines; - if(!txt_pt_match(range.min, range.max) && ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_Copy].string))) - { - U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, regs->text_key, regs->lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); - String8 copy_data = txt_string_from_info_data_txt_rng(&info, data, range); - os_set_clipboard_text(copy_data); - ui_ctx_menu_close(); - } - if(range.min.line == range.max.line && ui_clicked(rd_icon_buttonf(RD_IconKind_RightArrow, 0, "Set Next Statement"))) - { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - U64 new_rip_vaddr = regs->vaddr; - if(regs->file_path.size != 0) - { - for(D_LineNode *n = lines.first; n != 0; n = n->next) - { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &n->v.dbgi_key); - CTRL_Entity *module = ctrl_module_from_thread_candidates(d_state->ctrl_entity_store, thread, &modules); - if(module != &ctrl_entity_nil) - { - new_rip_vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); - break; - } - } - } - rd_cmd(RD_CmdKind_SetThreadIP, .vaddr = new_rip_vaddr); - ui_ctx_menu_close(); - } - if(range.min.line == range.max.line && ui_clicked(rd_icon_buttonf(RD_IconKind_Play, 0, "Run To Line"))) - { - if(regs->file_path.size != 0) - { - rd_cmd(RD_CmdKind_RunToLine, .file_path = regs->file_path, .cursor = range.min); - } - else - { - rd_cmd(RD_CmdKind_RunToAddress, .vaddr = regs->vaddr); - } - ui_ctx_menu_close(); - } - if(range.min.line == range.max.line && ui_clicked(rd_icon_buttonf(RD_IconKind_Null, 0, "Go To Name"))) - { - U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, regs->text_key, regs->lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); - Rng1U64 expr_off_range = {0}; - if(range.min.column != range.max.column) - { - expr_off_range = r1u64(txt_off_from_info_pt(&info, range.min), txt_off_from_info_pt(&info, range.max)); - } - else - { - expr_off_range = txt_expr_off_range_from_info_data_pt(&info, data, range.min); - } - String8 expr = str8_substr(data, expr_off_range); - rd_cmd(RD_CmdKind_GoToName, .string = expr); - ui_ctx_menu_close(); - } - if(range.min.line == range.max.line && ui_clicked(rd_icon_buttonf(RD_IconKind_CircleFilled, 0, "Toggle Breakpoint"))) - { - rd_cmd(RD_CmdKind_ToggleBreakpoint, - .file_path = regs->file_path, - .cursor = range.min, - .vaddr = regs->vaddr); - ui_ctx_menu_close(); - } - if(range.min.line == range.max.line && ui_clicked(rd_icon_buttonf(RD_IconKind_Binoculars, 0, "Toggle Watch Expression"))) - { - U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, regs->text_key, regs->lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); - Rng1U64 expr_off_range = {0}; - if(range.min.column != range.max.column) - { - expr_off_range = r1u64(txt_off_from_info_pt(&info, range.min), txt_off_from_info_pt(&info, range.max)); - } - else - { - expr_off_range = txt_expr_off_range_from_info_data_pt(&info, data, range.min); - } - String8 expr = str8_substr(data, expr_off_range); - rd_cmd(RD_CmdKind_ToggleWatchExpression, .string = expr); - ui_ctx_menu_close(); - } - if(regs->file_path.size == 0 && range.min.line == range.max.line && ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_GoToSource].string))) - { - rd_cmd(RD_CmdKind_GoToSource, .lines = lines); - ui_ctx_menu_close(); - } - if(regs->file_path.size != 0 && range.min.line == range.max.line && ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_GoToDisassembly].string))) - { - rd_cmd(RD_CmdKind_GoToDisassembly, .lines = lines); - ui_ctx_menu_close(); - } - hs_scope_close(hs_scope); - txt_scope_close(txt_scope); - }break; - - ////////////////////// - //- rjf: tabs - // - case RD_RegSlot_View: - { - RD_Panel *panel = rd_panel_from_handle(regs->panel); - RD_View *view = rd_view_from_handle(regs->view); - RD_IconKind view_icon = rd_icon_kind_from_view(view); - DR_FancyStringList fstrs = rd_title_fstrs_from_view(scratch.arena, view, ui_top_palette()->text, ui_top_palette()->text_weak, ui_top_font_size()); - String8 file_path = rd_file_path_from_eval_string(scratch.arena, str8(view->query_buffer, view->query_string_size)); - - // rjf: title - UI_Row - { - ui_spacer(ui_em(1.f, 1.f)); - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_PrefWidth(ui_em(2.f, 1.f)) - UI_PrefHeight(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_label(rd_icon_kind_text_table[view_icon]); - UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(name_box, &fstrs); - } - } - - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - - // rjf: copy name - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Clipboard, 0, "Copy Name"))) - { - os_set_clipboard_text(dr_string_from_fancy_string_list(scratch.arena, &fstrs)); - ui_ctx_menu_close(); - } - - // rjf: copy full path - if(file_path.size != 0) - { - UI_Signal copy_full_path_sig = rd_icon_buttonf(RD_IconKind_Clipboard, 0, "Copy Full Path"); - String8 full_path = path_normalized_from_string(scratch.arena, file_path); - if(ui_clicked(copy_full_path_sig)) - { - os_set_clipboard_text(full_path); - ui_ctx_menu_close(); - } - if(ui_hovering(copy_full_path_sig)) UI_Tooltip - { - ui_label(full_path); - } - } - - // rjf: show in explorer - if(file_path.size != 0) - { - UI_Signal sig = rd_icon_buttonf(RD_IconKind_FolderClosedFilled, 0, "Show In Explorer"); - if(ui_clicked(sig)) - { - String8 full_path = path_normalized_from_string(scratch.arena, file_path); - os_show_in_filesystem_ui(full_path); - ui_ctx_menu_close(); - } - } - - // rjf: filter controls - if(view->spec->flags & RD_ViewRuleInfoFlag_CanFilter) - { - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_Filter].string))) - { - rd_cmd(RD_CmdKind_Filter, .panel = rd_handle_from_panel(panel), .view = rd_handle_from_view(view)); - ui_ctx_menu_close(); - } - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_ClearFilter].string))) - { - rd_cmd(RD_CmdKind_ClearFilter, .panel = rd_handle_from_panel(panel), .view = rd_handle_from_view(view)); - ui_ctx_menu_close(); - } - } - - // rjf: close tab - if(ui_clicked(rd_icon_buttonf(RD_IconKind_X, 0, "Close Tab"))) - { - rd_cmd(RD_CmdKind_CloseTab, .panel = rd_handle_from_panel(panel), .view = rd_handle_from_view(view)); - ui_ctx_menu_close(); - } - - // rjf: param tree editing - UI_TextPadding(ui_top_font_size()*1.5f) RD_Font(RD_FontSlot_Code) - { - Temp scratch = scratch_begin(0, 0); - String8 schema_string = view->spec->params_schema; - MD_TokenizeResult schema_tokenize = md_tokenize_from_text(scratch.arena, schema_string); - MD_ParseResult schema_parse = md_parse_from_text_tokens(scratch.arena, str8_zero(), schema_string, schema_tokenize.tokens); - MD_Node *schema_root = schema_parse.root->first; - if(!md_node_is_nil(schema_root)) - { - if(!md_node_is_nil(schema_root->first)) - { - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - } - for MD_EachNode(key, schema_root->first) - { - UI_Row - { - MD_Node *params = view->params_roots[view->params_write_gen%ArrayCount(view->params_roots)]; - MD_Node *param_tree = md_child_from_string(params, key->string, 0); - String8 pre_edit_value = md_string_from_children(scratch.arena, param_tree); - UI_PrefWidth(ui_em(10.f, 1.f)) ui_label(key->string); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border|RD_LineEditFlag_CodeContents, 0, 0, &ws->ctx_menu_input_cursor, &ws->ctx_menu_input_mark, ws->ctx_menu_input_buffer, ws->ctx_menu_input_buffer_size, &ws->ctx_menu_input_string_size, 0, pre_edit_value, "%S##view_param", key->string); - if(ui_committed(sig)) - { - String8 new_string = str8(ws->ctx_menu_input_buffer, ws->ctx_menu_input_string_size); - rd_view_store_param(view, key->string, new_string); - } - } - } - } - scratch_end(scratch); - } - }break; - - ////////////////////// - //- rjf: ctrl entities - // - case RD_RegSlot_Machine: ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->machine); goto ctrl_entity_title; - case RD_RegSlot_Process: ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->process); goto ctrl_entity_title; - case RD_RegSlot_Module: ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->module); goto ctrl_entity_title; - case RD_RegSlot_Thread: ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->thread); goto ctrl_entity_title; - case RD_RegSlot_CtrlEntity: ctrl_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, regs->ctrl_entity); goto ctrl_entity_title; - ctrl_entity_title:; - { - //- rjf: title - UI_Row - UI_PrefWidth(ui_text_dim(5, 1)) - UI_TextAlignment(UI_TextAlign_Center) - UI_TextPadding(ui_top_font_size()*1.5f) - { - DR_FancyStringList fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ctrl_entity, ui_top_palette()->text_weak, ui_top_font_size(), 0); - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &fstrs); - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - ui_spacer(ui_em(0.5f, 1.f)); - UI_FontSize(ui_top_font_size() - 1.f) - UI_CornerRadius(ui_top_font_size()*0.5f) - RD_Palette(RD_PaletteCode_NeutralPopButton) - UI_TextPadding(ui_top_font_size()*0.5f) - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_label(string_from_arch(ctrl_entity->arch)); - ui_spacer(ui_em(0.5f, 1.f)); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_labelf("TID: %i", (U32)ctrl_entity->id); - } - } - } - - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - - //- rjf: name editor - if(ctrl_entity->kind == CTRL_EntityKind_Thread) RD_Font(RD_FontSlot_Code) UI_TextPadding(ui_top_font_size()*1.5f) - { - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border|RD_LineEditFlag_CodeContents, 0, 0, &ws->ctx_menu_input_cursor, &ws->ctx_menu_input_mark, ws->ctx_menu_input_buffer, ws->ctx_menu_input_buffer_size, &ws->ctx_menu_input_string_size, 0, ctrl_entity->string, "Name###ctrl_entity_string_edit_%p", ctrl_entity); - if(ui_committed(sig)) - { - rd_cmd(RD_CmdKind_SetEntityName, .ctrl_entity = ctrl_entity->handle, .string = str8(ws->ctx_menu_input_buffer, ws->ctx_menu_input_string_size)); - } - } - - // rjf: copy full path - if(ctrl_entity->kind == CTRL_EntityKind_Module) if(ui_clicked(rd_icon_buttonf(RD_IconKind_Clipboard, 0, "Copy Full Path"))) - { - os_set_clipboard_text(ctrl_entity->string); - ui_ctx_menu_close(); - } - - // rjf: copy ID - if((ctrl_entity->kind == CTRL_EntityKind_Thread || - ctrl_entity->kind == CTRL_EntityKind_Process) && - ui_clicked(rd_icon_buttonf(RD_IconKind_Clipboard, 0, "Copy ID"))) - { - String8 string = str8_from_u64(scratch.arena, ctrl_entity->id, 10, 0, 0); - os_set_clipboard_text(string); - ui_ctx_menu_close(); - } - - // rjf: copy call stack - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Clipboard, 0, "Copy Call Stack"))) - { - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(ctrl_entity, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(ctrl_entity); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &base_unwind); - String8List lines = {0}; - for(U64 frame_idx = 0; frame_idx < rich_unwind.concrete_frame_count; frame_idx += 1) - { - CTRL_CallStackFrame *concrete_frame = &rich_unwind.frames[frame_idx]; - U64 rip_vaddr = regs_rip_from_arch_block(ctrl_entity->arch, concrete_frame->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - RDI_Parsed *rdi = concrete_frame->rdi; - RDI_Procedure *procedure = concrete_frame->procedure; - for(CTRL_CallStackInlineFrame *inline_frame = concrete_frame->last_inline_frame; - inline_frame != 0; - inline_frame = inline_frame->prev) - { - RDI_InlineSite *inline_site = inline_frame->inline_site; - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size); - str8_list_pushf(scratch.arena, &lines, "0x%I64x: [inlined] \"%S\"%s%S", rip_vaddr, name, module == &ctrl_entity_nil ? "" : " in ", module->string); - } - if(procedure != 0) - { - String8 name = {0}; - name.str = rdi_name_from_procedure(rdi, procedure, &name.size); - str8_list_pushf(scratch.arena, &lines, "0x%I64x: \"%S\"%s%S", rip_vaddr, name, module == &ctrl_entity_nil ? "" : " in ", module->string); - } - else if(module != &ctrl_entity_nil) - { - str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in %S]", rip_vaddr, module->string); - } - else - { - str8_list_pushf(scratch.arena, &lines, "0x%I64x: [??? in ???]", rip_vaddr); - } - } - StringJoin join = {0}; - join.sep = join.post = str8_lit("\n"); - String8 text = str8_list_join(scratch.arena, &lines, &join); - os_set_clipboard_text(text); - ui_ctx_menu_close(); - di_scope_close(di_scope); - } - } - - // rjf: find - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_FileOutline, 0, "Find"))) - { - rd_cmd(RD_CmdKind_FindThread, .thread = ctrl_entity->handle); - ui_ctx_menu_close(); - } - } - - // rjf: selection - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - B32 is_selected = ctrl_handle_match(rd_base_regs()->thread, ctrl_entity->handle); - if(is_selected) - { - rd_icon_buttonf(RD_IconKind_Thread, 0, "[Selected]###select_entity"); - } - else if(ui_clicked(rd_icon_buttonf(RD_IconKind_Thread, 0, "Select###select_entity"))) - { - rd_cmd(RD_CmdKind_SelectThread, .thread = ctrl_entity->handle); - ui_ctx_menu_close(); - } - } - - // rjf: freezing - if(ctrl_entity->kind == CTRL_EntityKind_Thread || - ctrl_entity->kind == CTRL_EntityKind_Process || - ctrl_entity->kind == CTRL_EntityKind_Machine) - { - B32 is_frozen = ctrl_entity_tree_is_frozen(ctrl_entity); - ui_set_next_palette(rd_palette_from_code(is_frozen ? RD_PaletteCode_NegativePopButton : RD_PaletteCode_PositivePopButton)); - if(is_frozen && ui_clicked(rd_icon_buttonf(RD_IconKind_Locked, 0, "Thaw###freeze_thaw"))) - { - rd_cmd(RD_CmdKind_ThawThread, .ctrl_entity = ctrl_entity->handle); - } - if(!is_frozen && ui_clicked(rd_icon_buttonf(RD_IconKind_Unlocked, 0, "Freeze###freeze_thaw"))) - { - rd_cmd(RD_CmdKind_FreezeThread, .ctrl_entity = ctrl_entity->handle); - } - } - - // rjf: callstack -#if 0 - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - if(ctrl_entity->kind == CTRL_EntityKind_Thread) UI_TextPadding(ui_top_font_size()*1.5f) - { - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *thread = ctrl_entity; - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &base_unwind); - for(U64 idx = 0; idx < rich_unwind.concrete_frame_count; idx += 1) - { - CTRL_CallStackFrame *f = &rich_unwind.frames[idx]; - RDI_Parsed *rdi = f->rdi; - RDI_Procedure *procedure = f->procedure; - U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, f->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - String8 module_name = module == &ctrl_entity_nil ? str8_lit("???") : str8_skip_last_slash(module->string); - - // rjf: inline frames - for(CTRL_CallStackInlineFrame *fin = f->last_inline_frame; fin != 0; fin = fin->prev) - { - UI_Box *row = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_ClickToFocus, "###callstack_row_%I64x", idx); - UI_Signal sig = ui_signal_from_box(row); - ui_push_parent(row); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, fin->inline_site->name_string_idx, &name.size); - UI_TextAlignment(UI_TextAlign_Left) RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(16.f, 1)) ui_labelf("0x%I64x", rip_vaddr); - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_label(str8_lit("[inlined]")); - if(name.size != 0) - { - RD_Font(RD_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1)) - { - rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - } - } - else - { - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name); - } - ui_pop_parent(); - } - - // rjf: concrete frame - { - UI_Box *row = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_ClickToFocus, "###callstack_row_%I64x", idx); - UI_Signal sig = ui_signal_from_box(row); - ui_push_parent(row); - String8 name = {0}; - name.str = rdi_name_from_procedure(rdi, procedure, &name.size); - UI_TextAlignment(UI_TextAlign_Left) RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(16.f, 1)) ui_labelf("0x%I64x", rip_vaddr); - if(name.size != 0) - { - RD_Font(RD_FontSlot_Code) UI_PrefWidth(ui_text_dim(10, 1)) - { - rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - } - } - else - { - RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_text_dim(10, 1)) ui_labelf("[??? in %S]", module_name); - } - ui_pop_parent(); - } - } - di_scope_close(di_scope); - } -#endif - - // rjf: color editor -#if 0 - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - { - UI_Padding(ui_em(1.5f, 1.f)) - { - ui_set_next_pref_height(ui_em(9.f, 1.f)); - UI_Row UI_Padding(ui_pct(1, 0)) - { - UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) UI_Column UI_PrefHeight(ui_em(1.5f, 0.f)) - { - Vec4F32 presets[] = - { - v4f32(1.0f, 0.2f, 0.1f, 1.0f), - v4f32(1.0f, 0.8f, 0.2f, 1.0f), - v4f32(0.3f, 0.8f, 0.2f, 1.0f), - v4f32(0.1f, 0.8f, 0.4f, 1.0f), - v4f32(0.1f, 0.6f, 0.8f, 1.0f), - v4f32(0.5f, 0.3f, 0.8f, 1.0f), - v4f32(0.8f, 0.3f, 0.5f, 1.0f), - }; - UI_CornerRadius(ui_em(0.3f, 1.f).value) - for(U64 preset_idx = 0; preset_idx < ArrayCount(presets); preset_idx += 1) - { - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = presets[preset_idx])); - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_Clickable| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - "###color_preset_%i", (int)preset_idx); - UI_Signal sig = ui_signal_from_box(box); - if(ui_clicked(sig)) - { - Vec3F32 hsv = hsv_from_rgb(v3f32(presets[preset_idx].x, presets[preset_idx].y, presets[preset_idx].z)); - Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, 1); - entity->color_hsva = hsva; - } - ui_spacer(ui_em(0.3f, 1.f)); - } - } - - ui_spacer(ui_em(0.75f, 1.f)); - - UI_PrefWidth(ui_em(9.f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) - { - ui_sat_val_pickerf(entity->color_hsva.x, &entity->color_hsva.y, &entity->color_hsva.z, "###ent_satval_picker"); - } - - ui_spacer(ui_em(0.75f, 1.f)); - - UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(9.f, 1.f)) - ui_hue_pickerf(&entity->color_hsva.x, entity->color_hsva.y, entity->color_hsva.z, "###ent_hue_picker"); - } - } - - UI_Row UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_em(16.f, 1.f)) UI_CornerRadius(8.f) UI_TextAlignment(UI_TextAlign_Center) - RD_Palette(RD_PaletteCode_Floating) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Trash, 0, "Remove Color###color_toggle"))) - { - entity->flags &= ~RD_EntityFlag_HasColor; - } - } - - ui_spacer(ui_em(1.5f, 1.f)); - } -#endif - }break; - - ////////////////////// - //- rjf: frontend entities - // - case RD_RegSlot_Entity: - { - RD_Entity *entity = rd_entity_from_handle(regs->entity); - RD_EntityKindFlags kind_flags = rd_entity_kind_flags_table[entity->kind]; - - //- rjf: title - UI_Row - UI_PrefWidth(ui_text_dim(5, 1)) - UI_TextAlignment(UI_TextAlign_Center) - UI_TextPadding(ui_top_font_size()*1.5f) - { - DR_FancyStringList fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, ui_top_palette()->text_weak, ui_top_font_size()); - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &fstrs); - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - ui_spacer(ui_em(0.5f, 1.f)); - UI_FontSize(ui_top_font_size() - 1.f) - UI_CornerRadius(ui_top_font_size()*0.5f) - RD_Palette(RD_PaletteCode_NeutralPopButton) - UI_TextPadding(ui_top_font_size()*0.5f) - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_label(string_from_arch(ctrl_entity->arch)); - ui_spacer(ui_em(0.5f, 1.f)); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak|UI_BoxFlag_DrawBorder) ui_labelf("TID: %i", (U32)ctrl_entity->id); - } - } - } - - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); - - //- rjf: name editor - if(kind_flags & RD_EntityKindFlag_CanRename) RD_Font(RD_FontSlot_Code) UI_TextPadding(ui_top_font_size()*1.5f) - { - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border|RD_LineEditFlag_CodeContents, 0, 0, &ws->ctx_menu_input_cursor, &ws->ctx_menu_input_mark, ws->ctx_menu_input_buffer, ws->ctx_menu_input_buffer_size, &ws->ctx_menu_input_string_size, 0, entity->string, "Name###entity_string_edit_%p", ctrl_entity); - if(ui_committed(sig)) - { - rd_cmd(RD_CmdKind_NameEntity, .entity = regs->entity, .string = str8(ws->ctx_menu_input_buffer, ws->ctx_menu_input_string_size)); - } - } - - //- rjf: condition editor - if(kind_flags & RD_EntityKindFlag_CanCondition) RD_Font(RD_FontSlot_Code) UI_TextPadding(ui_top_font_size()*1.5f) - { - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border|RD_LineEditFlag_CodeContents, 0, 0, &ws->ctx_menu_input_cursor, &ws->ctx_menu_input_mark, ws->ctx_menu_input_buffer, ws->ctx_menu_input_buffer_size, &ws->ctx_menu_input_string_size, 0, rd_entity_child_from_kind(entity, RD_EntityKind_Condition)->string, "Condition###entity_condition_edit_%p", entity); - if(ui_committed(sig)) - { - rd_cmd(RD_CmdKind_ConditionEntity, .entity = regs->entity, .string = str8(ws->ctx_menu_input_buffer, ws->ctx_menu_input_string_size)); - } - } - - //- rjf: name editor - if(entity->cfg_src == RD_CfgSrc_CommandLine) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Save, 0, "Save To Project"))) - { - rd_entity_equip_cfg_src(entity, RD_CfgSrc_Project); - } - } - }break; - - } - } - - scratch_end(scratch); - } - - //////////////////////////// - //- rjf: drop-completion context menu + //- rjf: @window_ui_part drop-completion context menu // if(ws->drop_completion_paths.node_count != 0) { - RD_Palette(RD_PaletteCode_Floating) UI_CtxMenu(rd_state->drop_completion_key) - RD_Palette(RD_PaletteCode_ImplicitButton) - UI_PrefWidth(ui_em(40.f, 1.f)) + UI_CtxMenu(rd_state->drop_completion_key) UI_PrefWidth(ui_em(40.f, 1.f)) UI_TagF("implicit") { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + UI_TagF("weak") for(String8Node *n = ws->drop_completion_paths.first; n != 0; n = n->next) { UI_Row UI_Padding(ui_em(1.f, 1.f)) @@ -4656,7 +6670,7 @@ rd_window_frame(RD_Window *ws) UI_PrefWidth(ui_text_dim(10, 1)) ui_label(n->string); } } - RD_Palette(RD_PaletteCode_Floating) ui_divider(ui_em(1.f, 1.f)); + ui_divider(ui_em(1.f, 1.f)); if(ui_clicked(rd_icon_buttonf(RD_IconKind_Target, 0, "Add File%s As Target%s", (ws->drop_completion_paths.node_count > 1) ? "s" : "", (ws->drop_completion_paths.node_count > 1) ? "s" : ""))) @@ -4677,7 +6691,7 @@ rd_window_frame(RD_Window *ws) { rd_cmd(RD_CmdKind_AddTarget, .file_path = n->string); } - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count != 0) { rd_cmd(RD_CmdKind_KillAll); @@ -4696,7 +6710,7 @@ rd_window_frame(RD_Window *ws) { rd_cmd(RD_CmdKind_AddTarget, .file_path = n->string); } - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count != 0) { rd_cmd(RD_CmdKind_KillAll); @@ -4718,20 +6732,19 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: popup + //- rjf: @window_ui_part popup // { if(rd_state->popup_t > 0.005f) UI_TextAlignment(UI_TextAlign_Center) UI_Focus(rd_state->popup_active ? UI_FocusKind_Root : UI_FocusKind_Off) { Vec2F32 window_dim = dim_2f32(window_rect); UI_Box *bg_box = &ui_nil_box; - UI_Palette *palette = ui_build_palette(rd_palette_from_code(RD_PaletteCode_Floating)); - palette->background.w *= rd_state->popup_t; UI_Rect(window_rect) UI_ChildLayoutAxis(Axis2_X) UI_Focus(UI_FocusKind_On) UI_BlurSize(10*rd_state->popup_t) - UI_Palette(palette) + UI_Transparency(1-rd_state->popup_t) + UI_TagF("floating") { bg_box = ui_build_box_from_stringf(UI_BoxFlag_FixedSize| UI_BoxFlag_Floating| @@ -4748,11 +6761,11 @@ rd_window_frame(RD_Window *ws) UI_WidthFill UI_PrefHeight(ui_children_sum(1.f)) UI_Column UI_Padding(ui_pct(1, 0)) { UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Main)) UI_FontSize(ui_top_font_size()*2.f) UI_PrefHeight(ui_em(3.f, 1.f)) ui_label(rd_state->popup_title); - UI_PrefHeight(ui_em(3.f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label(rd_state->popup_desc); + UI_PrefHeight(ui_em(3.f, 1.f)) UI_TagF("weak") ui_label(rd_state->popup_desc); ui_spacer(ui_em(1.5f, 1.f)); UI_Row UI_Padding(ui_pct(1.f, 0.f)) UI_PrefWidth(ui_em(16.f, 1.f)) UI_PrefHeight(ui_em(3.5f, 1.f)) UI_CornerRadius(ui_top_font_size()*0.5f) { - RD_Palette(RD_PaletteCode_NeutralPopButton) + UI_TagF("pop") if(ui_clicked(ui_buttonf("OK")) || (ui_key_match(bg_box->default_nav_focus_hot_key, ui_key_zero()) && ui_slot_press(UI_EventActionSlot_Accept))) { rd_cmd(RD_CmdKind_PopupAccept); @@ -4771,564 +6784,711 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: build auto-complete lister + //- rjf: @window_ui_part build autocompletion callee info helper // - ProfScope("build autocomplete lister") - if(!ui_key_match(ws->autocomp_root_key, ui_key_zero()) && ws->autocomp_last_frame_idx+1 >= rd_state->frame_index) + F32 autocomp_callee_helper_height_px = 0; + if(rd_setting_b32_from_name(str8_lit("view_call_argument_helper")) && + ws->autocomp_regs != 0 && ws->autocomp_last_frame_index+1 >= rd_state->frame_index && + ws->autocomp_cursor_info.callee_expr.size != 0) { - String8 input = str8(ws->autocomp_lister_input_buffer, ws->autocomp_lister_input_size); - String8 query_word = rd_autocomp_query_word_from_input_string_off(input, ws->autocomp_cursor_off); - String8 query_path = rd_autocomp_query_path_from_input_string_off(input, ws->autocomp_cursor_off); - UI_Box *autocomp_root_box = ui_box_from_key(ws->autocomp_root_key); - if(!ui_box_is_nil(autocomp_root_box)) + E_Eval eval = e_eval_from_string(ws->autocomp_cursor_info.callee_expr); + E_Type *type = e_type_from_key(eval.irtree.type_key); + if(type->kind == E_TypeKind_LensSpec) UI_TagF("floating") { - Temp scratch = scratch_begin(0, 0); - DI_Scope *di_scope = di_scope_open(); - DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena); - DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); + F32 open_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "autocomp_callee_helper_t"), 1.f, .rate = rd_state->menu_animation_rate); - //- rjf: grab rdis - U64 rdis_count = dbgi_keys.count; - RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); + //- rjf: determine rects/sizes + F32 row_height_px = ui_top_font_size()*2.f; + F32 padding_px = ui_top_font_size()*1.f; + Vec2F32 callee_helper_pos = {0}; { - for(U64 idx = 0; idx < rdis_count; idx += 1) + UI_Box *anchor_box = ui_box_from_key(ws->autocomp_regs->ui_key); + callee_helper_pos.x = anchor_box->rect.x0; + callee_helper_pos.y = anchor_box->rect.y1; + } + F32 height_px_target = row_height_px*1.f + padding_px*2.f; + autocomp_callee_helper_height_px = height_px_target * open_t; + + //- rjf: build top-level callee helper box + UI_Box *callee_helper = &ui_nil_box; + UI_FixedPos(callee_helper_pos) + UI_Squish(0.1f-0.1f*open_t) + UI_Transparency(1.f-open_t) + UI_CornerRadius(ui_top_font_size()*0.25f) + UI_PrefWidth(ui_children_sum(1)) + UI_PrefHeight(ui_px(height_px_target, 1.f)) + { + callee_helper = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_SquishAnchored|UI_BoxFlag_Clickable, + "top_level_window_callee_helper"); + } + + //- rjf: fill helper + UI_Parent(callee_helper) + UI_Padding(ui_px(padding_px, 1.f)) + UI_PrefWidth(ui_children_sum(1)) + UI_HeightFill + UI_Column + UI_PrefHeight(ui_px(row_height_px, 1.f)) + UI_Padding(ui_px(padding_px, 1.f)) + { + // rjf: main name / args text + UI_Row UI_TextPadding(0) UI_PrefWidth(ui_text_dim(0, 1)) RD_Font(RD_FontSlot_Code) { - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_keys.v[idx], 0); - RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); - rdis[idx] = rdi; + Vec4F32 code_default = ui_color_from_name(str8_lit("code_default")); + String8 opener = push_str8f(scratch.arena, "%S(", type->name); + rd_code_label(1, 0, code_default, opener); + MD_NodePtrList schemas = rd_schemas_from_name(type->name); + B32 first = 1; + UI_TagF(".") for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + for MD_EachNode(child, n->v->first) + { + if(md_node_has_tag(child, str8_lit("no_callee_helper"), 0)) + { + continue; + } + if(!first) + { + rd_code_label(1, 0, code_default, str8_lit(", ")); + } + first = 0; + UI_Key arg_key = ui_key_from_stringf(ui_active_seed_key(), "###arg_%p", child); + DR_FStrList arg_fstrs = rd_fstrs_from_code_string(scratch.arena, 1.f, 0, code_default, child->string); + if(child == ws->autocomp_cursor_info.arg_schema) + { + ui_set_next_flags(UI_BoxFlag_DrawSideBottom); + ui_set_next_tag(str8_lit("good_pop")); + } + UI_Box *arg_box = ui_build_box_from_key(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects, arg_key); + ui_box_equip_display_fstrs(arg_box, &arg_fstrs); + UI_Signal arg_sig = ui_signal_from_box(arg_box); + if(ui_hovering(arg_sig)) + { + String8 display_name = md_tag_from_string(child, str8_lit("display_name"), 0)->first->string; + String8 desc = md_tag_from_string(child, str8_lit("description"), 0)->first->string; + if(desc.size != 0) + UI_Tooltip RD_Font(RD_FontSlot_Main) + { + ui_state->tooltip_anchor_key = arg_box->key; + UI_Row + { + RD_Font(RD_FontSlot_Code) ui_label(child->string); + if(display_name.size != 0) + { + ui_spacer(ui_em(0.5f, 1.f)); + UI_TagF("weak") ui_label(display_name); + } + } + UI_TagF("weak") ui_label(desc); + } + } + } + } + rd_code_label(1, 0, code_default, str8_lit(")")); } } - //- rjf: unpack lister params - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_base_regs()->thread); - U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, rd_base_regs()->unwind_count); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, thread_rip_vaddr); - U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - - //- rjf: gather lister items - RD_AutoCompListerItemChunkList item_list = {0}; - { - //- rjf: gather locals - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Locals) - { - E_String2NumMap *locals_map = d_query_cached_locals_map_from_dbgi_key_voff(&dbgi_key, thread_rip_voff); - E_String2NumMap *member_map = d_query_cached_member_map_from_dbgi_key_voff(&dbgi_key, thread_rip_voff); - for(E_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) - { - RD_AutoCompListerItem item = {0}; - { - item.string = n->string; - item.kind_string = str8_lit("Local"); - item.matches = fuzzy_match_find(scratch.arena, query_word, n->string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - for(E_String2NumMapNode *n = member_map->first; n != 0; n = n->order_next) - { - RD_AutoCompListerItem item = {0}; - { - item.string = n->string; - item.kind_string = str8_lit("Local (Member)"); - item.matches = fuzzy_match_find(scratch.arena, query_word, n->string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - - //- rjf: gather registers - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Registers) - { - Arch arch = thread->arch; - U64 reg_names_count = regs_reg_code_count_from_arch(arch); - U64 alias_names_count = regs_alias_code_count_from_arch(arch); - String8 *reg_names = regs_reg_code_string_table_from_arch(arch); - String8 *alias_names = regs_alias_code_string_table_from_arch(arch); - for(U64 idx = 0; idx < reg_names_count; idx += 1) - { - if(reg_names[idx].size != 0) - { - RD_AutoCompListerItem item = {0}; - { - item.string = reg_names[idx]; - item.kind_string = str8_lit("Register"); - item.matches = fuzzy_match_find(scratch.arena, query_word, reg_names[idx]); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - for(U64 idx = 0; idx < alias_names_count; idx += 1) - { - if(alias_names[idx].size != 0) - { - RD_AutoCompListerItem item = {0}; - { - item.string = alias_names[idx]; - item.kind_string = str8_lit("Reg. Alias"); - item.matches = fuzzy_match_find(scratch.arena, query_word, alias_names[idx]); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - } - - //- rjf: gather view rules - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_ViewRules) - { - for(U64 slot_idx = 0; slot_idx < d_state->view_rule_spec_table_size; slot_idx += 1) - { - for(D_ViewRuleSpec *spec = d_state->view_rule_spec_table[slot_idx]; spec != 0 && spec != &d_nil_core_view_rule_spec; spec = spec->hash_next) - { - RD_AutoCompListerItem item = {0}; - { - item.string = spec->info.string; - item.kind_string = str8_lit("View Rule"); - item.matches = fuzzy_match_find(scratch.arena, query_word, spec->info.string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - } - - //- rjf: gather members - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Members) - { - // TODO(rjf) - } - - //- rjf: gather globals - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Globals && query_word.size != 0) - { - U128 search_key = {d_hash_from_string(str8_lit("autocomp_globals_search_key")), d_hash_from_string(str8_lit("autocomp_globals_search_key"))}; - DI_SearchParams search_params = - { - RDI_SectionKind_GlobalVariables, - dbgi_keys, - }; - B32 is_stale = 0; - DI_SearchItemArray items = di_search_items_from_key_params_query(di_scope, search_key, &search_params, query_word, 0, &is_stale); - for(U64 idx = 0; idx < 20 && idx < items.count; idx += 1) - { - // rjf: skip bad elements - if(items.v[idx].dbgi_idx >= rdis_count) - { - continue; - } - - // rjf: unpack info - RDI_Parsed *rdi = rdis[items.v[idx].dbgi_idx]; - String8 name = di_search_item_string_from_rdi_target_element_idx(rdi, search_params.target, items.v[idx].idx); - - // rjf: push item - RD_AutoCompListerItem item = {0}; - { - item.string = name; - item.kind_string = str8_lit("Global"); - item.matches = items.v[idx].match_ranges; - item.group = 1; - } - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - - //- rjf: gather thread locals - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_ThreadLocals && query_word.size != 0) - { - U128 search_key = {d_hash_from_string(str8_lit("autocomp_tvars_dis_key")), d_hash_from_string(str8_lit("autocomp_tvars_dis_key"))}; - DI_SearchParams search_params = - { - RDI_SectionKind_ThreadVariables, - dbgi_keys, - }; - B32 is_stale = 0; - DI_SearchItemArray items = di_search_items_from_key_params_query(di_scope, search_key, &search_params, query_word, 0, &is_stale); - for(U64 idx = 0; idx < 20 && idx < items.count; idx += 1) - { - // rjf: skip bad elements - if(items.v[idx].dbgi_idx >= rdis_count) - { - continue; - } - - // rjf: unpack info - RDI_Parsed *rdi = rdis[items.v[idx].dbgi_idx]; - String8 name = di_search_item_string_from_rdi_target_element_idx(rdi, search_params.target, items.v[idx].idx); - - // rjf: push item - RD_AutoCompListerItem item = {0}; - { - item.string = name; - item.kind_string = str8_lit("Thread Local"); - item.matches = items.v[idx].match_ranges; - item.group = 1; - } - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - - //- rjf: gather procedures - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Procedures && query_word.size != 0) - { - U128 search_key = {d_hash_from_string(str8_lit("autocomp_procedures_search_key")), d_hash_from_string(str8_lit("autocomp_procedures_search_key"))}; - DI_SearchParams search_params = - { - RDI_SectionKind_Procedures, - dbgi_keys, - }; - B32 is_stale = 0; - DI_SearchItemArray items = di_search_items_from_key_params_query(di_scope, search_key, &search_params, query_word, 0, &is_stale); - for(U64 idx = 0; idx < 20 && idx < items.count; idx += 1) - { - // rjf: skip bad elements - if(items.v[idx].dbgi_idx >= rdis_count) - { - continue; - } - - // rjf: unpack info - RDI_Parsed *rdi = rdis[items.v[idx].dbgi_idx]; - String8 name = di_search_item_string_from_rdi_target_element_idx(rdi, search_params.target, items.v[idx].idx); - - // rjf: push item - RD_AutoCompListerItem item = {0}; - { - item.string = name; - item.kind_string = str8_lit("Procedure"); - item.matches = items.v[idx].match_ranges; - item.group = 1; - } - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - - //- rjf: gather types - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Types && query_word.size != 0) - { - U128 search_key = {d_hash_from_string(str8_lit("autocomp_types_search_key")), d_hash_from_string(str8_lit("autocomp_types_search_key"))}; - DI_SearchParams search_params = - { - RDI_SectionKind_UDTs, - dbgi_keys, - }; - B32 is_stale = 0; - DI_SearchItemArray items = di_search_items_from_key_params_query(di_scope, search_key, &search_params, query_word, 0, &is_stale); - for(U64 idx = 0; idx < 20 && idx < items.count; idx += 1) - { - // rjf: skip bad elements - if(items.v[idx].dbgi_idx >= rdis_count) - { - continue; - } - - // rjf: unpack info - RDI_Parsed *rdi = rdis[items.v[idx].dbgi_idx]; - String8 name = di_search_item_string_from_rdi_target_element_idx(rdi, search_params.target, items.v[idx].idx); - - // rjf: push item - RD_AutoCompListerItem item = {0}; - { - item.string = name; - item.kind_string = str8_lit("Type"); - item.matches = items.v[idx].match_ranges; - item.group = 1; - } - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - - //- rjf: gather languages - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Languages) - { - for EachNonZeroEnumVal(TXT_LangKind, lang) - { - RD_AutoCompListerItem item = {0}; - { - item.string = txt_extension_from_lang_kind(lang); - item.kind_string = str8_lit("Language"); - item.matches = fuzzy_match_find(scratch.arena, query_word, item.string); - } - if(item.string.size != 0 && (query_word.size == 0 || item.matches.count != 0)) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - - //- rjf: gather architectures - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Architectures) - { - for EachNonZeroEnumVal(Arch, arch) - { - RD_AutoCompListerItem item = {0}; - { - item.string = string_from_arch(arch); - item.kind_string = str8_lit("Arch"); - item.matches = fuzzy_match_find(scratch.arena, query_word, item.string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - - //- rjf: gather tex2dformats - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Tex2DFormats) - { - for EachEnumVal(R_Tex2DFormat, fmt) - { - RD_AutoCompListerItem item = {0}; - { - item.string = lower_from_str8(scratch.arena, r_tex2d_format_display_string_table[fmt]); - item.kind_string = str8_lit("Format"); - item.matches = fuzzy_match_find(scratch.arena, query_word, item.string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - - //- rjf: gather view rule params - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_ViewRuleParams) - { - for(String8Node *n = ws->autocomp_lister_params.strings.first; n != 0; n = n->next) - { - String8 string = n->string; - RD_AutoCompListerItem item = {0}; - { - item.string = string; - item.kind_string = str8_lit("Parameter"); - item.matches = fuzzy_match_find(scratch.arena, query_word, item.string); - } - if(query_word.size == 0 || item.matches.count != 0) - { - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - } - - //- rjf: gather files - if(ws->autocomp_lister_params.flags & RD_AutoCompListerFlag_Files) - { - // rjf: find containing directory in query_path - String8 dir_str_in_input = {0}; - for(U64 i = 0; i < query_path.size; i += 1) - { - String8 substr1 = str8_substr(query_path, r1u64(i, i+1)); - String8 substr2 = str8_substr(query_path, r1u64(i, i+2)); - String8 substr3 = str8_substr(query_path, r1u64(i, i+3)); - if(str8_match(substr1, str8_lit("/"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(query_path, r1u64(i, query_path.size)); - } - else if(i != 0 && str8_match(substr2, str8_lit(":/"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(query_path, r1u64(i-1, query_path.size)); - } - else if(str8_match(substr2, str8_lit("./"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(query_path, r1u64(i, query_path.size)); - } - else if(str8_match(substr3, str8_lit("../"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(query_path, r1u64(i, query_path.size)); - } - if(dir_str_in_input.size != 0) - { - break; - } - } - - // rjf: use query_path string to form various parts of search space - String8 prefix = {0}; - String8 path = {0}; - String8 search = {0}; - if(dir_str_in_input.size != 0) - { - String8 dir = dir_str_in_input; - U64 one_past_last_slash = dir.size; - for(U64 i = 0; i < dir_str_in_input.size; i += 1) - { - if(dir_str_in_input.str[i] == '/' || dir_str_in_input.str[i] == '\\') - { - one_past_last_slash = i+1; - } - } - dir.size = one_past_last_slash; - path = dir; - search = str8_substr(dir_str_in_input, r1u64(one_past_last_slash, dir_str_in_input.size)); - prefix = str8_substr(query_path, r1u64(0, path.str - query_path.str)); - } - - // rjf: get current files, filtered - B32 allow_dirs = 1; - OS_FileIter *it = os_file_iter_begin(scratch.arena, path, 0); - for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, it, &info);) - { - FuzzyMatchRangeList match_ranges = fuzzy_match_find(scratch.arena, search, info.name); - B32 fits_search = (search.size == 0 || match_ranges.count == match_ranges.needle_part_count); - B32 fits_dir_only = (allow_dirs || !(info.props.flags & FilePropertyFlag_IsFolder)); - if(fits_search && fits_dir_only) - { - RD_AutoCompListerItem item = {0}; - { - item.string = info.props.flags & FilePropertyFlag_IsFolder ? push_str8f(scratch.arena, "%S/", info.name) : info.name; - item.kind_string = info.props.flags & FilePropertyFlag_IsFolder ? str8_lit("Folder") : str8_lit("File"); - item.matches = match_ranges; - item.is_non_code = 1; - } - rd_autocomp_lister_item_chunk_list_push(scratch.arena, &item_list, 256, &item); - } - } - os_file_iter_end(it); - } - } - - //- rjf: lister item list -> sorted array - RD_AutoCompListerItemArray item_array = rd_autocomp_lister_item_array_from_chunk_list(scratch.arena, &item_list); - rd_autocomp_lister_item_array_sort__in_place(&item_array); - - //- rjf: animate - { - // rjf: animate target # of rows - { - F32 rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? (1 - pow_f32(2, (-60.f * rd_state->frame_dt))) : 1.f; - F32 target = Min((F32)item_array.count, 16.f); - if(abs_f32(target - ws->autocomp_num_visible_rows_t) > 0.01f) - { - rd_request_frame(); - } - ws->autocomp_num_visible_rows_t += (target - ws->autocomp_num_visible_rows_t) * rate; - if(abs_f32(target - ws->autocomp_num_visible_rows_t) <= 0.02f) - { - ws->autocomp_num_visible_rows_t = target; - } - } - - // rjf: animate open - { - F32 rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f; - F32 diff = 1.f-ws->autocomp_open_t; - ws->autocomp_open_t += diff*rate; - if(abs_f32(diff) < 0.05f) - { - ws->autocomp_open_t = 1.f; - } - else - { - rd_request_frame(); - } - } - } - - //- rjf: build - if(item_array.count != 0) - { - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - ui_set_next_fixed_x(autocomp_root_box->rect.x0); - ui_set_next_fixed_y(autocomp_root_box->rect.y1); - ui_set_next_pref_width(ui_em(30.f, 1.f)); - ui_set_next_pref_height(ui_px(row_height_px*ws->autocomp_num_visible_rows_t + ui_top_font_size()*2.f, 1.f)); - ui_set_next_child_layout_axis(Axis2_Y); - ui_set_next_corner_radius_01(ui_top_font_size()*0.25f); - ui_set_next_corner_radius_11(ui_top_font_size()*0.25f); - ui_set_next_corner_radius_10(ui_top_font_size()*0.25f); - UI_Focus(UI_FocusKind_On) - UI_Squish(0.25f-0.25f*ws->autocomp_open_t) - UI_Transparency(1.f-ws->autocomp_open_t) - RD_Palette(RD_PaletteCode_Floating) - { - autocomp_box = ui_build_box_from_stringf(UI_BoxFlag_DefaultFocusNavY| - UI_BoxFlag_Clickable| - UI_BoxFlag_Clip| - UI_BoxFlag_RoundChildrenByParent| - UI_BoxFlag_DisableFocusOverlay| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackgroundBlur| - UI_BoxFlag_DrawDropShadow| - UI_BoxFlag_DrawBackground, - "autocomp_box"); - if(ws->autocomp_input_dirty) - { - ws->autocomp_input_dirty = 0; - autocomp_box->default_nav_focus_hot_key = autocomp_box->default_nav_focus_active_key = autocomp_box->default_nav_focus_next_hot_key = autocomp_box->default_nav_focus_next_active_key = ui_key_zero(); - } - } - UI_Parent(autocomp_box) - UI_WidthFill - UI_PrefHeight(ui_px(row_height_px, 1.f)) - RD_Font(RD_FontSlot_Code) - UI_HoverCursor(OS_Cursor_HandPoint) - UI_Focus(UI_FocusKind_Null) - RD_Palette(RD_PaletteCode_ImplicitButton) - UI_Padding(ui_em(1.f, 1.f)) - { - for(U64 idx = 0; idx < item_array.count; idx += 1) - { - RD_AutoCompListerItem *item = &item_array.v[idx]; - UI_Box *item_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawActiveEffects|UI_BoxFlag_MouseClickable, "autocomp_%I64x", idx); - UI_Parent(item_box) UI_Padding(ui_em(1.f, 1.f)) - { - UI_WidthFill RD_Font(item->is_non_code ? RD_FontSlot_Main : RD_FontSlot_Code) - { - UI_Box *box = item->is_non_code ? ui_label(item->string).box : rd_code_label(1.f, 0, ui_top_palette()->text, item->string); - ui_box_equip_fuzzy_match_ranges(box, &item->matches); - } - RD_Font(RD_FontSlot_Main) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_label(item->kind_string); - } - UI_Signal item_sig = ui_signal_from_box(item_box); - if(ui_clicked(item_sig)) - { - UI_Event move_back_evt = zero_struct; - move_back_evt.kind = UI_EventKind_Navigate; - move_back_evt.flags = UI_EventFlag_KeepMark; - move_back_evt.delta_2s32.x = -(S32)query_word.size; - ui_event_list_push(ui_build_arena(), &ws->ui_events, &move_back_evt); - UI_Event paste_evt = zero_struct; - paste_evt.kind = UI_EventKind_Text; - paste_evt.string = item->string; - ui_event_list_push(ui_build_arena(), &ws->ui_events, &paste_evt); - autocomp_box->default_nav_focus_hot_key = autocomp_box->default_nav_focus_active_key = autocomp_box->default_nav_focus_next_hot_key = autocomp_box->default_nav_focus_next_active_key = ui_key_zero(); - } - else if(item_box->flags & UI_BoxFlag_FocusHot && !(item_box->flags & UI_BoxFlag_FocusHotDisabled)) - { - UI_Event evt = zero_struct; - evt.kind = UI_EventKind_AutocompleteHint; - evt.string = item->string; - ui_event_list_push(ui_build_arena(), &ws->ui_events, &evt); - } - } - } - } - - di_scope_close(di_scope); - scratch_end(scratch); + //- rjf: fall-through interactions with helper + UI_Signal sig = ui_signal_from_box(callee_helper); + (void)sig; } } //////////////////////////// - //- rjf: top bar + //- rjf: @window_ui_part gather all tasks to build floating views + // + typedef struct FloatingViewTask FloatingViewTask; + struct FloatingViewTask + { + FloatingViewTask *next; + RD_Cfg *view; + RD_Regs *regs; + Rng2F32 rect; + B32 is_focused; + B32 is_anchored; + B32 force_inside_window_x; + B32 force_inside_window_y; + B32 only_secondary_navigation; + B32 reset_open; + UI_Signal signal; // NOTE(rjf): output, from build + B32 pressed; + B32 pressed_outside; + }; + FloatingViewTask *autocomp_floating_view_task = 0; + FloatingViewTask *hover_eval_floating_view_task = 0; + FloatingViewTask *query_floating_view_task = 0; + FloatingViewTask *first_floating_view_task = 0; + FloatingViewTask *last_floating_view_task = 0; + RD_Font(RD_FontSlot_Code) + { + //- rjf: add autocompletion view task + if(ws->autocomp_regs != 0 && ws->autocomp_last_frame_index+1 >= rd_state->frame_index) + { + // rjf: build view + RD_Cfg *root = rd_immediate_cfg_from_keyf("autocomp_view_%I64x", window->id); + RD_Cfg *view = rd_cfg_child_from_string_or_alloc(root, str8_lit("watch")); + rd_cfg_child_from_string_or_alloc(view, str8_lit("autocomplete")); + RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); + RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + rd_cfg_new_replace(input, ws->autocomp_cursor_info.filter); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + rd_cfg_new_replace(expr, ws->autocomp_cursor_info.list_expr); + + // rjf: determine container size + EV_BlockTree predicted_block_tree = {0}; + RD_RegsScope(.view = view->id, .tab = 0) + { + String8 expr = rd_expr_from_cfg(view); + E_Eval list_eval = e_eval_from_string(expr); + ev_key_set_expansion(rd_view_eval_view(), ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); + predicted_block_tree = ev_block_tree_from_eval(scratch.arena, rd_view_eval_view(), rd_view_query_input(), list_eval); + } + F32 row_height_px = ui_top_px_height(); + U64 max_row_count = (U64)floor_f32(ui_top_font_size()*30.f / row_height_px); + U64 needed_row_count = Min(max_row_count, predicted_block_tree.total_row_count - 1); + F32 width_px = floor_f32(30.f*ui_top_font_size()); + F32 height_px = needed_row_count*row_height_px; + + // rjf: determine list top-level rect + Rng2F32 rect = r2f32p(0, 0, 0, 0); + if(!ui_key_match(ui_key_zero(), ws->autocomp_regs->ui_key)) + { + UI_Box *anchor_box = ui_box_from_key(ws->autocomp_regs->ui_key); + rect.x0 = anchor_box->rect.x0; + rect.y0 = anchor_box->rect.y1 + autocomp_callee_helper_height_px; + rect.x1 = rect.x0 + width_px; + rect.y1 = rect.y0 + height_px; + } + + // rjf: push task + if(predicted_block_tree.total_row_count > 1) + { + FloatingViewTask *t = push_array(scratch.arena, FloatingViewTask, 1); + SLLQueuePush(first_floating_view_task, last_floating_view_task, t); + autocomp_floating_view_task = t; + t->view = view; + t->rect = rect; + t->is_focused = 1; + t->is_anchored = 1; + t->only_secondary_navigation = 1; + } + } + + //- rjf: try to add hover eval + { + B32 build_hover_eval = (hover_eval_is_open && !rd_drag_is_active()); + + // rjf: disable hover eval if hovered view is actively scrolling + if(hover_eval_is_open) + { + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + { + if(panel->first != &rd_nil_panel_node) { continue; } + RD_Cfg *tab = panel->selected_tab; + if(tab != &rd_nil_cfg) + { + RD_ViewState *vs = rd_view_state_from_cfg(tab); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + if(contains_2f32(panel_rect, ui_mouse()) && + (abs_f32(vs->scroll_pos.x.off) > 0.01f || + abs_f32(vs->scroll_pos.y.off) > 0.01f)) + { + build_hover_eval = 0; + ws->hover_eval_firstt_us = rd_state->time_in_us; + } + } + } + } + + // rjf: choose hover evaluation expression + String8 hover_eval_expr = ws->hover_eval_string; + + // rjf: evaluate hover evaluation expression, & determine if it evaluates + // such that we want to build a hover eval. + E_Eval hover_eval = e_eval_from_string(hover_eval_expr); + { + if(hover_eval.msgs.max_kind > E_MsgKind_Null) + { + build_hover_eval = 0; + } + else if(hover_eval.space.kind == RD_EvalSpaceKind_MetaCfg && + rd_cfg_from_eval_space(hover_eval.space) == &rd_nil_cfg) + { + build_hover_eval = 0; + } + else if((hover_eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + hover_eval.space.kind == RD_EvalSpaceKind_CtrlEntity) && + rd_ctrl_entity_from_eval_space(hover_eval.space) == &ctrl_entity_nil) + { + build_hover_eval = 0; + } + } + + // rjf: request frames if we're waiting to open + if(ws->hover_eval_string.size != 0 && + !hover_eval_is_open && + ws->hover_eval_lastt_us < ws->hover_eval_firstt_us+hover_eval_open_delay_us && + rd_state->time_in_us - ws->hover_eval_lastt_us < hover_eval_open_delay_us*2) + { + rd_request_frame(); + } + + // rjf: build hover eval task + if(build_hover_eval) + { + // rjf: determine if we have a top-level visualizer + EV_ExpandRule *expand_rule = ev_expand_rule_from_type_key(hover_eval.irtree.type_key); + RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(expand_rule->string); + + // rjf: build view + RD_Cfg *root = rd_immediate_cfg_from_keyf("hover_eval_view_%I64x", ws->cfg_id); + RD_Cfg *view = rd_view_from_eval(root, hover_eval); + rd_cfg_child_from_string_or_alloc(view, str8_lit("explicit_root")); + + // rjf: determine size of hover evaluation container + EV_BlockTree predicted_block_tree = {0}; + RD_RegsScope(.view = view->id, .tab = 0) + { + ev_key_set_expansion(rd_view_eval_view(), ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); + predicted_block_tree = ev_block_tree_from_eval(scratch.arena, rd_view_eval_view(), str8_zero(), hover_eval); + } + F32 row_height_px = ui_top_px_height(); + U64 max_row_count = (U64)floor_f32(ui_top_font_size()*10.f / row_height_px); + if(ws->hover_eval_focused) + { + max_row_count *= 3; + } + U64 needed_row_count = Min(max_row_count, predicted_block_tree.total_row_count); + F32 width_px = floor_f32(70.f*ui_top_font_size()); + F32 height_px = needed_row_count*row_height_px; + + // rjf: if arbitrary visualizer, pick catchall size + if(view_ui_rule != &rd_nil_view_ui_rule) + { + height_px = floor_f32(40.f*ui_top_font_size()); + } + + // rjf: determine hover eval top-level rect + Rng2F32 rect = r2f32p(ws->hover_eval_spawn_pos.x, + ws->hover_eval_spawn_pos.y, + ws->hover_eval_spawn_pos.x + width_px, + ws->hover_eval_spawn_pos.y + height_px); + + // rjf: push hover eval task + { + FloatingViewTask *t = push_array(scratch.arena, FloatingViewTask, 1); + SLLQueuePush(first_floating_view_task, last_floating_view_task, t); + hover_eval_floating_view_task = t; + t->view = view; + t->rect = rect; + t->is_focused = ws->hover_eval_focused; + t->is_anchored = 1; + t->force_inside_window_x = 1; + } + } + + // rjf: reset focus state if hover eval is not being built + if(!build_hover_eval || ws->hover_eval_string.size == 0 || !hover_eval_is_open) + { + ws->hover_eval_focused = 0; + } + } + + //- rjf: force-close query, if it's anchored, but box is gone + if(query_is_open) + { + UI_Box *box = ui_box_from_key(ws->query_regs->ui_key); + if(!ui_key_match(ui_key_zero(), ws->query_regs->ui_key) && ui_box_is_nil(box)) + { + query_is_open = 0; + rd_cmd(RD_CmdKind_CancelQuery); + } + } + + //- rjf: force-close query, if it has an expression, but that expression does not evaluate + if(query_is_open) + { + String8 expr = ws->query_regs->expr; + E_Eval eval = e_eval_from_string(expr); + if(eval.msgs.max_kind > E_MsgKind_Null) + { + query_is_open = 0; + rd_cmd(RD_CmdKind_CancelQuery); + } + else if(eval.space.kind == RD_EvalSpaceKind_MetaCfg && + rd_cfg_from_eval_space(eval.space) == &rd_nil_cfg) + { + query_is_open = 0; + rd_cmd(RD_CmdKind_CancelQuery); + } + else if((eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + eval.space.kind == RD_EvalSpaceKind_CtrlEntity) && + rd_ctrl_entity_from_eval_space(eval.space) == &ctrl_entity_nil) + { + query_is_open = 0; + rd_cmd(RD_CmdKind_CancelQuery); + } + } + + //- rjf: try to add opened query + if(query_is_open) + { + // rjf: unpack view for query + RD_Cfg *root = rd_immediate_cfg_from_keyf("window_query_%p", window); + RD_Cfg *view = rd_cfg_child_from_string_or_alloc(root, str8_lit("watch")); + RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); + B32 is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); + B32 root_is_explicit = (rd_cfg_child_from_string(view, str8_lit("explicit_root")) != &rd_nil_cfg); + RD_ViewState *vs = rd_view_state_from_cfg(view); + + // rjf: did this view ID change? -> reset open animation + B32 reset_open = 0; + if(view->id != ws->query_last_view_id) + { + ws->query_last_view_id = view->id; + reset_open = 1; + } + + // rjf: unpack query info + String8 cmd_name = ws->query_regs->cmd_name; + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + String8 query_expr = ws->query_regs->expr; + if(query_expr.size == 0 && cmd_name.size != 0) + { + query_expr = cmd_kind_info->query.expr; + } + B32 query_is_anchored = (!ui_box_is_nil(ui_box_from_key(ws->query_regs->ui_key))); + B32 size_query_by_expr_eval = (query_is_anchored || query_expr.size == 0); + + // rjf: compute query expression + if(query_expr.size == 0) + { + query_expr = str8(vs->query_buffer, vs->query_string_size); + } + else + { + U64 input_insertion_pos = str8_find_needle(query_expr, 0, str8_lit("$input"), 0); + if(input_insertion_pos < query_expr.size) + { + String8 pre_insertion = str8_prefix(query_expr, input_insertion_pos); + String8 post_insertion = str8_skip(query_expr, input_insertion_pos + 6); + String8 input_text = str8(vs->query_buffer, vs->query_string_size); + String8 input_text__escaped = escaped_from_raw_str8(scratch.arena, input_text); + // TODO(rjf): @hack need to escape because this is putting the user's input + // into a containing "folder:"..."" in all cases. but this is kinda shady + // and should be replaced long-term with something more solid... + query_expr = push_str8f(scratch.arena, "%S%S%S", pre_insertion, input_text__escaped, post_insertion); + } + } + + // rjf: store expression + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + rd_cfg_new_replace(expr, query_expr); + + // rjf: evaluate query expression + E_Eval query_eval = e_eval_from_string(query_expr); + + // rjf: determine & store row-height setting + if(ws->query_regs->do_big_rows) + { + F32 row_height = 5.f; + F32 row_height_px = row_height * ui_top_font_size(); + RD_Cfg *row_height_root = rd_cfg_child_from_string_or_alloc(view, str8_lit("row_height")); + rd_cfg_new_replacef(row_height_root, "%f", row_height); + } + + // rjf: compute query view's top-level rectangle + Rng2F32 rect = {0}; + RD_RegsScope(.view = view->id, .tab = 0) + { + F32 row_height_px = ui_top_font_size() * rd_setting_f32_from_name(str8_lit("row_height")); + Vec2F32 content_rect_center = center_2f32(content_rect); + Vec2F32 content_rect_dim = dim_2f32(content_rect); + ev_key_set_expansion(rd_view_eval_view(), ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); + EV_BlockTree predicted_block_tree = ev_block_tree_from_eval(scratch.arena, rd_view_eval_view(), rd_view_query_input(), query_eval); + F32 query_width_px = floor_f32(content_rect_dim.x * 0.35f); + F32 max_query_height_px = content_rect_dim.y*0.8f; + F32 query_height_px = max_query_height_px; + if(size_query_by_expr_eval) + { + F32 search_row_open_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "search_row_open_%p", view), + (F32)!!vs->query_is_open, + .initial = (F32)!!vs->query_is_open, + .epsilon = 0.01f, + .rate = rd_state->menu_animation_rate); + query_height_px = row_height_px * (predicted_block_tree.total_row_count - !root_is_explicit) + ui_top_px_height()*search_row_open_t; + query_height_px = Min(query_height_px, max_query_height_px); + } + rect = r2f32p(content_rect_center.x - query_width_px/2, + content_rect_center.y - max_query_height_px/2.f, + content_rect_center.x + query_width_px/2, + content_rect_center.y - max_query_height_px/2.f + query_height_px); + if(!ui_key_match(ui_key_zero(), ws->query_regs->ui_key)) + { + UI_Box *anchor_box = ui_box_from_key(ws->query_regs->ui_key); + if(anchor_box != &ui_nil_box) + { + rect.x0 = anchor_box->rect.x0 + ws->query_regs->off_px.x; + rect.y0 = anchor_box->rect.y1 + ws->query_regs->off_px.y; + rect.x1 = rect.x0 + ui_top_font_size()*60.f; + rect.y1 = rect.y0 + query_height_px; + } + } + } + + // rjf: push query task + { + FloatingViewTask *t = push_array(scratch.arena, FloatingViewTask, 1); + SLLQueuePush(first_floating_view_task, last_floating_view_task, t); + query_floating_view_task = t; + t->view = view; + t->regs = ws->query_regs; + t->rect = rect; + t->is_focused = 1; + t->is_anchored = query_is_anchored; + t->reset_open = reset_open; + t->force_inside_window_x = 1; + t->force_inside_window_y = 1; + } + } + } + + //////////////////////////// + //- rjf: @window_ui_part build all floating views + // + ProfScope("build all floating views") + RD_Font(RD_FontSlot_Code) + UI_TagF("floating") + UI_Focus(ui_any_ctx_menu_is_open() || ws->menu_bar_focused ? UI_FocusKind_Off : UI_FocusKind_Null) + { + F32 fast_open_rate = rd_state->menu_animation_rate; + F32 slow_open_rate = rd_state->menu_animation_rate__slow; + for(FloatingViewTask *t = first_floating_view_task; t != 0; t = t->next) + { + // rjf: unpack + RD_Cfg *view = t->view; + Rng2F32 rect = t->rect; + B32 is_focused = t->is_focused; + B32 is_anchored = t->is_anchored; + B32 only_secondary_navigation = t->only_secondary_navigation; + F32 open_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "floating_view_open_%p", view), 1.f, + .rate = is_anchored ? fast_open_rate : slow_open_rate, + .reset = t->reset_open, + .initial = 0.f); + + // rjf: force rect inside window if needed + if(t->force_inside_window_x || t->force_inside_window_y) + { + B32 axis_mask[] = {t->force_inside_window_x, t->force_inside_window_y}; + Rng2F32 window_rect = os_client_rect_from_window(ws->os); + for EachEnumVal(Axis2, axis) + { + if(!axis_mask[axis]) { continue; } + F32 max_delta = rect.p1.v[axis] - window_rect.p1.v[axis]; + F32 min_delta = window_rect.p0.v[axis] - rect.p0.v[axis]; + F32 total_delta = Max(min_delta, 0) - Max(max_delta, 0); + rect.p0.v[axis] += total_delta; + rect.p1.v[axis] += total_delta; + } + } + + // rjf: push view regs + rd_push_regs(); + { + if(t->regs != 0) + { + rd_regs()->cfg = t->regs->cfg; + } + rd_regs()->view = view->id; + String8 view_expr = rd_expr_from_cfg(view); + String8 view_file_path = rd_file_path_from_eval_string(rd_frame_arena(), view_expr); + // NOTE(rjf): we want to only fill out this view's file path slot if it + // evaluates one - this way, a view can use the slot to know the selected + // file path (if there is one). this is useful when pushing commandas which + // apply to a cursor, for example. + if(view_file_path.size != 0) + { + rd_regs()->file_path = view_file_path; + } + } + + // rjf: build + UI_Focus(is_focused ? UI_FocusKind_On : UI_FocusKind_Off) + UI_PermissionFlags(only_secondary_navigation ? + UI_PermissionFlag_KeyboardSecondary|UI_PermissionFlag_Clicks|UI_PermissionFlag_ScrollX|UI_PermissionFlag_ScrollY : + UI_PermissionFlag_All) + { + // rjf: build top-level container box + UI_Box *container = &ui_nil_box; + UI_Rect(rect) UI_ChildLayoutAxis(Axis2_Y) + UI_Squish(0.1f-0.1f*open_t) + UI_Transparency(1.f-open_t) + UI_CornerRadius(ui_top_font_size()*0.25f) + { + container = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_RoundChildrenByParent| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DrawDropShadow| + (UI_BoxFlag_SquishAnchored*!!is_anchored), + "floating_view_container_%p", view); + } + + // rjf: peek press inside/outside events + { + for(UI_Event *evt = 0; ui_next_event(&evt);) + { + if(evt->kind == UI_EventKind_Press && + evt->key == OS_Key_LeftMouseButton) + { + if(contains_2f32(container->rect, evt->pos)) + { + t->pressed = 1; + } + else + { + t->pressed_outside = 1; + } + } + } + } + + // rjf: build overlay container for loading animation + UI_Box *loading_overlay_container = &ui_nil_box; + UI_Parent(container) UI_WidthFill UI_HeightFill + { + loading_overlay_container = ui_build_box_from_key(UI_BoxFlag_Floating, ui_key_zero()); + } + + // rjf: build contents + UI_Parent(container) UI_Focus(is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) + { + ui_set_next_pref_width(ui_pct(1, 0)); + ui_set_next_pref_height(ui_pct(1, 0)); + ui_set_next_child_layout_axis(Axis2_Y); + UI_Box *view_contents_container = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip, "###view_contents_container"); + UI_Parent(view_contents_container) UI_WidthFill + { + rd_view_ui(rect); + } + } + + // rjf: build loading overlay + { + RD_ViewState *vs = rd_view_state_from_cfg(view); + F32 loading_t = vs->loading_t; + if(loading_t > 0.01f) UI_Parent(loading_overlay_container) + { + rd_loading_overlay(rect, loading_t, vs->loading_progress_v, vs->loading_progress_v_target); + } + } + + // rjf: interact with container + UI_Signal sig = ui_signal_from_box(container); + t->signal = sig; + } + + // rjf: pop interaction registers; commit if this is focused + RD_Regs *view_regs = rd_pop_regs(); + if(is_focused) + { + MemoryCopyStruct(rd_regs(), view_regs); + } + + // rjf: is not anchored? -> darken rest of screen + if(!is_anchored) + { + UI_TagF("inactive") UI_Transparency(1-open_t) UI_Rect(content_rect) ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_Floating, ui_key_zero()); + } + + //- rjf: autocompletion view early-closing rules + if(t == autocomp_floating_view_task) + { + B32 has_autocomplete_hint = ui_autocomplete_string().size != 0; + B32 has_accept_operation = 0; + for(UI_Event *evt = 0; ui_next_event(&evt);) + { + if(evt->kind == UI_EventKind_Press && evt->slot == UI_EventActionSlot_Accept) + { + has_accept_operation = 1; + break; + } + } + if(has_autocomplete_hint && has_accept_operation) + { + autocomp_floating_view_task->signal.box->fixed_position = v2f32(10000, 10000); + } + } + + //- rjf: hover eval focus rules + if(t == hover_eval_floating_view_task) + { + UI_Signal sig = hover_eval_floating_view_task->signal; + if(ui_pressed(sig) || hover_eval_floating_view_task->pressed) + { + ws->hover_eval_focused = 1; + } + if(ui_mouse_over(sig) || ws->hover_eval_focused) + { + ws->hover_eval_lastt_us = rd_state->time_in_us; + } + else if(ws->hover_eval_lastt_us+1000000 < rd_state->time_in_us) + { + rd_request_frame(); + } + if(hover_eval_floating_view_task->pressed_outside || ui_slot_press(UI_EventActionSlot_Cancel)) + { + ws->hover_eval_focused = 0; + MemoryZeroStruct(&ws->hover_eval_string); + arena_clear(ws->hover_eval_arena); + rd_request_frame(); + } + } + + //- rjf: query interactions + if(t == query_floating_view_task) + { + RD_Cfg *view = query_floating_view_task->view; + RD_ViewState *vs = rd_view_state_from_cfg(query_floating_view_task->view); + String8 cmd_name = ws->query_regs->cmd_name; + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + + // rjf: close queries + if(query_floating_view_task->pressed_outside || + (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg && !vs->query_is_open) || + (cmd_name.size != 0 && !vs->query_is_open) || + ui_slot_press(UI_EventActionSlot_Cancel)) + { + rd_cmd(RD_CmdKind_CancelQuery); + } + + // rjf: any queries which take a file path mutate the debugger's "current path" + if(cmd_kind_info->query.slot == RD_RegSlot_FilePath) + { + RD_Cfg *query = rd_cfg_child_from_string(view, str8_lit("query")); + RD_Cfg *input = rd_cfg_child_from_string(query, str8_lit("input")); + if(input != &rd_nil_cfg) + { + String8 path_chopped = str8_chop_last_slash(input->first->string); + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *current_path = rd_cfg_child_from_string_or_alloc(user, str8_lit("current_path")); + if(!str8_match(current_path->first->string, path_chopped, 0)) + { + rd_cmd(RD_CmdKind_SetCurrentPath, .file_path = path_chopped); + } + } + } + } + } + } + + //////////////////////////// + //- rjf: @window_ui_part top bar // ProfScope("build top bar") { @@ -5336,8 +7496,8 @@ rd_window_frame(RD_Window *ws) os_window_push_custom_edges(ws->os, window_edge_px); os_window_push_custom_title_bar(ws->os, dim_2f32(top_bar_rect).y); ui_set_next_flags(UI_BoxFlag_DefaultFocusNav|UI_BoxFlag_DisableFocusOverlay); - RD_Palette(RD_PaletteCode_MenuBar) - UI_Focus((ws->menu_bar_focused && window_is_focused && !ui_any_ctx_menu_is_open() && !ws->hover_eval_focused) ? UI_FocusKind_On : UI_FocusKind_Null) + UI_Focus((ws->menu_bar_focused && window_is_focused && !ui_any_ctx_menu_is_open()) ? UI_FocusKind_On : UI_FocusKind_Null) + UI_TagF("menu_bar") UI_Pane(top_bar_rect, str8_lit("###top_bar")) UI_WidthFill UI_Row UI_Focus(UI_FocusKind_Null) @@ -5346,634 +7506,398 @@ rd_window_frame(RD_Window *ws) MemoryZeroArray(ui_top_parent()->parent->corner_radii); //- rjf: left column - ui_set_next_flags(UI_BoxFlag_Clip|UI_BoxFlag_ViewScrollX|UI_BoxFlag_ViewClamp); - UI_WidthFill UI_NamedRow(str8_lit("###menu_bar")) { - //- rjf: icon - UI_Padding(ui_em(0.5f, 1.f)) + ui_set_next_flags(UI_BoxFlag_Clip|UI_BoxFlag_ViewScrollX|UI_BoxFlag_ViewClamp); + UI_WidthFill UI_NamedRow(str8_lit("###menu_bar")) { - UI_PrefWidth(ui_px(dim_2f32(top_bar_rect).y - ui_top_font_size()*0.8f, 1.f)) - UI_Column - UI_Padding(ui_em(0.4f, 1.f)) - UI_HeightFill + //- rjf: icon + UI_Padding(ui_em(0.5f, 1.f)) { - R_Handle texture = rd_state->icon_texture; - Vec2S32 texture_dim = r_size_from_tex2d(texture); - ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); - } - } - - //- rjf: menu items - ui_set_next_flags(UI_BoxFlag_DrawBackground); - UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(20, 1)) UI_GroupKey(menu_bar_group_key) - { - // rjf: file menu - UI_Key file_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_file_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(file_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - String8 cmds[] = - { - rd_cmd_kind_info_table[RD_CmdKind_Open].string, - rd_cmd_kind_info_table[RD_CmdKind_OpenUser].string, - rd_cmd_kind_info_table[RD_CmdKind_OpenProject].string, - rd_cmd_kind_info_table[RD_CmdKind_OpenRecentProject].string, - rd_cmd_kind_info_table[RD_CmdKind_Exit].string, - }; - U32 codepoints[] = - { - 'o', - 'u', - 'p', - 'r', - 'x', - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - } - - // rjf: window menu - UI_Key window_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_window_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(window_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - String8 cmds[] = - { - rd_cmd_kind_info_table[RD_CmdKind_OpenWindow].string, - rd_cmd_kind_info_table[RD_CmdKind_CloseWindow].string, - rd_cmd_kind_info_table[RD_CmdKind_ToggleFullscreen].string, - }; - U32 codepoints[] = - { - 'w', - 'c', - 'f', - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - } - - // rjf: panel menu - UI_Key panel_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_panel_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(panel_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - String8 cmds[] = - { - rd_cmd_kind_info_table[RD_CmdKind_NewPanelUp].string, - rd_cmd_kind_info_table[RD_CmdKind_NewPanelDown].string, - rd_cmd_kind_info_table[RD_CmdKind_NewPanelRight].string, - rd_cmd_kind_info_table[RD_CmdKind_NewPanelLeft].string, - rd_cmd_kind_info_table[RD_CmdKind_ClosePanel].string, - rd_cmd_kind_info_table[RD_CmdKind_RotatePanelColumns].string, - rd_cmd_kind_info_table[RD_CmdKind_NextPanel].string, - rd_cmd_kind_info_table[RD_CmdKind_PrevPanel].string, - rd_cmd_kind_info_table[RD_CmdKind_CloseTab].string, - rd_cmd_kind_info_table[RD_CmdKind_NextTab].string, - rd_cmd_kind_info_table[RD_CmdKind_PrevTab].string, - rd_cmd_kind_info_table[RD_CmdKind_TabBarTop].string, - rd_cmd_kind_info_table[RD_CmdKind_TabBarBottom].string, - rd_cmd_kind_info_table[RD_CmdKind_ResetToDefaultPanels].string, - rd_cmd_kind_info_table[RD_CmdKind_ResetToCompactPanels].string, - }; - U32 codepoints[] = - { - 'u', - 'd', - 'r', - 'l', - 'x', - 'c', - 'n', - 'p', - 't', - 'b', - 'v', - 0, - 0, - 0, - 0, - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - } - - // rjf: view menu - UI_Key view_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_view_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(view_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - String8 cmds[] = - { - rd_cmd_kind_info_table[RD_CmdKind_Targets].string, - rd_cmd_kind_info_table[RD_CmdKind_Scheduler].string, - rd_cmd_kind_info_table[RD_CmdKind_CallStack].string, - rd_cmd_kind_info_table[RD_CmdKind_Modules].string, - rd_cmd_kind_info_table[RD_CmdKind_Output].string, - rd_cmd_kind_info_table[RD_CmdKind_Memory].string, - rd_cmd_kind_info_table[RD_CmdKind_Disassembly].string, - rd_cmd_kind_info_table[RD_CmdKind_Watch].string, - rd_cmd_kind_info_table[RD_CmdKind_Locals].string, - rd_cmd_kind_info_table[RD_CmdKind_Registers].string, - rd_cmd_kind_info_table[RD_CmdKind_Globals].string, - rd_cmd_kind_info_table[RD_CmdKind_ThreadLocals].string, - rd_cmd_kind_info_table[RD_CmdKind_Types].string, - rd_cmd_kind_info_table[RD_CmdKind_Procedures].string, - rd_cmd_kind_info_table[RD_CmdKind_Breakpoints].string, - rd_cmd_kind_info_table[RD_CmdKind_WatchPins].string, - rd_cmd_kind_info_table[RD_CmdKind_FilePathMap].string, - rd_cmd_kind_info_table[RD_CmdKind_AutoViewRules].string, - rd_cmd_kind_info_table[RD_CmdKind_Settings].string, - rd_cmd_kind_info_table[RD_CmdKind_ExceptionFilters].string, - rd_cmd_kind_info_table[RD_CmdKind_GettingStarted].string, - }; - U32 codepoints[] = - { - 't', - 's', - 'k', - 'd', - 'o', - 'm', - 'y', - 'w', - 'l', - 'r', - 0, - 0, - 0, - 0, - 'b', - 'h', - 'p', - 'v', - 'e', - 'g', - 0, - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - } - - // rjf: targets menu - UI_Key targets_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_targets_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(targets_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - Temp scratch = scratch_begin(0, 0); - String8 cmds[] = - { - rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string, - }; - U32 codepoints[] = - { - 'a', - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - scratch_end(scratch); - } - - // rjf: ctrl menu - UI_Key ctrl_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_ctrl_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(ctrl_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - String8 cmds[] = - { - rd_cmd_kind_info_table[D_CmdKind_Run].string, - rd_cmd_kind_info_table[D_CmdKind_KillAll].string, - rd_cmd_kind_info_table[D_CmdKind_Restart].string, - rd_cmd_kind_info_table[D_CmdKind_Halt].string, - rd_cmd_kind_info_table[D_CmdKind_SoftHaltRefresh].string, - rd_cmd_kind_info_table[D_CmdKind_StepInto].string, - rd_cmd_kind_info_table[D_CmdKind_StepOver].string, - rd_cmd_kind_info_table[D_CmdKind_StepOut].string, - rd_cmd_kind_info_table[D_CmdKind_Attach].string, - }; - U32 codepoints[] = - { - 'r', - 'k', - 's', - 'h', - 'f', - 'i', - 'o', - 't', - 'a', - }; - Assert(ArrayCount(codepoints) == ArrayCount(cmds)); - rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); - } - - // rjf: help menu - UI_Key help_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_help_menu_key_")); - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(help_menu_key) - UI_PrefWidth(ui_em(50.f, 1.f)) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - UI_Row UI_TextAlignment(UI_TextAlign_Center) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); - ui_spacer(ui_em(1.f, 1.f)); - UI_PrefHeight(ui_children_sum(1)) UI_Row UI_Padding(ui_pct(1, 0)) + UI_PrefWidth(ui_px(dim_2f32(top_bar_rect).y - ui_top_font_size()*0.8f, 1.f)) + UI_Column + UI_Padding(ui_em(0.4f, 1.f)) + UI_HeightFill { R_Handle texture = rd_state->icon_texture; Vec2S32 texture_dim = r_size_from_tex2d(texture); - UI_PrefWidth(ui_px(ui_top_font_size()*10.f, 1.f)) - UI_PrefHeight(ui_px(ui_top_font_size()*10.f, 1.f)) - ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); + ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); } - ui_spacer(ui_em(1.f, 1.f)); - UI_Row - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextAlignment(UI_TextAlign_Center) - UI_Padding(ui_pct(1, 0)) - { - ui_labelf("Search for commands by pressing "); - UI_Flags(UI_BoxFlag_DrawBorder) - UI_TextAlignment(UI_TextAlign_Center) - rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_RunCommand].string); - } - ui_spacer(ui_em(1.f, 1.f)); - RD_Palette(RD_PaletteCode_NeutralPopButton) - UI_Row UI_Padding(ui_pct(1, 0)) UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(10, 1)) - UI_CornerRadius(ui_top_font_size()*0.5f) - { - String8 url = str8_lit("https://github.com/EpicGamesExt/raddebugger/issues"); - UI_Signal sig = ui_button(str8_lit("Submit Request, Issue, or Bug Report")); - if(ui_clicked(sig)) - { - os_open_in_browser(url); - } - } - ui_spacer(ui_em(0.5f, 1.f)); } - // rjf: buttons - UI_TextAlignment(UI_TextAlign_Center) UI_HeightFill + //- rjf: menu items + if(dim_2f32(top_bar_rect).x > ui_top_font_size()*60) { - // rjf: set up table - struct + ui_set_next_flags(UI_BoxFlag_DrawBackground); + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(20, 1)) UI_GroupKey(menu_bar_group_key) { - String8 name; - U32 codepoint; - OS_Key key; - UI_Key menu_key; - } - items[] = - { - {str8_lit("File"), 'f', OS_Key_F, file_menu_key}, - {str8_lit("Window"), 'w', OS_Key_W, window_menu_key}, - {str8_lit("Panel"), 'p', OS_Key_P, panel_menu_key}, - {str8_lit("View"), 'v', OS_Key_V, view_menu_key}, - {str8_lit("Targets"), 't', OS_Key_T, targets_menu_key}, - {str8_lit("Control"), 'c', OS_Key_C, ctrl_menu_key}, - {str8_lit("Help"), 'h', OS_Key_H, help_menu_key}, - }; - - // rjf: determine if one of the menus is already open - B32 menu_open = 0; - U64 open_menu_idx = 0; - for(U64 idx = 0; idx < ArrayCount(items); idx += 1) - { - if(ui_ctx_menu_is_open(items[idx].menu_key)) + // rjf: file menu + UI_Key file_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_file_menu_key_")); + UI_CtxMenu(file_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") { - menu_open = 1; - open_menu_idx = idx; - break; + String8 cmds[] = + { + rd_cmd_kind_info_table[RD_CmdKind_Open].string, + rd_cmd_kind_info_table[RD_CmdKind_OpenPalette].string, + rd_cmd_kind_info_table[RD_CmdKind_NewUser].string, + rd_cmd_kind_info_table[RD_CmdKind_NewProject].string, + rd_cmd_kind_info_table[RD_CmdKind_OpenUser].string, + rd_cmd_kind_info_table[RD_CmdKind_OpenProject].string, + rd_cmd_kind_info_table[RD_CmdKind_OpenRecentProject].string, + rd_cmd_kind_info_table[RD_CmdKind_SaveUser].string, + rd_cmd_kind_info_table[RD_CmdKind_SaveProject].string, + rd_cmd_kind_info_table[RD_CmdKind_UserSettings].string, + rd_cmd_kind_info_table[RD_CmdKind_ProjectSettings].string, + rd_cmd_kind_info_table[RD_CmdKind_Exit].string, + }; + U32 codepoints[] = + { + 'o', + 'n', + 'w', + 'j', + 'u', + 'p', + 'r', + 's', + 'a', + 'e', + 't', + 'x', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); } - } - - // rjf: navigate between menus - U64 open_menu_idx_prime = open_menu_idx; - if(menu_open && ws->menu_bar_focused && window_is_focused) - { - for(UI_Event *evt = 0; ui_next_event(&evt);) + + // rjf: window menu + UI_Key window_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_window_menu_key_")); + UI_CtxMenu(window_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") { - B32 taken = 0; - if(evt->delta_2s32.x > 0) + String8 cmds[] = { - taken = 1; - open_menu_idx_prime += 1; - open_menu_idx_prime = open_menu_idx_prime%ArrayCount(items); - } - if(evt->delta_2s32.x < 0) + rd_cmd_kind_info_table[RD_CmdKind_OpenWindow].string, + rd_cmd_kind_info_table[RD_CmdKind_CloseWindow].string, + rd_cmd_kind_info_table[RD_CmdKind_ToggleFullscreen].string, + rd_cmd_kind_info_table[RD_CmdKind_WindowSettings].string, + }; + U32 codepoints[] = { - taken = 1; - open_menu_idx_prime = open_menu_idx_prime > 0 ? open_menu_idx_prime-1 : (ArrayCount(items)-1); - } - if(taken) - { - ui_eat_event(evt); - } + 'w', + 'c', + 'f', + 's', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); } - } - - // rjf: make ui - for(U64 idx = 0; idx < ArrayCount(items); idx += 1) - { - ui_set_next_fastpath_codepoint(items[idx].codepoint); - B32 alt_fastpath_key = 0; - if(ui_key_press(OS_Modifier_Alt, items[idx].key)) + + // rjf: panel menu + UI_Key panel_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_panel_menu_key_")); + UI_CtxMenu(panel_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") { - alt_fastpath_key = 1; - } - if((ws->menu_bar_key_held || ws->menu_bar_focused) && !ui_any_ctx_menu_is_open()) - { - ui_set_next_flags(UI_BoxFlag_DrawTextFastpathCodepoint); - } - UI_Signal sig = rd_menu_bar_button(items[idx].name); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(menu_open) - { - if((ui_hovering(sig) && !ui_ctx_menu_is_open(items[idx].menu_key)) || (open_menu_idx_prime == idx && open_menu_idx_prime != open_menu_idx)) + String8 cmds[] = { - ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + rd_cmd_kind_info_table[RD_CmdKind_NewPanelUp].string, + rd_cmd_kind_info_table[RD_CmdKind_NewPanelDown].string, + rd_cmd_kind_info_table[RD_CmdKind_NewPanelRight].string, + rd_cmd_kind_info_table[RD_CmdKind_NewPanelLeft].string, + rd_cmd_kind_info_table[RD_CmdKind_ClosePanel].string, + rd_cmd_kind_info_table[RD_CmdKind_RotatePanelColumns].string, + rd_cmd_kind_info_table[RD_CmdKind_NextPanel].string, + rd_cmd_kind_info_table[RD_CmdKind_PrevPanel].string, + rd_cmd_kind_info_table[RD_CmdKind_TabBarTop].string, + rd_cmd_kind_info_table[RD_CmdKind_TabBarBottom].string, + rd_cmd_kind_info_table[RD_CmdKind_ResetToDefaultPanels].string, + rd_cmd_kind_info_table[RD_CmdKind_ResetToCompactPanels].string, + rd_cmd_kind_info_table[RD_CmdKind_ResetToSimplePanels].string, + }; + U32 codepoints[] = + { + 'u', + 'd', + 'r', + 'l', + 'x', + 'c', + 'n', + 'p', + 0, + 0, + 0, + 0, + 0, + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); + } + + // rjf: view menu + UI_Key tab_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_tab_menu_key_")); + UI_CtxMenu(tab_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") + { + String8 cmds[] = + { + rd_cmd_kind_info_table[RD_CmdKind_OpenTab].string, + rd_cmd_kind_info_table[RD_CmdKind_CloseTab].string, + rd_cmd_kind_info_table[RD_CmdKind_DuplicateTab].string, + rd_cmd_kind_info_table[RD_CmdKind_MoveTabLeft].string, + rd_cmd_kind_info_table[RD_CmdKind_MoveTabRight].string, + rd_cmd_kind_info_table[RD_CmdKind_NextTab].string, + rd_cmd_kind_info_table[RD_CmdKind_PrevTab].string, + rd_cmd_kind_info_table[RD_CmdKind_TabSettings].string, + }; + U32 codepoints[] = + { + 'o', + 'c', + 'd', + 'l', + 'r', + 'n', + 'p', + 's', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); + } + + // rjf: targets menu + UI_Key targets_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_targets_menu_key_")); + UI_CtxMenu(targets_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") + { + Temp scratch = scratch_begin(0, 0); + String8 cmds[] = + { + rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string, + rd_cmd_kind_info_table[RD_CmdKind_LaunchAndRun].string, + rd_cmd_kind_info_table[RD_CmdKind_LaunchAndStepInto].string, + }; + U32 codepoints[] = + { + 'a', + 'r', + 's', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); + scratch_end(scratch); + } + + // rjf: ctrl menu + UI_Key ctrl_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_ctrl_menu_key_")); + UI_CtxMenu(ctrl_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") + { + String8 cmds[] = + { + rd_cmd_kind_info_table[D_CmdKind_Run].string, + rd_cmd_kind_info_table[D_CmdKind_KillAll].string, + rd_cmd_kind_info_table[D_CmdKind_Restart].string, + rd_cmd_kind_info_table[D_CmdKind_Halt].string, + rd_cmd_kind_info_table[D_CmdKind_StepInto].string, + rd_cmd_kind_info_table[D_CmdKind_StepOver].string, + rd_cmd_kind_info_table[D_CmdKind_StepOut].string, + rd_cmd_kind_info_table[D_CmdKind_Attach].string, + }; + U32 codepoints[] = + { + 'r', + 'k', + 's', + 'h', + 'i', + 'o', + 't', + 'a', + }; + Assert(ArrayCount(codepoints) == ArrayCount(cmds)); + rd_cmd_list_menu_buttons(ArrayCount(cmds), cmds, codepoints); + } + + // rjf: help menu + UI_Key help_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_help_menu_key_")); + UI_CtxMenu(help_menu_key) UI_PrefWidth(ui_em(50.f, 1.f)) UI_TagF("implicit") + { + UI_Row UI_TextAlignment(UI_TextAlign_Center) UI_TagF("weak") + ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); + ui_spacer(ui_em(1.f, 1.f)); + UI_PrefHeight(ui_children_sum(1)) UI_Row UI_Padding(ui_pct(1, 0)) + { + R_Handle texture = rd_state->icon_texture; + Vec2S32 texture_dim = r_size_from_tex2d(texture); + UI_PrefWidth(ui_px(ui_top_font_size()*10.f, 1.f)) + UI_PrefHeight(ui_px(ui_top_font_size()*10.f, 1.f)) + ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); } - } - else if(ui_pressed(sig) || alt_fastpath_key) - { - if(ui_ctx_menu_is_open(items[idx].menu_key)) + ui_spacer(ui_em(1.f, 1.f)); + UI_Row + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) + UI_Padding(ui_pct(1, 0)) { - ui_ctx_menu_close(); + ui_labelf("Search for commands and options by pressing "); + UI_Flags(UI_BoxFlag_DrawBorder) + UI_TextAlignment(UI_TextAlign_Center) + rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_OpenPalette].string, str8_zero(), 1); } - else + ui_spacer(ui_em(1.f, 1.f)); + UI_TagF("pop") + UI_Row UI_Padding(ui_pct(1, 0)) UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(10, 1)) + UI_CornerRadius(ui_top_font_size()*0.5f) { - ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + String8 url = str8_lit("https://github.com/EpicGamesExt/raddebugger/issues"); + UI_Signal sig = ui_button(str8_lit("Submit Request, Issue, or Bug Report")); + if(ui_clicked(sig)) + { + os_open_in_browser(url); + } + } + ui_spacer(ui_em(0.5f, 1.f)); + } + + // rjf: buttons + UI_TextAlignment(UI_TextAlign_Center) UI_HeightFill + { + // rjf: set up table + struct + { + String8 name; + U32 codepoint; + OS_Key key; + UI_Key menu_key; + } + items[] = + { + {str8_lit("File"), 'f', OS_Key_F, file_menu_key}, + {str8_lit("Window"), 'w', OS_Key_W, window_menu_key}, + {str8_lit("Panel"), 'p', OS_Key_P, panel_menu_key}, + {str8_lit("Tab"), 'b', OS_Key_V, tab_menu_key}, + {str8_lit("Targets"), 't', OS_Key_T, targets_menu_key}, + {str8_lit("Control"), 'c', OS_Key_C, ctrl_menu_key}, + {str8_lit("Help"), 'h', OS_Key_H, help_menu_key}, + }; + + // rjf: determine if one of the menus is already open + B32 menu_open = 0; + U64 open_menu_idx = 0; + for(U64 idx = 0; idx < ArrayCount(items); idx += 1) + { + if(ui_ctx_menu_is_open(items[idx].menu_key)) + { + menu_open = 1; + open_menu_idx = idx; + break; + } + } + + // rjf: navigate between menus + U64 open_menu_idx_prime = open_menu_idx; + if(menu_open && ws->menu_bar_focused && window_is_focused) + { + for(UI_Event *evt = 0; ui_next_event(&evt);) + { + B32 taken = 0; + if(evt->delta_2s32.x > 0) + { + taken = 1; + open_menu_idx_prime += 1; + open_menu_idx_prime = open_menu_idx_prime%ArrayCount(items); + } + if(evt->delta_2s32.x < 0) + { + taken = 1; + open_menu_idx_prime = open_menu_idx_prime > 0 ? open_menu_idx_prime-1 : (ArrayCount(items)-1); + } + if(taken) + { + ui_eat_event(evt); + } + } + } + + // rjf: make ui + for(U64 idx = 0; idx < ArrayCount(items); idx += 1) + { + ui_set_next_fastpath_codepoint(items[idx].codepoint); + B32 alt_fastpath_key = 0; + if(rd_setting_b32_from_name(str8_lit("focus_menu_bar_with_alt")) && ui_key_press(OS_Modifier_Alt, items[idx].key)) + { + alt_fastpath_key = 1; + } + if((ws->menu_bar_key_held || ws->menu_bar_focused) && !ui_any_ctx_menu_is_open()) + { + ui_set_next_flags(UI_BoxFlag_DrawTextFastpathCodepoint); + } + UI_Signal sig = rd_menu_bar_button(items[idx].name); + os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); + if(menu_open) + { + if((ui_hovering(sig) && !ui_ctx_menu_is_open(items[idx].menu_key)) || (open_menu_idx_prime == idx && open_menu_idx_prime != open_menu_idx)) + { + ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + } + } + else if(ui_pressed(sig) || alt_fastpath_key) + { + if(ui_ctx_menu_is_open(items[idx].menu_key)) + { + ui_ctx_menu_close(); + } + else + { + ui_ctx_menu_open(items[idx].menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); + } + } } } } } } - - ui_spacer(ui_em(0.75f, 1)); - - // rjf: conversion task visualization - UI_PrefWidth(ui_text_dim(10, 1)) UI_HeightFill - RD_Palette(RD_PaletteCode_NeutralPopButton) - { - Temp scratch = scratch_begin(0, 0); - RD_EntityList tasks = rd_query_cached_entity_list_with_kind(RD_EntityKind_ConversionTask); - for(RD_EntityNode *n = tasks.first; n != 0; n = n->next) - { - RD_Entity *task = n->entity; - if(task->alloc_time_us + 500000 < os_now_microseconds()) - { - String8 rdi_path = task->string; - String8 rdi_name = str8_skip_last_slash(rdi_path); - String8 task_text = push_str8f(scratch.arena, "Creating %S...", rdi_name); - UI_Key key = ui_key_from_stringf(ui_key_zero(), "task_%p", task); - UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawText|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, key); - os_window_push_custom_title_bar_client_area(ws->os, box->rect); - UI_Signal sig = ui_signal_from_box(box); - if(ui_hovering(sig)) UI_Tooltip - { - ui_label(rdi_path); - } - ui_box_equip_display_string(box, task_text); - } - } - scratch_end(scratch); - } } //- rjf: center column - UI_PrefWidth(ui_children_sum(1.f)) UI_Row - UI_PrefWidth(ui_em(2.25f, 1)) + if(dim_2f32(top_bar_rect).x > ui_top_font_size()*60) + UI_PrefWidth(ui_children_sum(1.f)) UI_Row + UI_PrefWidth(ui_px(dim_2f32(top_bar_rect).y, 1)) RD_Font(RD_FontSlot_Icons) UI_FontSize(ui_top_font_size()*0.85f) { Temp scratch = scratch_begin(0, 0); - RD_EntityList targets = rd_push_active_target_list(scratch.arena); - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); - B32 have_targets = targets.count != 0; + RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); B32 can_send_signal = !d_ctrl_targets_running(); - B32 can_play = (have_targets && (can_send_signal || d_ctrl_last_run_frame_idx()+4 > d_frame_index())); - B32 can_pause = (!can_send_signal); - B32 can_stop = (processes.count != 0); - B32 can_step = (processes.count != 0 && can_send_signal); - - //- rjf: play button - if(can_play || !have_targets || processes.count == 0) - UI_TextAlignment(UI_TextAlign_Center) - UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextPositive))) + typedef struct CenterButtonTask CenterButtonTask; + struct CenterButtonTask { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_Play]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(ui_hovering(sig) && !can_play) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: %s", have_targets ? "Targets are currently running" : "No active targets exist"); - } - if(ui_hovering(sig) && can_play) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - { - if(can_stop) - { - ui_labelf("Resume all processes"); - } - else - { - ui_labelf("Launch all active targets:"); - for(RD_EntityNode *n = targets.first; n != 0; n = n->next) - { - DR_FancyStringList title_fstrs = rd_title_fstrs_from_entity(ui_build_arena(), n->entity, ui_top_palette()->text_weak, ui_top_font_size()); - UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &title_fstrs); - } - } - } - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_Run); - } - } - - //- rjf: restart button - else UI_TextAlignment(UI_TextAlign_Center) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextPositive))) + String8 cmd_name; + String8 tag; + B32 is_enabled; + }; + CenterButtonTask center_button_tasks[] = { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_Redo]); + {rd_cmd_kind_info_table[RD_CmdKind_Run].string, str8_lit("good"), (can_send_signal || d_ctrl_last_run_frame_idx()+4 > d_frame_index())}, + {rd_cmd_kind_info_table[RD_CmdKind_Restart].string, str8_lit("neutral"), processes.count != 0}, + {rd_cmd_kind_info_table[RD_CmdKind_Halt].string, str8_lit("weak"), !can_send_signal}, + {rd_cmd_kind_info_table[RD_CmdKind_KillAll].string, str8_lit("bad"), processes.count != 0}, + {rd_cmd_kind_info_table[RD_CmdKind_StepOver].string, str8_lit("weak"), can_send_signal}, + {rd_cmd_kind_info_table[RD_CmdKind_StepInto].string, str8_lit("weak"), can_send_signal}, + {rd_cmd_kind_info_table[RD_CmdKind_StepOut].string, str8_lit("weak"), processes.count != 0 && can_send_signal}, + }; + UI_TextAlignment(UI_TextAlign_Center) + for EachElement(idx, center_button_tasks) + UI_Flags(center_button_tasks[idx].is_enabled ? 0 : UI_BoxFlag_Disabled) + UI_Tag(center_button_tasks[idx].is_enabled ? center_button_tasks[idx].tag : str8_lit("weak")) + { + String8 cmd_name = center_button_tasks[idx].cmd_name; + UI_Signal sig = ui_button(rd_icon_kind_text_table[rd_icon_kind_from_code_name(cmd_name)]); os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); if(ui_hovering(sig)) { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - { - ui_labelf("Restart"); - } + RD_RegsScope(.cmd_name = cmd_name, .ui_key = sig.box->key) rd_set_hover_regs(RD_RegSlot_CmdName); } if(ui_clicked(sig)) { - rd_cmd(RD_CmdKind_Restart); + rd_push_cmd(cmd_name, rd_regs()); } } - - //- rjf: pause button - UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_pause ? 0 : UI_BoxFlag_Disabled) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNeutral))) - { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_Pause]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(ui_hovering(sig) && !can_pause) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: Already halted"); - } - if(ui_hovering(sig) && can_pause) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Halt all attached processes"); - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_Halt); - } - } - - //- rjf: stop button - UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_stop ? 0 : UI_BoxFlag_Disabled) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative))) - { - UI_Signal sig = {0}; - { - sig = ui_button(rd_icon_kind_text_table[RD_IconKind_Stop]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - } - if(ui_hovering(sig) && !can_stop) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: No processes are running"); - } - if(ui_hovering(sig) && can_stop) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Kill all attached processes"); - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_KillAll); - } - } - - //- rjf: step over button - UI_TextAlignment(UI_TextAlign_Center) UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) - { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_StepOver]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(ui_hovering(sig)) - { - if(can_play) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Step Over"); - } - else - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: %s", have_targets ? "Targets are currently running" : "No active targets exist"); - } - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_StepOver); - } - } - - //- rjf: step into button - UI_TextAlignment(UI_TextAlign_Center) UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) - { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_StepInto]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(ui_hovering(sig)) - { - if(can_play) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Step Into"); - } - else - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: %s", have_targets ? "Targets are currently running" : "No active targets exist"); - } - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_StepInto); - } - } - - //- rjf: step out button - UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_step ? 0 : UI_BoxFlag_Disabled) - { - UI_Signal sig = ui_button(rd_icon_kind_text_table[RD_IconKind_StepOut]); - os_window_push_custom_title_bar_client_area(ws->os, sig.box->rect); - if(ui_hovering(sig) && !can_step && can_pause) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: Running"); - } - if(ui_hovering(sig) && !can_step && !can_stop) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Disabled: No processes are running"); - } - if(ui_hovering(sig) && can_step) - { - UI_Tooltip - RD_Font(RD_FontSlot_Main) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - ui_labelf("Step Out"); - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_StepOut); - } - } - scratch_end(scratch); } @@ -5985,11 +7909,10 @@ rd_window_frame(RD_Window *ws) ui_spacer(ui_pct(1, 0)); // rjf: loaded user viz - if(do_user_prof) RD_Palette(RD_PaletteCode_NeutralPopButton) + if(do_user_prof) UI_TagF("pop") { ui_set_next_pref_width(ui_children_sum(1)); ui_set_next_child_layout_axis(Axis2_X); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *user_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBackground| @@ -5999,7 +7922,7 @@ rd_window_frame(RD_Window *ws) os_window_push_custom_title_bar_client_area(ws->os, user_box->rect); UI_Parent(user_box) UI_PrefWidth(ui_text_dim(10, 0)) UI_TextAlignment(UI_TextAlign_Center) { - String8 user_path = rd_cfg_path_from_src(RD_CfgSrc_User); + String8 user_path = rd_state->user_path; user_path = str8_chop_last_dot(user_path); RD_Font(RD_FontSlot_Icons) UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Icons)) @@ -6019,11 +7942,10 @@ rd_window_frame(RD_Window *ws) } // rjf: loaded project viz - if(do_user_prof) RD_Palette(RD_PaletteCode_NeutralPopButton) + if(do_user_prof) UI_TagF("pop") { ui_set_next_pref_width(ui_children_sum(1)); ui_set_next_child_layout_axis(Axis2_X); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *prof_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBackground| @@ -6033,7 +7955,7 @@ rd_window_frame(RD_Window *ws) os_window_push_custom_title_bar_client_area(ws->os, prof_box->rect); UI_Parent(prof_box) UI_PrefWidth(ui_text_dim(10, 0)) UI_TextAlignment(UI_TextAlign_Center) { - String8 prof_path = rd_cfg_path_from_src(RD_CfgSrc_Project); + String8 prof_path = rd_state->project_path; prof_path = str8_chop_last_dot(prof_path); RD_Font(RD_FontSlot_Icons) ui_label(rd_icon_kind_text_table[RD_IconKind_Briefcase]); @@ -6051,6 +7973,20 @@ rd_window_frame(RD_Window *ws) ui_spacer(ui_em(0.75f, 0)); } + // rjf: close dropdown + UI_Key close_ctx_menu_key = ui_key_from_stringf(ui_key_zero(), "###close_ctx_menu"); + UI_CtxMenu(close_ctx_menu_key) UI_TagF("implicit") + { + if(ui_clicked(rd_icon_buttonf(RD_IconKind_Window, 0, "Close Window"))) + { + rd_cmd(RD_CmdKind_CloseWindow); + } + if(ui_clicked(rd_icon_buttonf(RD_IconKind_X, 0, "Exit"))) + { + rd_cmd(RD_CmdKind_Exit); + } + } + // rjf: min/max/close buttons { UI_Signal min_sig = {0}; @@ -6059,12 +7995,13 @@ rd_window_frame(RD_Window *ws) Vec2F32 bar_dim = dim_2f32(top_bar_rect); F32 button_dim = floor_f32(bar_dim.y); UI_PrefWidth(ui_px(button_dim, 1.f)) + UI_FontSize(ui_top_font_size()*0.75f) { - min_sig = rd_icon_buttonf(RD_IconKind_Minus, 0, "##minimize"); - max_sig = rd_icon_buttonf(RD_IconKind_Window, 0, "##maximize"); + min_sig = rd_icon_buttonf(RD_IconKind_WindowMinimize, 0, "##minimize"); + max_sig = rd_icon_buttonf(os_window_is_maximized(ws->os) ? RD_IconKind_WindowRestore : RD_IconKind_Window, 0, "##maximize"); } UI_PrefWidth(ui_px(button_dim, 1.f)) - RD_Palette(RD_PaletteCode_NegativePopButton) + UI_TagF("bad_pop") { cls_sig = rd_icon_buttonf(RD_IconKind_X, 0, "##close"); } @@ -6078,7 +8015,15 @@ rd_window_frame(RD_Window *ws) } if(ui_clicked(cls_sig)) { - rd_cmd(RD_CmdKind_CloseWindow, .window = rd_handle_from_window(ws)); + if(ws->order_next != &rd_nil_window_state || + ws->order_prev != &rd_nil_window_state) + { + ui_ctx_menu_open(close_ctx_menu_key, cls_sig.box->key, v2f32(0, dim_2f32(cls_sig.box->rect).y)); + } + else + { + rd_cmd(RD_CmdKind_Exit); + } } os_window_push_custom_title_bar_client_area(ws->os, min_sig.box->rect); os_window_push_custom_title_bar_client_area(ws->os, max_sig.box->rect); @@ -6089,52 +8034,111 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: bottom bar + //- rjf: @window_ui_part bottom bar // ProfScope("build bottom bar") { + //- rjf: unpack status info B32 is_running = d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index(); CTRL_Event stop_event = d_ctrl_last_stop_event(); - UI_Palette *positive_scheme = rd_palette_from_code(RD_PaletteCode_PositivePopButton); - UI_Palette *running_scheme = rd_palette_from_code(RD_PaletteCode_NeutralPopButton); - UI_Palette *negative_scheme = rd_palette_from_code(RD_PaletteCode_NegativePopButton); - UI_Palette *palette = running_scheme; - if(!is_running) + String8 tag = str8_lit("pop"); + RD_CfgList tasks = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("conversion_task")); + RD_CfgList long_running_tasks = {0}; + F32 alive_t_rate = 1 - pow_f32(2, (-5.f * rd_state->frame_dt)); + for(RD_CfgNode *n = tasks.first; n != 0; n = n->next) + { + RD_Cfg *task = n->v; + F32 task_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "task_anim_%I64u", task->id), 1.f, .rate = alive_t_rate); + if(task_t > 0.5f) + { + rd_cfg_list_push(scratch.arena, &long_running_tasks, task); + } + } + if(rd_state->bind_change_active) + { + tag = str8_lit("pop"); + } + else if(ws->error_t >= 0.01f && ws->error_string_size != 0) + { + tag = str8_lit("bad_pop"); + } + else if(!is_running) { switch(stop_event.cause) { default: case CTRL_EventCause_Finished: { - palette = positive_scheme; + tag = str8_lit("good_pop"); }break; case CTRL_EventCause_UserBreakpoint: case CTRL_EventCause_InterruptedByException: case CTRL_EventCause_InterruptedByTrap: case CTRL_EventCause_InterruptedByHalt: { - palette = negative_scheme; + tag = str8_lit("bad_pop"); }break; } } - if(ws->error_t > 0.01f) + + //- rjf: compute fstrs for status explanation + DR_FStrList status_fstrs = {0}; { - UI_Palette *blended_scheme = push_array(ui_build_arena(), UI_Palette, 1); - MemoryCopyStruct(blended_scheme, palette); - for EachEnumVal(UI_ColorCode, code) + if(rd_state->bind_change_active) { - for(U64 idx = 0; idx < 4; idx += 1) + RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(rd_state->bind_change_cmd_name); + String8 display_name = rd_display_from_code_name(info->string); + String8 string = push_str8f(scratch.arena, "Currently rebinding \"%S\"", display_name); + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, string); + } + else if(ws->error_t >= 0.01f && ws->error_string_size != 0) + { + String8 error_string = str8(ws->error_buffer, ws->error_string_size); + ws->error_t -= rd_state->frame_dt/8.f; + rd_request_frame(); + ui_set_next_pref_width(ui_children_sum(1)); + UI_CornerRadius(4) + UI_Row + UI_PrefWidth(ui_text_dim(10, 1)) + UI_TextAlignment(UI_TextAlign_Center) { - blended_scheme->colors[code].v[idx] += (negative_scheme->colors[code].v[idx] - blended_scheme->colors[code].v[idx]) * ws->error_t; + DR_FStrList error_fstrs = rd_fstrs_from_rich_string(scratch.arena, error_string); + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_WarningBig], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_concat_in_place(&status_fstrs, &error_fstrs); } } - palette = blended_scheme; + else if(is_running) + { + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_Play], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, str8_lit(" Running...")); + if(long_running_tasks.count != 0) + { + String8 string = push_str8f(scratch.arena, " Loading %I64u debug information file%s...", long_running_tasks.count, long_running_tasks.count == 1 ? "" : "s"); + dr_fstrs_push_new(scratch.arena, &status_fstrs, ¶ms, string); + } + } + else + { + status_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &stop_event); + } } + + //- rjf: build bottom bar UI_Flags(UI_BoxFlag_DrawBackground) UI_CornerRadius(0) - UI_Palette(palette) + UI_Tag(tag) UI_Pane(bottom_bar_rect, str8_lit("###bottom_bar")) UI_WidthFill UI_Row UI_Flags(0) { + Temp scratch = scratch_begin(0, 0); + // rjf: developer frame-time indicator if(DEV_updating_indicator) { @@ -6145,680 +8149,41 @@ rd_window_frame(RD_Window *ws) ui_spacer(ui_em(1.5f*(1-animation_t), 1.f)); } - // rjf: status + // rjf: build status + UI_PrefWidth(ui_text_dim(10, 1)) { ui_spacer(ui_em(1.f, 1.f)); - if(is_running) - { - ui_label(str8_lit("Running")); - } - else - { - Temp scratch = scratch_begin(0, 0); - DR_FancyStringList explanation_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &stop_event); - UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &explanation_fstrs); - scratch_end(scratch); - } + UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(box, &status_fstrs); } ui_spacer(ui_pct(1, 0)); - // rjf: bind change visualization - if(rd_state->bind_change_active) - { - RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(rd_state->bind_change_cmd_name); + // rjf: version + UI_FontSize(ui_top_font_size()*0.85f) UI_PrefWidth(ui_text_dim(10, 1)) - UI_Flags(UI_BoxFlag_DrawBackground) - UI_TextAlignment(UI_TextAlign_Center) - UI_CornerRadius(4) - RD_Palette(RD_PaletteCode_NeutralPopButton) - ui_labelf("Currently rebinding \"%S\" hotkey", info->display_name); - } - - // rjf: error visualization - else if(ws->error_t >= 0.01f) + UI_TextAlignment(UI_TextAlign_Center) { - ws->error_t -= rd_state->frame_dt/8.f; - rd_request_frame(); - String8 error_string = str8(ws->error_buffer, ws->error_string_size); - if(error_string.size != 0) - { - ui_set_next_pref_width(ui_children_sum(1)); - UI_CornerRadius(4) - UI_Row - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextAlignment(UI_TextAlign_Center) - { - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - ui_label(rd_icon_kind_text_table[RD_IconKind_WarningBig]); - rd_label(error_string); - } - } + ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); } - } - } - - //////////////////////////// - //- rjf: prepare query view stack for the in-progress command - // - if(ws->query_cmd_name.size != 0) - { - RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(ws->query_cmd_name); - RD_RegSlot missing_slot = cmd_kind_info->query.slot; - String8 query_view_name = cmd_kind_info->query.view_name; - if(query_view_name.size == 0) - { - switch(missing_slot) - { - default:{}break; - case RD_RegSlot_Thread: - case RD_RegSlot_Module: - case RD_RegSlot_Process: - case RD_RegSlot_Machine: - case RD_RegSlot_CtrlEntity:{query_view_name = rd_view_rule_kind_info_table[RD_ViewRuleKind_CtrlEntityLister].string;}break; - case RD_RegSlot_Entity: {query_view_name = rd_view_rule_kind_info_table[RD_ViewRuleKind_EntityLister].string;}break; - case RD_RegSlot_EntityList:{query_view_name = rd_view_rule_kind_info_table[RD_ViewRuleKind_EntityLister].string;}break; - case RD_RegSlot_FilePath: {query_view_name = rd_view_rule_kind_info_table[RD_ViewRuleKind_FileSystem].string;}break; - case RD_RegSlot_PID: {query_view_name = rd_view_rule_kind_info_table[RD_ViewRuleKind_SystemProcesses].string;}break; - } - } - RD_ViewRuleInfo *view_spec = rd_view_rule_info_from_string(query_view_name); - if(ws->query_view_stack_top->spec != view_spec || - rd_view_is_nil(ws->query_view_stack_top)) - { - Temp scratch = scratch_begin(0, 0); - - // rjf: clear existing query stack - for(RD_View *query_view = ws->query_view_stack_top, *next = 0; - !rd_view_is_nil(query_view); - query_view = next) - { - next = query_view->order_next; - rd_view_release(query_view); - } - - // rjf: determine default query - String8 default_query = {0}; - switch(missing_slot) - { - default: - if(cmd_kind_info->query.flags & RD_QueryFlag_KeepOldInput) - { - default_query = rd_push_search_string(scratch.arena); - }break; - case RD_RegSlot_FilePath: - { - default_query = path_normalized_from_string(scratch.arena, rd_state->current_path); - default_query = push_str8f(scratch.arena, "%S/", default_query); - }break; - } - - // rjf: construct & push new view - RD_View *view = rd_view_alloc(); - rd_view_equip_spec(view, view_spec, default_query, &md_nil_node); - if(cmd_kind_info->query.flags & RD_QueryFlag_SelectOldInput) - { - view->query_mark = txt_pt(1, 1); - } - ws->query_view_stack_top = view; - ws->query_view_selected = 1; - view->order_next = &rd_nil_view; scratch_end(scratch); } } //////////////////////////// - //- rjf: animate query info - // - { - F32 rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f; - - // rjf: animate query view selection transition - { - F32 target = (F32)!!ws->query_view_selected; - F32 diff = abs_f32(target - ws->query_view_selected_t); - if(diff > 0.005f) - { - rd_request_frame(); - if(diff < 0.005f) - { - ws->query_view_selected_t = target; - } - ws->query_view_selected_t += (target - ws->query_view_selected_t) * rate; - } - } - - // rjf: animate query view open/close transition - { - F32 query_view_t_target = !rd_view_is_nil(ws->query_view_stack_top); - F32 diff = abs_f32(query_view_t_target - ws->query_view_t); - if(diff > 0.005f) - { - rd_request_frame(); - } - if(diff < 0.005f) - { - ws->query_view_t = query_view_t_target; - } - ws->query_view_t += (query_view_t_target - ws->query_view_t) * rate; - } - } - - //////////////////////////// - //- rjf: build query - // - if(!rd_view_is_nil(ws->query_view_stack_top)) - UI_Focus((window_is_focused && !ui_any_ctx_menu_is_open() && !ws->menu_bar_focused && ws->query_view_selected) ? UI_FocusKind_On : UI_FocusKind_Off) - RD_Palette(RD_PaletteCode_Floating) - { - RD_View *view = ws->query_view_stack_top; - String8 query_cmd_name = ws->query_cmd_name; - RD_CmdKindInfo *query_cmd_info = rd_cmd_kind_info_from_string(query_cmd_name); - RD_Query *query = &query_cmd_info->query; - - //- rjf: calculate rectangles - Vec2F32 window_center = center_2f32(window_rect); - F32 query_container_width = dim_2f32(window_rect).x*0.5f; - F32 query_container_margin = ui_top_font_size()*8.f; - F32 query_line_edit_height = ui_top_font_size()*3.f; - Rng2F32 query_container_rect = r2f32p(window_center.x - query_container_width/2 + (1-ws->query_view_t)*query_container_width/4, - window_rect.y0 + query_container_margin, - window_center.x + query_container_width/2 - (1-ws->query_view_t)*query_container_width/4, - window_rect.y1 - query_container_margin); - if(ws->query_view_stack_top->spec == &rd_nil_view_rule_info) - { - query_container_rect.y1 = query_container_rect.y0 + query_line_edit_height; - } - query_container_rect.y1 = mix_1f32(query_container_rect.y0, query_container_rect.y1, ws->query_view_t); - Rng2F32 query_container_content_rect = r2f32p(query_container_rect.x0, - query_container_rect.y0+query_line_edit_height, - query_container_rect.x1, - query_container_rect.y1); - - //- rjf: build floating query view container - UI_Box *query_container_box = &ui_nil_box; - UI_Rect(query_container_rect) - UI_CornerRadius(ui_top_font_size()*0.2f) - UI_ChildLayoutAxis(Axis2_Y) - UI_Squish(0.25f-ws->query_view_t*0.25f) - UI_Transparency(1-ws->query_view_t) - { - query_container_box = ui_build_box_from_stringf(UI_BoxFlag_Floating| - UI_BoxFlag_AllowOverflow| - UI_BoxFlag_Clickable| - UI_BoxFlag_Clip| - UI_BoxFlag_DisableFocusOverlay| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBackgroundBlur| - UI_BoxFlag_DrawDropShadow, - "panel_query_container"); - } - - //- rjf: build query text input - B32 query_completed = 0; - B32 query_cancelled = 0; - UI_Parent(query_container_box) - UI_WidthFill UI_PrefHeight(ui_px(query_line_edit_height, 1.f)) - UI_Focus(UI_FocusKind_On) - { - ui_set_next_flags(UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBorder); - UI_Row - { - UI_PrefWidth(ui_text_dim(0.f, 1.f)) UI_Padding(ui_em(1.f, 1.f)) - { - RD_IconKind icon_kind = query_cmd_info->icon_kind; - if(icon_kind != RD_IconKind_Null) - { - RD_Font(RD_FontSlot_Icons) ui_label(rd_icon_kind_text_table[icon_kind]); - } - ui_labelf("%S", query_cmd_info->display_name); - } - RD_Font((query->flags & RD_QueryFlag_CodeInput) ? RD_FontSlot_Code : RD_FontSlot_Main) - UI_TextPadding(ui_top_font_size()*0.5f) - { - UI_Signal sig = rd_line_edit(RD_LineEditFlag_Border| - (RD_LineEditFlag_CodeContents * !!(query->flags & RD_QueryFlag_CodeInput)), - 0, - 0, - &view->query_cursor, - &view->query_mark, - view->query_buffer, - sizeof(view->query_buffer), - &view->query_string_size, - 0, - str8(view->query_buffer, view->query_string_size), - str8_lit("###query_text_input")); - if(ui_pressed(sig)) - { - ws->query_view_selected = 1; - } - } - UI_PrefWidth(ui_em(5.f, 1.f)) UI_Focus(UI_FocusKind_Off) RD_Palette(RD_PaletteCode_PositivePopButton) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_RightArrow, 0, "##complete_query"))) - { - query_completed = 1; - } - } - UI_PrefWidth(ui_em(3.f, 1.f)) UI_Focus(UI_FocusKind_Off) RD_Palette(RD_PaletteCode_PlainButton) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_X, 0, "##cancel_query"))) - { - query_cancelled = 1; - } - } - } - } - - //- rjf: build query view - UI_Parent(query_container_box) UI_WidthFill UI_Focus(UI_FocusKind_Null) - RD_RegsScope(.view = rd_handle_from_view(view)) - { - RD_ViewRuleUIFunctionType *view_ui = view->spec->ui; - view_ui(str8(view->query_buffer, view->query_string_size), view->params_roots[view->params_read_gen%ArrayCount(view->params_roots)], query_container_content_rect); - } - - //- rjf: query submission - if(((ui_is_focus_active() || (window_is_focused && !ui_any_ctx_menu_is_open() && !ws->menu_bar_focused && !ws->query_view_selected)) && - ui_slot_press(UI_EventActionSlot_Cancel)) || query_cancelled) - { - rd_cmd(RD_CmdKind_CancelQuery); - } - if((ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Accept)) || query_completed) - { - Temp scratch = scratch_begin(0, 0); - RD_View *view = ws->query_view_stack_top; - RD_RegsScope() - { - rd_regs_fill_slot_from_string(query->slot, str8(view->query_buffer, view->query_string_size)); - rd_cmd(RD_CmdKind_CompleteQuery); - } - scratch_end(scratch); - } - - //- rjf: take fallthrough interaction in query view - { - UI_Signal sig = ui_signal_from_box(query_container_box); - if(ui_pressed(sig)) - { - ws->query_view_selected = 1; - } - } - - //- rjf: build darkening overlay for rest of screen - UI_Palette(ui_build_palette(0, .background = mix_4f32(rd_rgba_from_theme_color(RD_ThemeColor_InactivePanelOverlay), v4f32(0, 0, 0, 0), 1-ws->query_view_selected_t))) - UI_Rect(window_rect) - { - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } - else - { - ws->query_view_selected = 0; - } - - //////////////////////////// - //- rjf: build hover eval - // - ProfScope("build hover eval") - { - B32 build_hover_eval = hover_eval_is_open; - - // rjf: disable hover eval if hovered view is actively scrolling - if(hover_eval_is_open) - { - for(RD_Panel *panel = ws->root_panel; - !rd_panel_is_nil(panel); - panel = rd_panel_rec_depth_first_pre(panel).next) - { - if(!rd_panel_is_nil(panel->first)) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel(content_rect, ws->root_panel, panel); - RD_View *view = rd_selected_tab_from_panel(panel); - if(!rd_view_is_nil(view) && - contains_2f32(panel_rect, ui_mouse()) && - (abs_f32(view->scroll_pos.x.off) > 0.01f || - abs_f32(view->scroll_pos.y.off) > 0.01f)) - { - build_hover_eval = 0; - ws->hover_eval_first_frame_idx = rd_state->frame_index; - } - } - } - - // rjf: reset open animation - if(ws->hover_eval_string.size == 0) - { - ws->hover_eval_open_t = 0; - ws->hover_eval_num_visible_rows_t = 0; - } - - // rjf: reset animation, but request frames if we're waiting to open - if(ws->hover_eval_string.size != 0 && !hover_eval_is_open && ws->hover_eval_last_frame_idx < ws->hover_eval_first_frame_idx+20 && rd_state->frame_index-ws->hover_eval_last_frame_idx < 50) - { - rd_request_frame(); - ws->hover_eval_num_visible_rows_t = 0; - ws->hover_eval_open_t = 0; - } - - // rjf: reset focus state if hover eval is not being built - if(!build_hover_eval || ws->hover_eval_string.size == 0 || !hover_eval_is_open) - { - ws->hover_eval_focused = 0; - } - - // rjf: build hover eval - if(build_hover_eval && ws->hover_eval_string.size != 0 && hover_eval_is_open) - RD_Font(RD_FontSlot_Code) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - RD_Palette(RD_PaletteCode_Floating) - { - Temp scratch = scratch_begin(0, 0); - DI_Scope *scope = di_scope_open(); - String8 expr = ws->hover_eval_string; - E_Eval eval = e_eval_from_string(scratch.arena, expr); - EV_ViewRuleList top_level_view_rules = {0}; - - //- rjf: build if good - if(!e_type_key_match(eval.type_key, e_type_key_zero()) && !ui_any_ctx_menu_is_open()) - UI_Focus((hover_eval_is_open && !ui_any_ctx_menu_is_open() && ws->hover_eval_focused && (!query_is_open || !ws->query_view_selected)) ? UI_FocusKind_Null : UI_FocusKind_Off) - { - //- rjf: eval -> viz artifacts - F32 row_height = floor_f32(ui_top_font_size()*2.8f); - RD_CfgTable cfg_table = {0}; - U64 expr_hash = d_hash_from_string(expr); - String8 ev_view_key_string = push_str8f(scratch.arena, "eval_hover_%I64x", expr_hash); - EV_View *ev_view = rd_ev_view_from_key(d_hash_from_string(ev_view_key_string)); - EV_Key parent_key = ev_key_make(5381, 1); - EV_Key key = ev_key_make(ev_hash_from_key(parent_key), 1); - EV_BlockTree block_tree = ev_block_tree_from_string(scratch.arena, ev_view, str8_zero(), expr, &top_level_view_rules); - EV_BlockRangeList block_ranges = ev_block_range_list_from_tree(scratch.arena, &block_tree); - // EV_BlockList viz_blocks = ev_block_list_from_view_expr_keys(scratch.arena, ev_view, str8_zero(), &top_level_view_rules, expr, parent_key, key, 0); - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); - U32 default_radix = (entity->kind == CTRL_EntityKind_Thread ? 16 : 10); - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, ev_view, str8_zero(), &block_ranges, r1u64(0, 50)); - // EV_WindowedRowList viz_rows = ev_windowed_row_list_from_block_list(scratch.arena, ev_view, r1s64(0, 50), &viz_blocks); - - //- rjf: animate - { - // rjf: animate height - { - F32 fish_rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f; - F32 hover_eval_container_height_target = row_height * Min(30, block_tree.total_row_count); - ws->hover_eval_num_visible_rows_t += (hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) * fish_rate; - if(abs_f32(hover_eval_container_height_target - ws->hover_eval_num_visible_rows_t) > 0.5f) - { - rd_request_frame(); - } - else - { - ws->hover_eval_num_visible_rows_t = hover_eval_container_height_target; - } - } - - // rjf: animate open - { - F32 fish_rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-60.f * rd_state->frame_dt)) : 1.f; - F32 diff = 1.f - ws->hover_eval_open_t; - ws->hover_eval_open_t += diff*fish_rate; - if(abs_f32(diff) < 0.01f) - { - ws->hover_eval_open_t = 1.f; - } - else - { - rd_request_frame(); - } - } - } - - //- rjf: calculate width - F32 width_px = 40.f*ui_top_font_size(); - F32 expr_column_width_px = 15.f*ui_top_font_size(); - F32 value_column_width_px = 25.f*ui_top_font_size(); - if(rows.first != 0) - { - EV_Row *row = rows.first; - E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0); - String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); - expr_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_expr_string).x + ui_top_font_size()*10.f; - value_column_width_px = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, 0, row_display_value).x + ui_top_font_size()*5.f; - F32 total_dim_px = (expr_column_width_px + value_column_width_px); - width_px = Min(80.f*ui_top_font_size(), total_dim_px*1.5f); - } - - //- rjf: build hover eval box - F32 hover_eval_container_height = ws->hover_eval_num_visible_rows_t; - F32 corner_radius = ui_top_font_size()*0.25f; - ui_set_next_fixed_x(ws->hover_eval_spawn_pos.x); - ui_set_next_fixed_y(ws->hover_eval_spawn_pos.y); - ui_set_next_pref_width(ui_px(width_px, 1.f)); - ui_set_next_pref_height(ui_px(hover_eval_container_height, 1.f)); - ui_set_next_corner_radius_00(0); - ui_set_next_corner_radius_01(corner_radius); - ui_set_next_corner_radius_10(corner_radius); - ui_set_next_corner_radius_11(corner_radius); - ui_set_next_child_layout_axis(Axis2_Y); - ui_set_next_squish(0.25f-0.25f*ws->hover_eval_open_t); - ui_set_next_transparency(1.f-ws->hover_eval_open_t); - UI_Focus(UI_FocusKind_On) - { - hover_eval_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBackgroundBlur| - UI_BoxFlag_DrawDropShadow| - UI_BoxFlag_DisableFocusOverlay| - UI_BoxFlag_Clip| - UI_BoxFlag_AllowOverflowY| - UI_BoxFlag_ViewScroll| - UI_BoxFlag_ViewClamp| - UI_BoxFlag_Floating| - UI_BoxFlag_AnimatePos| - UI_BoxFlag_Clickable| - UI_BoxFlag_DefaultFocusNav, - "###hover_eval"); - } - - //- rjf: build contents - UI_Parent(hover_eval_box) UI_PrefHeight(ui_px(row_height, 1.f)) - { - //- rjf: build rows - for(EV_Row *row = rows.first; row != 0; row = row->next) - { - //- rjf: unpack row - U64 row_depth = ev_depth_from_block(row->block); - E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - String8 row_expr_string = ev_expr_string_from_row(scratch.arena, row, 0); - String8 row_edit_value = rd_value_string_from_eval(scratch.arena, 0, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); - String8 row_display_value = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), 500.f, row_eval, row->member, row->view_rules); - B32 row_is_editable = ev_row_is_editable(row); - B32 row_is_expandable = ev_row_is_expandable(row); - - //- rjf: determine if row's data is fresh and/or bad - B32 row_is_fresh = 0; - B32 row_is_bad = 0; - switch(row_eval.mode) - { - default:{}break; - case E_Mode_Offset: - { - CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row_eval.space); - if(space_entity->kind == CTRL_EntityKind_Process) - { - U64 size = e_type_byte_size_from_key(row_eval.type_key); - size = Min(size, 64); - Rng1U64 vaddr_rng = r1u64(row_eval.value.u64, row_eval.value.u64+size); - CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, space_entity->handle, vaddr_rng, 0); - for(U64 idx = 0; idx < (slice.data.size+63)/64; idx += 1) - { - if(slice.byte_changed_flags[idx] != 0) - { - row_is_fresh = 1; - } - if(slice.byte_bad_flags[idx] != 0) - { - row_is_bad = 1; - } - } - } - }break; - } - - //- rjf: build row - UI_WidthFill UI_Row - { - ui_spacer(ui_em(0.5f, 1.f)); - if(row_depth > 0) - { - for(U64 indent = 0; indent < row_depth; indent += 1) - { - ui_spacer(ui_em(0.5f, 1.f)); - UI_Flags(UI_BoxFlag_DrawSideLeft) ui_spacer(ui_em(1.f, 1.f)); - } - } - U64 row_hash = ev_hash_from_key(row->key); - B32 row_is_expanded = ev_expansion_from_key(ev_view, row->key); - if(row_is_expandable) - UI_PrefWidth(ui_em(1.f, 1)) - if(ui_pressed(ui_expanderf(row->block->rows_default_expanded ? !row_is_expanded : row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_id))) - { - ev_key_set_expansion(ev_view, row->block->key, row->key, !row_is_expanded); - } - if(!row_is_expandable) - { - UI_PrefWidth(ui_em(1.f, 1)) - UI_Flags(UI_BoxFlag_DrawTextWeak) - RD_Font(RD_FontSlot_Icons) - ui_label(rd_icon_kind_text_table[RD_IconKind_Dot]); - } - UI_WidthFill UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Code)) - { - UI_PrefWidth(ui_px(expr_column_width_px, 1.f)) rd_code_label(1.f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), row_expr_string); - ui_spacer(ui_em(1.5f, 1.f)); - if(row_is_editable) - { - if(row_is_fresh) - { - Vec4F32 rgba = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = rgba)); - } - UI_Signal sig = rd_line_editf(RD_LineEditFlag_CodeContents| - RD_LineEditFlag_DisplayStringIsCode| - RD_LineEditFlag_PreferDisplayString| - RD_LineEditFlag_Border, - 0, 0, &ws->hover_eval_txt_cursor, &ws->hover_eval_txt_mark, ws->hover_eval_txt_buffer, sizeof(ws->hover_eval_txt_buffer), &ws->hover_eval_txt_size, 0, row_edit_value, "%S###val_%I64x", row_display_value, row_hash); - if(ui_pressed(sig)) - { - ws->hover_eval_focused = 1; - } - if(ui_committed(sig)) - { - String8 commit_string = str8(ws->hover_eval_txt_buffer, ws->hover_eval_txt_size); - B32 success = rd_commit_eval_value_string(row_eval, commit_string, 1); - if(success == 0) - { - log_user_error(str8_lit("Could not commit value successfully.")); - } - } - } - else - { - if(row_is_fresh) - { - Vec4F32 rgba = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = rgba)); - ui_set_next_flags(UI_BoxFlag_DrawBackground); - } - rd_code_label(1.f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), row_display_value); - } - } - if(row == rows.first) - { - UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f)) - UI_CornerRadius00(0) - UI_CornerRadius01(0) - UI_CornerRadius10(0) - UI_CornerRadius11(0) - { - UI_Signal watch_sig = rd_icon_buttonf(RD_IconKind_List, 0, "###watch_hover_eval"); - if(ui_hovering(watch_sig)) UI_Tooltip RD_Font(RD_FontSlot_Main) UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - { - ui_labelf("Add the hovered expression to an opened watch view."); - } - if(ui_clicked(watch_sig)) - { - rd_cmd(RD_CmdKind_ToggleWatchExpression, .string = expr); - } - } - if(ws->hover_eval_file_path.size != 0 || ws->hover_eval_vaddr != 0) - UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_em(3.f, 1.f)) - UI_CornerRadius10(corner_radius) - UI_CornerRadius11(corner_radius) - { - UI_Signal pin_sig = rd_icon_buttonf(RD_IconKind_Pin, 0, "###pin_hover_eval"); - if(ui_hovering(pin_sig)) UI_Tooltip RD_Font(RD_FontSlot_Main) UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Main)) - UI_CornerRadius00(0) - UI_CornerRadius01(0) - UI_CornerRadius10(0) - UI_CornerRadius11(0) - { - ui_labelf("Pin the hovered expression to this code location."); - } - if(ui_clicked(pin_sig)) - { - rd_cmd(RD_CmdKind_ToggleWatchPin, - .file_path = ws->hover_eval_file_path, - .cursor = ws->hover_eval_file_pt, - .vaddr = ws->hover_eval_vaddr, - .string = expr); - } - } - } - } - } - UI_PrefWidth(ui_px(0, 0)) ui_spacer(ui_px(hover_eval_container_height-row_height, 1.f)); - } - - //- rjf: interact - { - UI_Signal hover_eval_sig = ui_signal_from_box(hover_eval_box); - if(ui_mouse_over(hover_eval_sig)) - { - ws->hover_eval_last_frame_idx = rd_state->frame_index; - } - else if(ws->hover_eval_last_frame_idx+2 < rd_state->frame_index) - { - rd_request_frame(); - } - if(ui_pressed(hover_eval_sig)) - { - ws->hover_eval_focused = 1; - } - } - } - - di_scope_close(scope); - scratch_end(scratch); - } - } - - //////////////////////////// - //- rjf: panel non-leaf UI (drag boundaries, drag/drop sites) + //- rjf: @window_ui_part panel non-leaf UI (drag boundaries, drag/drop sites) // B32 is_changing_panel_boundaries = 0; ProfScope("non-leaf panel UI") - for(RD_Panel *panel = ws->root_panel; - !rd_panel_is_nil(panel); - panel = rd_panel_rec_depth_first_pre(panel).next) + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { ////////////////////////// //- rjf: continue on leaf panels // - if(rd_panel_is_nil(panel->first)) + if(panel->first == &rd_nil_panel_node) { continue; } @@ -6827,14 +8192,14 @@ rd_window_frame(RD_Window *ws) //- rjf: grab info // Axis2 split_axis = panel->split_axis; - Rng2F32 panel_rect = rd_target_rect_from_panel(content_rect, ws->root_panel, panel); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); ////////////////////////// //- rjf: boundary tab-drag/drop sites // { - RD_View *drag_view = rd_view_from_handle(rd_state->drag_drop_regs->view); - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && !rd_view_is_nil(drag_view)) + RD_Cfg *drag_view = rd_cfg_from_id(rd_state->drag_drop_regs->view); + if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && drag_view != &rd_nil_cfg) { //- rjf: params F32 drop_site_major_dim_px = ceil_f32(ui_top_font_size()*7.f); @@ -6846,10 +8211,10 @@ rd_window_frame(RD_Window *ws) // // (this does not naturally follow from the below algorithm, since the // root level panel only splits on X) - if(panel == ws->root_panel) UI_CornerRadius(corner_radius) + if(panel == panel_tree.root) UI_CornerRadius(corner_radius) { Vec2F32 panel_rect_center = center_2f32(panel_rect); - Axis2 axis = axis2_flip(ws->root_panel->split_axis); + Axis2 axis = axis2_flip(panel_tree.root->split_axis); for EachEnumVal(Side, side) { UI_Key key = ui_key_from_stringf(ui_key_zero(), "root_extra_split_%i", side); @@ -6862,9 +8227,10 @@ rd_window_frame(RD_Window *ws) // rjf: build UI_Box *site_box = &ui_nil_box; { - UI_Rect(site_rect) + F32 site_open_t = ui_anim(ui_key_from_stringf(key, "open_t"), 1.f, .rate = rd_state->menu_animation_rate); + UI_Rect(site_rect) UI_Squish(0.1f-0.1f*site_open_t) UI_Transparency(1-site_open_t) { - site_box = ui_build_box_from_key(UI_BoxFlag_DropSite, key); + site_box = ui_build_box_from_key(UI_BoxFlag_DropSite|UI_BoxFlag_DrawHotEffects, key); ui_signal_from_box(site_box); } UI_Box *site_box_viz = &ui_nil_box; @@ -6872,16 +8238,14 @@ rd_window_frame(RD_Window *ws) UI_Padding(ui_px(padding, 1.f)) UI_Column UI_Padding(ui_px(padding, 1.f)) + UI_GroupKey(key) { ui_set_next_child_layout_axis(axis2_flip(axis)); - if(ui_key_match(key, ui_drop_hot_key())) - { - ui_set_next_palette(ui_build_palette(ui_top_palette(), .border = rd_rgba_from_theme_color(RD_ThemeColor_Hover))); - } site_box_viz = ui_build_box_from_key(UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawDropShadow| - UI_BoxFlag_DrawBackgroundBlur, ui_key_zero()); + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawHotEffects, ui_key_zero()); } UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) { @@ -6898,14 +8262,23 @@ rd_window_frame(RD_Window *ws) // rjf: viz if(ui_key_match(site_box->key, ui_drop_hot_key())) { - Rng2F32 future_split_rect = site_rect; - future_split_rect.p0.v[axis] -= drop_site_major_dim_px; - future_split_rect.p1.v[axis] += drop_site_major_dim_px; - future_split_rect.p0.v[axis2_flip(axis)] = panel_rect.p0.v[axis2_flip(axis)]; - future_split_rect.p1.v[axis2_flip(axis)] = panel_rect.p1.v[axis2_flip(axis)]; - UI_Rect(future_split_rect) RD_Palette(RD_PaletteCode_DropSiteOverlay) + Rng2F32 future_split_rect_target = site_rect; + future_split_rect_target.p0.v[axis] -= drop_site_major_dim_px; + future_split_rect_target.p1.v[axis] += drop_site_major_dim_px; + future_split_rect_target.p0.v[axis2_flip(axis)] = panel_rect.p0.v[axis2_flip(axis)]; + future_split_rect_target.p1.v[axis2_flip(axis)] = panel_rect.p1.v[axis2_flip(axis)]; + future_split_rect_target = pad_2f32(future_split_rect_target, -ui_top_font_size()*2.f); + Vec2F32 future_split_rect_target_center = center_2f32(future_split_rect_target); + Rng2F32 future_split_rect = { - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v0"), future_split_rect_target.x0, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v1"), future_split_rect_target.y0, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v2"), future_split_rect_target.x1, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v3"), future_split_rect_target.y1, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + }; + UI_Rect(future_split_rect) UI_TagF("drop_site") UI_CornerRadius(ui_top_font_size()*2.f) + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); } } @@ -6917,11 +8290,11 @@ rd_window_frame(RD_Window *ws) Dir2_Invalid); if(dir != Dir2_Invalid) { - RD_Panel *split_panel = panel; + RD_PanelNode *split_panel = panel; rd_cmd(RD_CmdKind_SplitPanel, - .dst_panel = rd_handle_from_panel(split_panel), + .dst_panel = split_panel->cfg->id, .panel = rd_state->drag_drop_regs->panel, - .view = rd_state->drag_drop_regs->view, + .view = rd_state->drag_drop_regs->view, .dir2 = dir); } } @@ -6930,12 +8303,12 @@ rd_window_frame(RD_Window *ws) //- rjf: iterate all children, build boundary drop sites Axis2 split_axis = panel->split_axis; - UI_CornerRadius(corner_radius) for(RD_Panel *child = panel->first;; child = child->next) + UI_CornerRadius(corner_radius) for(RD_PanelNode *child = panel->first;; child = child->next) { // rjf: form rect - Rng2F32 child_rect = rd_target_rect_from_panel_child(panel_rect, panel, child); + Rng2F32 child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, child); Vec2F32 child_rect_center = center_2f32(child_rect); - UI_Key key = ui_key_from_stringf(ui_key_zero(), "drop_boundary_%p_%p", panel, child); + UI_Key key = ui_key_from_stringf(ui_key_zero(), "drop_boundary_%p_%p", panel->cfg, child->cfg); Rng2F32 site_rect = r2f32(child_rect_center, child_rect_center); site_rect.p0.v[split_axis] = child_rect.p0.v[split_axis] - drop_site_minor_dim_px/2; site_rect.p1.v[split_axis] = child_rect.p0.v[split_axis] + drop_site_minor_dim_px/2; @@ -6945,9 +8318,10 @@ rd_window_frame(RD_Window *ws) // rjf: build UI_Box *site_box = &ui_nil_box; { - UI_Rect(site_rect) + F32 site_open_t = ui_anim(ui_key_from_stringf(key, "open_t"), 1.f, .rate = rd_state->menu_animation_rate); + UI_Rect(site_rect) UI_Squish(0.1f-0.1f*site_open_t) UI_Transparency(1-site_open_t) { - site_box = ui_build_box_from_key(UI_BoxFlag_DropSite, key); + site_box = ui_build_box_from_key(UI_BoxFlag_DropSite|UI_BoxFlag_DrawHotEffects, key); ui_signal_from_box(site_box); } UI_Box *site_box_viz = &ui_nil_box; @@ -6955,16 +8329,14 @@ rd_window_frame(RD_Window *ws) UI_Padding(ui_px(padding, 1.f)) UI_Column UI_Padding(ui_px(padding, 1.f)) + UI_GroupKey(key) { ui_set_next_child_layout_axis(axis2_flip(split_axis)); - if(ui_key_match(key, ui_drop_hot_key())) - { - ui_set_next_palette(ui_build_palette(ui_top_palette(), .border = rd_rgba_from_theme_color(RD_ThemeColor_Hover))); - } site_box_viz = ui_build_box_from_key(UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawDropShadow| - UI_BoxFlag_DrawBackgroundBlur, ui_key_zero()); + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawHotEffects, ui_key_zero()); } UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) { @@ -6981,14 +8353,23 @@ rd_window_frame(RD_Window *ws) // rjf: viz if(ui_key_match(site_box->key, ui_drop_hot_key())) { - Rng2F32 future_split_rect = site_rect; - future_split_rect.p0.v[split_axis] -= drop_site_major_dim_px; - future_split_rect.p1.v[split_axis] += drop_site_major_dim_px; - future_split_rect.p0.v[axis2_flip(split_axis)] = child_rect.p0.v[axis2_flip(split_axis)]; - future_split_rect.p1.v[axis2_flip(split_axis)] = child_rect.p1.v[axis2_flip(split_axis)]; - UI_Rect(future_split_rect) RD_Palette(RD_PaletteCode_DropSiteOverlay) + Rng2F32 future_split_rect_target = site_rect; + future_split_rect_target.p0.v[split_axis] -= drop_site_major_dim_px; + future_split_rect_target.p1.v[split_axis] += drop_site_major_dim_px; + future_split_rect_target.p0.v[axis2_flip(split_axis)] = child_rect.p0.v[axis2_flip(split_axis)]; + future_split_rect_target.p1.v[axis2_flip(split_axis)] = child_rect.p1.v[axis2_flip(split_axis)]; + future_split_rect_target = pad_2f32(future_split_rect_target, -ui_top_font_size()*2.f); + Vec2F32 future_split_rect_target_center = center_2f32(future_split_rect_target); + Rng2F32 future_split_rect = { - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v0"), future_split_rect_target.x0, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v1"), future_split_rect_target.y0, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v2"), future_split_rect_target.x1, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v3"), future_split_rect_target.y1, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + }; + UI_Rect(future_split_rect) UI_TagF("drop_site") UI_CornerRadius(ui_top_font_size()*2.f) + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); } } @@ -6996,21 +8377,21 @@ rd_window_frame(RD_Window *ws) if(ui_key_match(site_box->key, ui_drop_hot_key()) && rd_drag_drop()) { Dir2 dir = (panel->split_axis == Axis2_X ? Dir2_Left : Dir2_Up); - RD_Panel *split_panel = child; - if(rd_panel_is_nil(split_panel)) + RD_PanelNode *split_panel = child; + if(split_panel == &rd_nil_panel_node) { split_panel = panel->last; dir = (panel->split_axis == Axis2_X ? Dir2_Right : Dir2_Down); } rd_cmd(RD_CmdKind_SplitPanel, - .dst_panel = rd_handle_from_panel(split_panel), + .dst_panel = split_panel->cfg->id, .panel = rd_state->drag_drop_regs->panel, - .view = rd_state->drag_drop_regs->view, + .view = rd_state->drag_drop_regs->view, .dir2 = dir); } // rjf: exit on opl child - if(rd_panel_is_nil(child)) + if(child == &rd_nil_panel_node) { break; } @@ -7021,12 +8402,14 @@ rd_window_frame(RD_Window *ws) ////////////////////////// //- rjf: do UI for drag boundaries between all children // - for(RD_Panel *child = panel->first; !rd_panel_is_nil(child) && !rd_panel_is_nil(child->next); child = child->next) + for(RD_PanelNode *child = panel->first; + child != &rd_nil_panel_node && child->next != &rd_nil_panel_node; + child = child->next) { - RD_Panel *min_child = child; - RD_Panel *max_child = min_child->next; - Rng2F32 min_child_rect = rd_target_rect_from_panel_child(panel_rect, panel, min_child); - Rng2F32 max_child_rect = rd_target_rect_from_panel_child(panel_rect, panel, max_child); + RD_PanelNode *min_child = child; + RD_PanelNode *max_child = min_child->next; + Rng2F32 min_child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, min_child); + Rng2F32 max_child_rect = rd_target_rect_from_panel_node_child(panel_rect, panel, max_child); Rng2F32 boundary_rect = {0}; { boundary_rect.p0.v[split_axis] = min_child_rect.p1.v[split_axis] - ui_top_font_size()/3; @@ -7038,7 +8421,7 @@ rd_window_frame(RD_Window *ws) UI_Rect(boundary_rect) { ui_set_next_hover_cursor(split_axis == Axis2_X ? OS_Cursor_LeftRight : OS_Cursor_UpDown); - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%p_%p", min_child, max_child); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###%p_%p", min_child->cfg, max_child->cfg); UI_Signal sig = ui_signal_from_box(box); if(ui_double_clicked(sig)) { @@ -7046,6 +8429,8 @@ rd_window_frame(RD_Window *ws) F32 sum_pct = min_child->pct_of_parent + max_child->pct_of_parent; min_child->pct_of_parent = 0.5f * sum_pct; max_child->pct_of_parent = 0.5f * sum_pct; + rd_cfg_equip_stringf(min_child->cfg, "%f", min_child->pct_of_parent); + rd_cfg_equip_stringf(max_child->cfg, "%f", max_child->pct_of_parent); } else if(ui_pressed(sig)) { @@ -7078,6 +8463,8 @@ rd_window_frame(RD_Window *ws) } min_child->pct_of_parent = min_pct__after; max_child->pct_of_parent = max_pct__after; + rd_cfg_equip_stringf(min_child->cfg, "%f", min_pct__after); + rd_cfg_equip_stringf(max_child->cfg, "%f", max_pct__after); is_changing_panel_boundaries = 1; } } @@ -7085,492 +8472,490 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: animate panels + //- rjf: @window_ui_part animate panels // { - F32 rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-50.f * rd_state->frame_dt)) : 1.f; + B32 window_is_resizing = (ws->last_window_rect.x1 != window_rect.x1 || + ws->last_window_rect.y1 != window_rect.y1); Vec2F32 content_rect_dim = dim_2f32(content_rect); if(content_rect_dim.x > 0 && content_rect_dim.y > 0) { - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - Rng2F32 target_rect_px = rd_target_rect_from_panel(content_rect, ws->root_panel, panel); + Rng2F32 target_rect_px = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); Rng2F32 target_rect_pct = r2f32p(target_rect_px.x0/content_rect_dim.x, target_rect_px.y0/content_rect_dim.y, target_rect_px.x1/content_rect_dim.x, target_rect_px.y1/content_rect_dim.y); - if(abs_f32(target_rect_pct.x0 - panel->animated_rect_pct.x0) > 0.005f || - abs_f32(target_rect_pct.y0 - panel->animated_rect_pct.y0) > 0.005f || - abs_f32(target_rect_pct.x1 - panel->animated_rect_pct.x1) > 0.005f || - abs_f32(target_rect_pct.y1 - panel->animated_rect_pct.y1) > 0.005f) - { - rd_request_frame(); - } - panel->animated_rect_pct.x0 += rate * (target_rect_pct.x0 - panel->animated_rect_pct.x0); - panel->animated_rect_pct.y0 += rate * (target_rect_pct.y0 - panel->animated_rect_pct.y0); - panel->animated_rect_pct.x1 += rate * (target_rect_pct.x1 - panel->animated_rect_pct.x1); - panel->animated_rect_pct.y1 += rate * (target_rect_pct.y1 - panel->animated_rect_pct.y1); - if(ws->frames_alive < 5 || is_changing_panel_boundaries) - { - panel->animated_rect_pct = target_rect_pct; - } + B32 reset = (window_is_resizing || ws->window_layout_reset || ws->frames_alive < 5 || is_changing_panel_boundaries); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x0", panel->cfg), target_rect_pct.x0, .initial = target_rect_pct.x0, .reset = reset, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y0", panel->cfg), target_rect_pct.y0, .initial = target_rect_pct.y0, .reset = reset, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x1", panel->cfg), target_rect_pct.x1, .initial = target_rect_pct.x1, .reset = reset, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y1", panel->cfg), target_rect_pct.y1, .initial = target_rect_pct.y1, .reset = reset, .rate = rd_state->menu_animation_rate); } } + ws->window_layout_reset = 0; } //////////////////////////// - //- rjf: panel leaf UI + //- rjf: @window_ui_part panel leaf UI // - ProfScope("leaf panel UI") - for(RD_Panel *panel = ws->root_panel; - !rd_panel_is_nil(panel); - panel = rd_panel_rec_depth_first_pre(panel).next) + if(content_rect.x1 > content_rect.x0 && content_rect.y1 > content_rect.y0) { - if(!rd_panel_is_nil(panel->first)) {continue;} - B32 panel_is_focused = (window_is_focused && - !ws->menu_bar_focused && - (!query_is_open || !ws->query_view_selected) && - !ui_any_ctx_menu_is_open() && - !ws->hover_eval_focused && - ws->focused_panel == panel); - UI_Focus(panel_is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) + ProfScope("leaf panel UI") + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - ////////////////////////// - //- rjf: calculate UI rectangles - // - Vec2F32 content_rect_dim = dim_2f32(content_rect); - Rng2F32 panel_rect_pct = panel->animated_rect_pct; - Rng2F32 panel_rect = r2f32p(panel_rect_pct.x0*content_rect_dim.x, - panel_rect_pct.y0*content_rect_dim.y, - panel_rect_pct.x1*content_rect_dim.x, - panel_rect_pct.y1*content_rect_dim.y); - panel_rect = pad_2f32(panel_rect, -1.f); - F32 tab_bar_rheight = ui_top_font_size()*3.f; - F32 tab_bar_vheight = ui_top_font_size()*2.6f; - F32 tab_bar_rv_diff = tab_bar_rheight - tab_bar_vheight; - F32 tab_spacing = ui_top_font_size()*0.4f; - F32 filter_bar_height = ui_top_font_size()*3.f; - Rng2F32 tab_bar_rect = r2f32p(panel_rect.x0, panel_rect.y0, panel_rect.x1, panel_rect.y0 + tab_bar_vheight); - Rng2F32 content_rect = r2f32p(panel_rect.x0, panel_rect.y0+tab_bar_vheight, panel_rect.x1, panel_rect.y1); - Rng2F32 filter_rect = {0}; - if(panel->tab_side == Side_Max) + if(panel->first != &rd_nil_panel_node) {continue;} + B32 panel_is_focused = (window_is_focused && + !ws->menu_bar_focused && + !query_is_open && + !ui_any_ctx_menu_is_open() && + !ws->hover_eval_focused && + panel_tree.focused == panel); + RD_Cfg *selected_tab = panel->selected_tab; + RD_ViewState *selected_tab_view_state = rd_view_state_from_cfg(selected_tab); + ProfScope("leaf panel UI work - %.*s: %.*s", str8_varg(selected_tab->string), str8_varg(rd_expr_from_cfg(selected_tab))) + UI_Focus(panel_is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) { - tab_bar_rect.y0 = panel_rect.y1 - tab_bar_vheight; - tab_bar_rect.y1 = panel_rect.y1; - content_rect.y0 = panel_rect.y0; - content_rect.y1 = panel_rect.y1 - tab_bar_vheight; - } - { - RD_View *tab = rd_selected_tab_from_panel(panel); - if(tab->is_filtering_t > 0.01f) + ////////////////////////// + //- rjf: calculate UI rectangles + // + Vec2F32 content_rect_dim = dim_2f32(content_rect); + Rng2F32 target_rect_px = rd_target_rect_from_panel_node(content_rect, panel_tree.root, panel); + Rng2F32 target_rect_pct = r2f32p(target_rect_px.x0 / content_rect_dim.x, + target_rect_px.y0 / content_rect_dim.y, + target_rect_px.x1 / content_rect_dim.x, + target_rect_px.y1 / content_rect_dim.y); + Rng2F32 panel_rect_pct = r2f32p(ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x0", panel->cfg), target_rect_pct.x0, .initial = target_rect_pct.x0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y0", panel->cfg), target_rect_pct.y0, .initial = target_rect_pct.y0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x1", panel->cfg), target_rect_pct.x1, .initial = target_rect_pct.x1, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y1", panel->cfg), target_rect_pct.y1, .initial = target_rect_pct.y1, .rate = rd_state->menu_animation_rate)); + Rng2F32 panel_rect = r2f32p(panel_rect_pct.x0*content_rect_dim.x, + panel_rect_pct.y0*content_rect_dim.y, + panel_rect_pct.x1*content_rect_dim.x, + panel_rect_pct.y1*content_rect_dim.y); + panel_rect = pad_2f32(panel_rect, floor_f32(-ui_top_font_size()*0.15f)); + F32 tab_bar_rheight = floor_f32(ui_top_font_size()*3.5f); + F32 tab_bar_vheight = floor_f32(ui_top_font_size()*rd_setting_f32_from_name(str8_lit("tab_height"))); + F32 tab_bar_rv_diff = tab_bar_rheight - tab_bar_vheight; + F32 tab_spacing = floor_f32(ui_top_font_size()*0.4f); + Rng2F32 tab_bar_rect = r2f32p(panel_rect.x0, panel_rect.y0, panel_rect.x1, panel_rect.y0 + tab_bar_vheight); + Rng2F32 content_rect = r2f32p(panel_rect.x0, panel_rect.y0+tab_bar_vheight, panel_rect.x1, panel_rect.y1); + if(panel->tab_side == Side_Max) { - filter_rect.x0 = content_rect.x0; - filter_rect.y0 = content_rect.y0; - filter_rect.x1 = content_rect.x1; - content_rect.y0 += filter_bar_height*tab->is_filtering_t; - filter_rect.y1 = content_rect.y0; + tab_bar_rect.y0 = panel_rect.y1 - tab_bar_vheight; + tab_bar_rect.y1 = panel_rect.y1; + content_rect.y0 = panel_rect.y0; + content_rect.y1 = panel_rect.y1 - tab_bar_vheight; } - } - - ////////////////////////// - //- rjf: build combined split+movetab drag/drop sites - // - { - RD_View *view = rd_view_from_handle(rd_state->drag_drop_regs->view); - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && !rd_view_is_nil(view) && contains_2f32(panel_rect, ui_mouse())) + tab_bar_rect = intersect_2f32(tab_bar_rect, panel_rect); + content_rect = intersect_2f32(content_rect, panel_rect); + + ////////////////////////// + //- rjf: decide to skip this panel (e.g. if it is too small + // + B32 build_panel = (content_rect.x1 > content_rect.x0 && content_rect.y1 > content_rect.y0); + + ////////////////////////// + //- rjf: build combined split+movetab drag/drop sites + // + if(build_panel) { - F32 drop_site_dim_px = ceil_f32(ui_top_font_size()*7.f); - Vec2F32 drop_site_half_dim = v2f32(drop_site_dim_px/2, drop_site_dim_px/2); - Vec2F32 panel_center = center_2f32(panel_rect); - F32 corner_radius = ui_top_font_size()*0.5f; - F32 padding = ceil_f32(ui_top_font_size()*0.5f); - struct - { - UI_Key key; - Dir2 split_dir; - Rng2F32 rect; - } - sites[] = + RD_Cfg *view = rd_cfg_from_id(rd_state->drag_drop_regs->view); + if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && view != &rd_nil_cfg && contains_2f32(panel_rect, ui_mouse()) && ui_key_match(ui_drop_hot_key(), ui_key_zero())) { + F32 drop_site_dim_px = ceil_f32(ui_top_font_size()*7.f); + drop_site_dim_px = Min(drop_site_dim_px, dim_2f32(panel_rect).v[panel->split_axis]/4.f); + drop_site_dim_px = Max(drop_site_dim_px, ceil_f32(ui_top_font_size()*3.f)); + Vec2F32 drop_site_half_dim = v2f32(drop_site_dim_px/2, drop_site_dim_px/2); + Vec2F32 panel_center = center_2f32(panel_rect); + F32 corner_radius = ui_top_font_size()*0.5f; + F32 padding = ceil_f32(ui_top_font_size()*0.5f); + struct { - ui_key_from_stringf(ui_key_zero(), "drop_split_center_%p", panel), - Dir2_Invalid, - r2f32(sub_2f32(panel_center, drop_site_half_dim), - add_2f32(panel_center, drop_site_half_dim)) - }, + UI_Key key; + Dir2 split_dir; + Rng2F32 rect; + } + sites[] = { - ui_key_from_stringf(ui_key_zero(), "drop_split_up_%p", panel), - Dir2_Up, - r2f32p(panel_center.x-drop_site_half_dim.x, - panel_center.y-drop_site_half_dim.y - drop_site_half_dim.y*2, - panel_center.x+drop_site_half_dim.x, - panel_center.y+drop_site_half_dim.y - drop_site_half_dim.y*2), - }, + { + ui_key_from_stringf(ui_key_zero(), "drop_split_center_%p", panel->cfg), + Dir2_Invalid, + r2f32(sub_2f32(panel_center, drop_site_half_dim), + add_2f32(panel_center, drop_site_half_dim)) + }, + { + ui_key_from_stringf(ui_key_zero(), "drop_split_up_%p", panel->cfg), + Dir2_Up, + r2f32p(panel_center.x-drop_site_half_dim.x, + panel_center.y-drop_site_half_dim.y - drop_site_half_dim.y*2, + panel_center.x+drop_site_half_dim.x, + panel_center.y+drop_site_half_dim.y - drop_site_half_dim.y*2), + }, + { + ui_key_from_stringf(ui_key_zero(), "drop_split_down_%p", panel->cfg), + Dir2_Down, + r2f32p(panel_center.x-drop_site_half_dim.x, + panel_center.y-drop_site_half_dim.y + drop_site_half_dim.y*2, + panel_center.x+drop_site_half_dim.x, + panel_center.y+drop_site_half_dim.y + drop_site_half_dim.y*2), + }, + { + ui_key_from_stringf(ui_key_zero(), "drop_split_left_%p", panel->cfg), + Dir2_Left, + r2f32p(panel_center.x-drop_site_half_dim.x - drop_site_half_dim.x*2, + panel_center.y-drop_site_half_dim.y, + panel_center.x+drop_site_half_dim.x - drop_site_half_dim.x*2, + panel_center.y+drop_site_half_dim.y), + }, + { + ui_key_from_stringf(ui_key_zero(), "drop_split_right_%p", panel->cfg), + Dir2_Right, + r2f32p(panel_center.x-drop_site_half_dim.x + drop_site_half_dim.x*2, + panel_center.y-drop_site_half_dim.y, + panel_center.x+drop_site_half_dim.x + drop_site_half_dim.x*2, + panel_center.y+drop_site_half_dim.y), + }, + }; + UI_CornerRadius(corner_radius) + for(U64 idx = 0; idx < ArrayCount(sites); idx += 1) { - ui_key_from_stringf(ui_key_zero(), "drop_split_down_%p", panel), - Dir2_Down, - r2f32p(panel_center.x-drop_site_half_dim.x, - panel_center.y-drop_site_half_dim.y + drop_site_half_dim.y*2, - panel_center.x+drop_site_half_dim.x, - panel_center.y+drop_site_half_dim.y + drop_site_half_dim.y*2), - }, - { - ui_key_from_stringf(ui_key_zero(), "drop_split_left_%p", panel), - Dir2_Left, - r2f32p(panel_center.x-drop_site_half_dim.x - drop_site_half_dim.x*2, - panel_center.y-drop_site_half_dim.y, - panel_center.x+drop_site_half_dim.x - drop_site_half_dim.x*2, - panel_center.y+drop_site_half_dim.y), - }, - { - ui_key_from_stringf(ui_key_zero(), "drop_split_right_%p", panel), - Dir2_Right, - r2f32p(panel_center.x-drop_site_half_dim.x + drop_site_half_dim.x*2, - panel_center.y-drop_site_half_dim.y, - panel_center.x+drop_site_half_dim.x + drop_site_half_dim.x*2, - panel_center.y+drop_site_half_dim.y), - }, - }; - UI_CornerRadius(corner_radius) + UI_Key key = sites[idx].key; + Dir2 dir = sites[idx].split_dir; + Rng2F32 rect = sites[idx].rect; + Axis2 split_axis = axis2_from_dir2(dir); + Side split_side = side_from_dir2(dir); + if(dir != Dir2_Invalid && split_axis == panel->parent->split_axis) + { + continue; + } + UI_Box *site_box = &ui_nil_box; + { + F32 site_open_t = ui_anim(ui_key_from_stringf(key, "open_t"), 1.f, .rate = rd_state->menu_animation_rate); + UI_Rect(rect) UI_Squish(0.1f-0.1f*site_open_t) UI_Transparency(1-site_open_t) + { + site_box = ui_build_box_from_key(UI_BoxFlag_DropSite|UI_BoxFlag_DrawHotEffects, key); + ui_signal_from_box(site_box); + } + UI_Box *site_box_viz = &ui_nil_box; + UI_GroupKey(key) + UI_Parent(site_box) UI_WidthFill UI_HeightFill + UI_Padding(ui_px(padding, 1.f)) + UI_Column + UI_Padding(ui_px(padding, 1.f)) + { + ui_set_next_child_layout_axis(axis2_flip(split_axis)); + site_box_viz = ui_build_box_from_key(UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_DrawHotEffects, ui_key_zero()); + } + if(dir != Dir2_Invalid) + { + UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) + { + ui_set_next_child_layout_axis(split_axis); + UI_Box *row_or_column = ui_build_box_from_key(0, ui_key_zero()); + UI_Parent(row_or_column) UI_Padding(ui_px(padding, 1.f)) UI_TagF("drop_site") + { + if(split_side == Side_Min) { ui_set_next_flags(UI_BoxFlag_DrawBackground); } + ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); + ui_spacer(ui_px(padding, 1.f)); + if(split_side == Side_Max) { ui_set_next_flags(UI_BoxFlag_DrawBackground); } + ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); + } + } + } + else + { + UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) + { + ui_set_next_child_layout_axis(split_axis); + UI_Box *row_or_column = ui_build_box_from_key(0, ui_key_zero()); + UI_Parent(row_or_column) UI_Padding(ui_px(padding, 1.f)) UI_TagF("drop_site") + { + ui_build_box_from_key(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, ui_key_zero()); + } + } + } + } + if(ui_key_match(site_box->key, ui_drop_hot_key()) && rd_drag_drop()) + { + if(dir != Dir2_Invalid) + { + rd_cmd(RD_CmdKind_SplitPanel, + .dst_panel = panel->cfg->id, + .panel = rd_state->drag_drop_regs->panel, + .view = rd_state->drag_drop_regs->view, + .dir2 = dir); + } + else + { + rd_cmd(RD_CmdKind_MoveView, + .dst_panel = panel->cfg->id, + .panel = rd_state->drag_drop_regs->panel, + .view = rd_state->drag_drop_regs->view, + .prev_tab = rd_cfg_list_last(&panel->tabs)->id); + } + } + } for(U64 idx = 0; idx < ArrayCount(sites); idx += 1) + { + B32 is_drop_hot = ui_key_match(ui_drop_hot_key(), sites[idx].key); + if(is_drop_hot) + { + Axis2 split_axis = axis2_from_dir2(sites[idx].split_dir); + Side split_side = side_from_dir2(sites[idx].split_dir); + Rng2F32 future_split_rect_target = panel_rect; + if(sites[idx].split_dir != Dir2_Invalid) + { + Vec2F32 panel_center = center_2f32(panel_rect); + future_split_rect_target.v[side_flip(split_side)].v[split_axis] = panel_center.v[split_axis]; + } + future_split_rect_target = pad_2f32(future_split_rect_target, -ui_top_font_size()*2.f); + Vec2F32 future_split_rect_target_center = center_2f32(future_split_rect_target); + Rng2F32 future_split_rect = + { + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v0"), future_split_rect_target.x0, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v1"), future_split_rect_target.y0, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v2"), future_split_rect_target.x1, .initial = future_split_rect_target_center.x, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "drop_site_v3"), future_split_rect_target.y1, .initial = future_split_rect_target_center.y, .rate = rd_state->menu_animation_rate), + }; + UI_Rect(future_split_rect) UI_TagF("drop_site") UI_CornerRadius(ui_top_font_size()*2.f) + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); + } + } + } + } + } + + ////////////////////////// + //- rjf: build catch-all panel drop-site + // + UI_Key catchall_drop_site_key = ui_key_from_stringf(ui_key_zero(), "catchall_drop_site_%p", panel->cfg); + if(build_panel && rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View) UI_Rect(panel_rect) + { + UI_Box *catchall_drop_site = ui_build_box_from_key(UI_BoxFlag_DropSite, catchall_drop_site_key); + ui_signal_from_box(catchall_drop_site); + } + + ////////////////////////// + //- rjf: panel not selected? -> darken + // + if(build_panel) if(panel != panel_tree.focused) + { + UI_Rect(content_rect) UI_TagF("inactive") + ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); + } + + ////////////////////////// + //- rjf: build panel container box + // + UI_Box *panel_box = &ui_nil_box; + if(build_panel) UI_Rect(content_rect) UI_ChildLayoutAxis(Axis2_Y) UI_CornerRadius(0) UI_Focus(UI_FocusKind_On) + { + UI_Key panel_key = ui_key_from_stringf(ui_key_zero(), "panel_box_%p", panel->cfg); + panel_box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| + UI_BoxFlag_Clip| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DisableFocusOverlay| + ((panel_tree.focused != panel)*UI_BoxFlag_DisableFocusBorder), + panel_key); + } + + ////////////////////////// + //- rjf: loading animation for stable view + // + UI_Box *loading_overlay_container = &ui_nil_box; + if(build_panel) UI_Parent(panel_box) UI_WidthFill UI_HeightFill + { + loading_overlay_container = ui_build_box_from_key(UI_BoxFlag_Floating, ui_key_zero()); + } + + ////////////////////////// + //- rjf: build selected tab view + // + if(build_panel) + UI_Parent(panel_box) + UI_Focus(panel_is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) + UI_WidthFill + { + //- rjf: push interaction registers, fill with per-view states + rd_push_regs(.panel = panel->cfg->id, + .tab = selected_tab->id, + .view = selected_tab->id); { - UI_Key key = sites[idx].key; - Dir2 dir = sites[idx].split_dir; - Rng2F32 rect = sites[idx].rect; - Axis2 split_axis = axis2_from_dir2(dir); - Side split_side = side_from_dir2(dir); - if(dir != Dir2_Invalid && split_axis == panel->parent->split_axis) + String8 view_expr = rd_expr_from_cfg(selected_tab); + String8 view_file_path = rd_file_path_from_eval_string(rd_frame_arena(), view_expr); + // NOTE(rjf): we want to only fill out this view's file path slot if it + // evaluates one - this way, a view can use the slot to know the selected + // file path (if there is one). this is useful when pushing commandas which + // apply to a cursor, for example. + if(view_file_path.size != 0) + { + rd_regs()->file_path = view_file_path; + } + } + + //- rjf: visualizers -> accept expression drops + UI_Box *view_drop_site = &ui_nil_box; + { + RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(selected_tab->string); + if(view_ui_rule != &rd_nil_view_ui_rule && rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_Expr && + !str8_match(selected_tab->string, str8_lit("text"), 0) && + !str8_match(selected_tab->string, str8_lit("disasm"), 0)) + { + UI_FixedSize(dim_2f32(content_rect)) + view_drop_site = ui_build_box_from_stringf(UI_BoxFlag_DropSite|UI_BoxFlag_Floating, "drop_site_%I64x", selected_tab->id); + } + } + + //- rjf: build view container + UI_Box *view_container_box = &ui_nil_box; + UI_FixedWidth(dim_2f32(content_rect).x) + UI_FixedHeight(dim_2f32(content_rect).y) + UI_ChildLayoutAxis(Axis2_Y) + { + view_container_box = ui_build_box_from_key(0, ui_key_zero()); + } + + //- rjf: build empty view + UI_Parent(view_container_box) if(selected_tab == &rd_nil_cfg && panel->parent != &rd_nil_panel_node) + { + ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); + UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) UI_TagF("weak") + UI_Padding(ui_pct(1, 0)) UI_Focus(UI_FocusKind_Null) + { + UI_PrefHeight(ui_em(3.f, 1.f)) + UI_Row + UI_Padding(ui_pct(1, 0)) + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_em(15.f, 1.f)) + UI_CornerRadius(ui_top_font_size()/2.f) + UI_TagF("bad_pop") + { + if(ui_clicked(rd_icon_buttonf(RD_IconKind_X, 0, "Close Panel"))) + { + rd_cmd(RD_CmdKind_ClosePanel); + } + } + } + } + + //- rjf: build tab view + UI_Parent(view_container_box) if(selected_tab != &rd_nil_cfg) ProfScope("build tab view") + { + rd_view_ui(content_rect); + } + + //- rjf: accept expression drops + if(view_drop_site != &ui_nil_box) + { + UI_Signal sig = ui_signal_from_box(view_drop_site); + if(ui_key_match(view_drop_site->key, ui_drop_hot_key())) + { + UI_Parent(view_drop_site) UI_WidthFill UI_HeightFill UI_TagF("drop_site") + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); + } + if(rd_drag_drop()) + { + rd_store_view_expr_string(rd_state->drag_drop_regs->expr); + } + } + } + + //- rjf: pop interaction registers; commit if this is the selected view + RD_Regs *view_regs = rd_pop_regs(); + if(panel_is_focused) + { + MemoryCopyStruct(rd_regs(), view_regs); + } + } + + //////////////////////// + //- rjf: loading? -> fill loading overlay container + // + if(build_panel) + { + F32 selected_tab_loading_t = selected_tab_view_state->loading_t; + if(selected_tab_loading_t > 0.01f) UI_Parent(loading_overlay_container) + { + rd_loading_overlay(panel_rect, selected_tab_loading_t, selected_tab_view_state->loading_progress_v, selected_tab_view_state->loading_progress_v_target); + } + } + + ////////////////////////// + //- rjf: consume panel fallthrough interaction events + // + if(build_panel) + { + UI_Signal panel_sig = ui_signal_from_box(panel_box); + if(ui_pressed(panel_sig)) + { + rd_cmd(RD_CmdKind_FocusPanel, .panel = panel->cfg->id); + } + } + + ////////////////////////// + //- rjf: compute tab build tasks + // + typedef struct TabTask TabTask; + struct TabTask + { + TabTask *next; + RD_Cfg *tab; + DR_FStrList fstrs; + F32 tab_width; + }; + TabTask *first_tab_task = 0; + TabTask *last_tab_task = 0; + U64 tab_task_count = 0; + F32 tab_close_width_px = ui_top_font_size()*2.5f; + F32 max_tab_width_px = ui_top_font_size()*20.f; + if(build_panel) UI_TagF("tab") + { + B32 reset = (ws->window_layout_reset || ws->frames_alive < 5 || is_changing_panel_boundaries); + for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + { + RD_Cfg *tab = n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } - UI_Box *site_box = &ui_nil_box; + UI_TagF(tab != panel->selected_tab ? "inactive" : "") { - UI_Rect(rect) - { - site_box = ui_build_box_from_key(UI_BoxFlag_DropSite, key); - ui_signal_from_box(site_box); - } - UI_Box *site_box_viz = &ui_nil_box; - UI_Parent(site_box) UI_WidthFill UI_HeightFill - UI_Padding(ui_px(padding, 1.f)) - UI_Column - UI_Padding(ui_px(padding, 1.f)) - { - ui_set_next_child_layout_axis(axis2_flip(split_axis)); - if(ui_key_match(key, ui_drop_hot_key())) - { - ui_set_next_palette(ui_build_palette(ui_top_palette(), .border = rd_rgba_from_theme_color(RD_ThemeColor_Hover))); - } - site_box_viz = ui_build_box_from_key(UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawDropShadow| - UI_BoxFlag_DrawBackgroundBlur, ui_key_zero()); - } - if(dir != Dir2_Invalid) - { - UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) - { - ui_set_next_child_layout_axis(split_axis); - UI_Box *row_or_column = ui_build_box_from_key(0, ui_key_zero()); UI_Parent(row_or_column) UI_Padding(ui_px(padding, 1.f)) - { - if(split_side == Side_Min) { ui_set_next_flags(UI_BoxFlag_DrawBackground); } - RD_Palette(RD_PaletteCode_DropSiteOverlay) ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); - ui_spacer(ui_px(padding, 1.f)); - if(split_side == Side_Max) { ui_set_next_flags(UI_BoxFlag_DrawBackground); } - RD_Palette(RD_PaletteCode_DropSiteOverlay) ui_build_box_from_key(UI_BoxFlag_DrawBorder, ui_key_zero()); - } - } - } - else - { - UI_Parent(site_box_viz) UI_WidthFill UI_HeightFill UI_Padding(ui_px(padding, 1.f)) - { - ui_set_next_child_layout_axis(split_axis); - UI_Box *row_or_column = ui_build_box_from_key(0, ui_key_zero()); - UI_Parent(row_or_column) UI_Padding(ui_px(padding, 1.f)) RD_Palette(RD_PaletteCode_DropSiteOverlay) - { - ui_build_box_from_key(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } - } - } - if(ui_key_match(site_box->key, ui_drop_hot_key()) && rd_drag_drop()) - { - if(dir != Dir2_Invalid) - { - rd_cmd(RD_CmdKind_SplitPanel, - .dst_panel = rd_handle_from_panel(panel), - .panel = rd_state->drag_drop_regs->panel, - .view = rd_state->drag_drop_regs->view, - .dir2 = dir); - } - else - { - rd_cmd(RD_CmdKind_MoveTab, - .dst_panel = rd_handle_from_panel(panel), - .panel = rd_state->drag_drop_regs->panel, - .view = rd_state->drag_drop_regs->view, - .prev_view = rd_handle_from_view(panel->last_tab_view)); - } - } - } - for(U64 idx = 0; idx < ArrayCount(sites); idx += 1) - { - B32 is_drop_hot = ui_key_match(ui_drop_hot_key(), sites[idx].key); - if(is_drop_hot) - { - Axis2 split_axis = axis2_from_dir2(sites[idx].split_dir); - Side split_side = side_from_dir2(sites[idx].split_dir); - Rng2F32 future_split_rect = panel_rect; - if(sites[idx].split_dir != Dir2_Invalid) - { - Vec2F32 panel_center = center_2f32(panel_rect); - future_split_rect.v[side_flip(split_side)].v[split_axis] = panel_center.v[split_axis]; - } - UI_Rect(future_split_rect) RD_Palette(RD_PaletteCode_DropSiteOverlay) - { - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } + TabTask *t = push_array(scratch.arena, TabTask, 1); + t->tab = tab; + t->fstrs = rd_title_fstrs_from_cfg(scratch.arena, tab); + F32 tab_width_target = dr_dim_from_fstrs(ui_top_tab_size(), &t->fstrs).x + tab_close_width_px + ui_top_font_size()*1.f; + tab_width_target = Min(max_tab_width_px, tab_width_target); + t->tab_width = floor_f32(ui_anim(ui_key_from_stringf(ui_key_zero(), "tab_width_%p", tab), tab_width_target, .initial = reset ? tab_width_target : 0, .rate = rd_state->menu_animation_rate)); + SLLQueuePush(first_tab_task, last_tab_task, t); + tab_task_count += 1; } } } - } - - ////////////////////////// - //- rjf: build catch-all panel drop-site - // - B32 catchall_drop_site_hovered = 0; - if(rd_drag_is_active() && ui_key_match(ui_key_zero(), ui_drop_hot_key())) - { - UI_Rect(panel_rect) - { - UI_Key key = ui_key_from_stringf(ui_key_zero(), "catchall_drop_site_%p", panel); - UI_Box *catchall_drop_site = ui_build_box_from_key(UI_BoxFlag_DropSite, key); - ui_signal_from_box(catchall_drop_site); - catchall_drop_site_hovered = ui_key_match(key, ui_drop_hot_key()); - } - } - - ////////////////////////// - //- rjf: build filtering box - // - { - RD_View *view = rd_selected_tab_from_panel(panel); - UI_Focus(UI_FocusKind_On) - { - if(view->is_filtering && ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Accept)) - { - rd_cmd(RD_CmdKind_ApplyFilter, .view = rd_handle_from_view(view)); - } - if(view->is_filtering || view->is_filtering_t > 0.01f) - { - UI_Box *filter_box = &ui_nil_box; - UI_Rect(filter_rect) - { - ui_set_next_child_layout_axis(Axis2_X); - filter_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder, "filter_box_%p", view); - } - UI_Parent(filter_box) UI_WidthFill UI_HeightFill - { - UI_PrefWidth(ui_em(3.f, 1.f)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - RD_Font(RD_FontSlot_Icons) - UI_TextAlignment(UI_TextAlign_Center) - ui_label(rd_icon_kind_text_table[RD_IconKind_Find]); - UI_PrefWidth(ui_text_dim(10, 1)) - { - ui_label(str8_lit("Filter")); - } - ui_spacer(ui_em(0.5f, 1.f)); - RD_Font(view->spec->flags & RD_ViewRuleInfoFlag_FilterIsCode ? RD_FontSlot_Code : RD_FontSlot_Main) - UI_Focus(view->is_filtering ? UI_FocusKind_On : UI_FocusKind_Off) - UI_TextPadding(ui_top_font_size()*0.5f) - { - UI_Signal sig = rd_line_edit(RD_LineEditFlag_CodeContents*!!(view->spec->flags & RD_ViewRuleInfoFlag_FilterIsCode), - 0, - 0, - &view->query_cursor, - &view->query_mark, - view->query_buffer, - sizeof(view->query_buffer), - &view->query_string_size, - 0, - str8(view->query_buffer, view->query_string_size), - str8_lit("###filter_text_input")); - if(ui_pressed(sig)) - { - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(panel)); - } - } - } - } - } - } - - ////////////////////////// - //- rjf: panel not selected? -> darken - // - if(panel != ws->focused_panel) - { - UI_Palette(ui_build_palette(0, .background = rd_rgba_from_theme_color(RD_ThemeColor_InactivePanelOverlay))) - UI_Rect(content_rect) - { - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } - - ////////////////////////// - //- rjf: build panel container box - // - UI_Box *panel_box = &ui_nil_box; - UI_Rect(content_rect) UI_ChildLayoutAxis(Axis2_Y) UI_CornerRadius(0) UI_Focus(UI_FocusKind_On) - { - UI_Key panel_key = rd_ui_key_from_panel(panel); - panel_box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| - UI_BoxFlag_Clip| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DisableFocusOverlay| - ((ws->focused_panel != panel)*UI_BoxFlag_DisableFocusBorder), - panel_key); - } - - ////////////////////////// - //- rjf: loading animation for stable view - // - UI_Box *loading_overlay_container = &ui_nil_box; - UI_Parent(panel_box) UI_WidthFill UI_HeightFill - { - loading_overlay_container = ui_build_box_from_key(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); - } - - ////////////////////////// - //- rjf: build selected tab view - // - UI_Parent(panel_box) - UI_Focus(panel_is_focused ? UI_FocusKind_Null : UI_FocusKind_Off) - UI_WidthFill - { - //- rjf: push interaction registers, fill with per-view states - rd_push_regs(); - { - RD_View *view = rd_selected_tab_from_panel(panel); - String8 view_file_path = rd_file_path_from_eval_string(rd_frame_arena(), str8(view->query_buffer, view->query_string_size)); - rd_regs()->panel = rd_handle_from_panel(panel); - rd_regs()->view = rd_handle_from_view(view); - if(view_file_path.size != 0) - { - rd_regs()->file_path = view_file_path; - } - } - //- rjf: build view container - UI_Box *view_container_box = &ui_nil_box; - UI_FixedWidth(dim_2f32(content_rect).x) - UI_FixedHeight(dim_2f32(content_rect).y) - UI_ChildLayoutAxis(Axis2_Y) - { - view_container_box = ui_build_box_from_key(0, ui_key_zero()); - } - - //- rjf: build empty view - UI_Parent(view_container_box) if(rd_view_is_nil(rd_selected_tab_from_panel(panel))) - { - RD_VIEW_RULE_UI_FUNCTION_NAME(empty)(str8_zero(), &md_nil_node, content_rect); - } - - //- rjf: build tab view - UI_Parent(view_container_box) if(!rd_view_is_nil(rd_selected_tab_from_panel(panel))) - { - RD_View *view = rd_selected_tab_from_panel(panel); - RD_ViewRuleUIFunctionType *view_ui = view->spec->ui; - view_ui(str8(view->query_buffer, view->query_string_size), view->params_roots[view->params_read_gen%ArrayCount(view->params_roots)], content_rect); - } - - //- rjf: pop interaction registers; commit if this is the selected view - RD_Regs *view_regs = rd_pop_regs(); - if(ws->focused_panel == panel) - { - MemoryCopyStruct(rd_regs(), view_regs); - } - } - - //////////////////////// - //- rjf: loading? -> fill loading overlay container - // - { - RD_View *view = rd_selected_tab_from_panel(panel); - if(view->loading_t > 0.01f) UI_Parent(loading_overlay_container) - { - rd_loading_overlay(panel_rect, view->loading_t, view->loading_progress_v, view->loading_progress_v_target); - } - } - - ////////////////////////// - //- rjf: take events to automatically start/end filtering, if applicable - // - UI_Focus(UI_FocusKind_On) - { - RD_View *view = rd_selected_tab_from_panel(panel); - if(ui_is_focus_active() && view->spec->flags & RD_ViewRuleInfoFlag_TypingAutomaticallyFilters && !view->is_filtering) - { - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->flags & UI_EventFlag_Paste) - { - ui_eat_event(evt); - rd_cmd(RD_CmdKind_Filter); - rd_cmd(RD_CmdKind_Paste); - } - else if(evt->string.size != 0 && evt->kind == UI_EventKind_Text) - { - ui_eat_event(evt); - rd_cmd(RD_CmdKind_Filter); - rd_cmd(RD_CmdKind_InsertText, .string = evt->string); - } - } - } - if(view->spec->flags & RD_ViewRuleInfoFlag_CanFilter && (view->query_string_size != 0 || view->is_filtering) && ui_is_focus_active() && ui_slot_press(UI_EventActionSlot_Cancel)) - { - rd_cmd(RD_CmdKind_ClearFilter, .view = rd_handle_from_view(view)); - } - } - - ////////////////////////// - //- rjf: consume panel fallthrough interaction events - // - UI_Signal panel_sig = ui_signal_from_box(panel_box); - if(ui_pressed(panel_sig)) - { - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(panel)); - } - - ////////////////////////// - //- rjf: build tab bar - // - UI_Focus(UI_FocusKind_Off) - { - Temp scratch = scratch_begin(0, 0); - - // rjf: types - typedef struct DropSite DropSite; - struct DropSite - { - F32 p; - RD_View *prev_view; - }; - - // rjf: prep output data - RD_View *next_selected_tab_view = rd_selected_tab_from_panel(panel); + ////////////////////////// + //- rjf: build tab bar container + // UI_Box *tab_bar_box = &ui_nil_box; - U64 drop_site_count = panel->tab_view_count+1; - DropSite *drop_sites = push_array(scratch.arena, DropSite, drop_site_count); - F32 drop_site_max_p = 0; - U64 view_idx = 0; - - // rjf: build - UI_CornerRadius(0) + if(build_panel) UI_CornerRadius(0) UI_Rect(tab_bar_rect) { - UI_Rect(tab_bar_rect) tab_bar_box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_AllowOverflowY|UI_BoxFlag_ViewClampX|UI_BoxFlag_ViewScrollX|UI_BoxFlag_Clickable, "tab_bar_%p", panel); + tab_bar_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| + UI_BoxFlag_AllowOverflowY| + UI_BoxFlag_ViewClampX| + UI_BoxFlag_ViewScrollX| + UI_BoxFlag_Clickable, + "tab_bar_%p", panel->cfg); if(panel->tab_side == Side_Max) { tab_bar_box->view_off.y = tab_bar_box->view_off_target.y = (tab_bar_rheight - tab_bar_vheight); @@ -7580,64 +8965,222 @@ rd_window_frame(RD_Window *ws) tab_bar_box->view_off.y = tab_bar_box->view_off_target.y = 0; } } - UI_Parent(tab_bar_box) UI_PrefHeight(ui_pct(1, 0)) + + ////////////////////////// + //- rjf: determine tab drop site + // + B32 tab_drop_is_active = rd_drag_is_active() && ui_key_match(ui_drop_hot_key(), catchall_drop_site_key); + RD_Cfg *tab_drop_prev = &rd_nil_cfg; + if(build_panel) { - Temp scratch = scratch_begin(0, 0); - F32 corner_radius = ui_em(0.6f, 1.f).value; - ui_spacer(ui_px(1.f, 1.f)); - - // rjf: build tabs - UI_PrefWidth(ui_em(18.f, 0.5f)) - UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) + F32 best_prev_distance_px = 1000000.f; + TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + F32 off = 0; + for(TabTask *task = &start_boundary_tab_task; task != 0; task = task->next) + { + off += task->tab_width; + Vec2F32 anchor_pt = v2f32(tab_bar_box->rect.x0 + off, tab_bar_box->rect.y1); + F32 distance = length_2f32(sub_2f32(ui_mouse(), anchor_pt)); + if(distance < best_prev_distance_px) + { + best_prev_distance_px = distance; + tab_drop_prev = task->tab; + } + } + } + + ////////////////////////// + //- rjf: turn off drop visualization if this drag would be a no-op + // + if(tab_drop_is_active && rd_state->drag_drop_regs->panel == panel->cfg->id) + { + TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + if(tab_drop_prev->id == rd_state->drag_drop_regs->view) + { + tab_drop_is_active = 0; + } + if(tab_drop_is_active) for(TabTask *t = &start_boundary_tab_task; t != 0; t = t->next) + { + if(t->tab == tab_drop_prev && t->next != 0 && t->next->tab->id == rd_state->drag_drop_regs->view) + { + tab_drop_is_active = 0; + break; + } + } + } + + ////////////////////////// + //- rjf: build tab bar contents + // + if(build_panel) UI_Focus(UI_FocusKind_Off) UI_Parent(tab_bar_box) UI_Padding(ui_em(0.5f, 1.f)) UI_PrefHeight(ui_pct(1, 0)) UI_TagF("tab") + { + F32 corner_radius = ui_top_font_size()*0.6f; + TabTask start_boundary_tab_task = {first_tab_task, &rd_nil_cfg}; + UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) UI_CornerRadius01(panel->tab_side == Side_Min ? 0 : corner_radius) UI_CornerRadius10(panel->tab_side == Side_Min ? corner_radius : 0) UI_CornerRadius11(panel->tab_side == Side_Min ? 0 : corner_radius) - for(RD_View *view = panel->first_tab_view;; view = view->order_next, view_idx += 1) + for(TabTask *tab_task = &start_boundary_tab_task; tab_task != 0; tab_task = tab_task->next) { - temp_end(scratch); - if(rd_view_is_project_filtered(view)) { continue; } + RD_Cfg *tab = tab_task->tab; - // rjf: if before this tab is the prev-view of the current tab drag, - // draw empty space - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && catchall_drop_site_hovered) + //- rjf: build tab + DR_FStrList tab_fstrs = tab_task->fstrs; + F32 tab_width_px = tab_task->tab_width; + if(tab != &rd_nil_cfg) RD_RegsScope(.panel = panel->cfg->id, .view = tab->id, .tab = tab->id) { - RD_Panel *dst_panel = rd_panel_from_handle(rd_last_drag_drop_panel); - RD_View *drag_view = rd_view_from_handle(rd_state->drag_drop_regs->view); - RD_View *dst_prev_view = rd_view_from_handle(rd_last_drag_drop_prev_tab); - if(dst_panel == panel && - ((!rd_view_is_nil(view) && dst_prev_view == view->order_prev && drag_view != view && drag_view != view->order_prev) || - (rd_view_is_nil(view) && dst_prev_view == panel->last_tab_view && drag_view != panel->last_tab_view))) + // rjf: gather info for this tab + B32 tab_is_selected = (tab == panel->selected_tab); + B32 tab_is_auto = rd_view_setting_b32_from_name(str8_lit("auto")); + + // rjf: begin vertical region for this tab + ui_set_next_child_layout_axis(Axis2_Y); + ui_set_next_pref_width(ui_px(tab_width_px, 1)); + UI_Box *tab_column_box = ui_build_box_from_stringf(!is_changing_panel_boundaries*UI_BoxFlag_AnimatePosX, "tab_column_%p", tab); + + // rjf: choose palette + B32 omit_name = 0; + if(rd_drag_is_active() && rd_state->drag_drop_regs->view == tab->id && rd_state->drag_drop_regs_slot == RD_RegSlot_View) { - UI_PrefWidth(ui_em(9.f, 0.2f)) UI_Column + omit_name = 1; + } + + // rjf: build tab container box + UI_Parent(tab_column_box) + UI_PrefHeight(ui_px(tab_bar_vheight, 1)) + UI_TagF(omit_name ? "hollow" : "") + UI_TagF(!omit_name && !tab_is_selected ? "inactive" : "") + UI_TagF(!omit_name && tab_is_auto ? "auto" : "") + { + if(panel->tab_side == Side_Max) { - ui_spacer(ui_em(0.2f, 1.f)); - UI_CornerRadius00(corner_radius) - UI_CornerRadius10(corner_radius) - RD_Palette(RD_PaletteCode_DropSiteOverlay) + ui_spacer(ui_px(tab_bar_rv_diff-1.f, 1.f)); + } + else + { + ui_spacer(ui_px(1.f, 1.f)); + } + UI_Box *tab_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + (UI_BoxFlag_DrawDropShadow*tab_is_selected)| + UI_BoxFlag_Clickable, + "tab_%p", tab); + + // rjf: build tab contents + if(!omit_name) UI_Parent(tab_box) + { + UI_WidthFill UI_Row { - ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); + ui_spacer(ui_em(0.5f, 1.f)); + UI_PrefWidth(ui_text_dim(10, 0)) + { + UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(name_box, &tab_fstrs); + } + } + UI_PrefWidth(ui_px(tab_close_width_px, 1.f)) UI_TextAlignment(UI_TextAlign_Center) + RD_Font(RD_FontSlot_Icons) + UI_FontSize(ui_top_font_size()*0.75f) + UI_TagF(".") UI_TagF("tab") UI_TagF("weak") UI_TagF("implicit") + UI_CornerRadius00(0) + UI_CornerRadius01(0) + { + UI_Box *close_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawText| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "%S###close_view_%p", rd_icon_kind_text_table[RD_IconKind_X], tab); + UI_Signal sig = ui_signal_from_box(close_box); + if(ui_clicked(sig) || ui_middle_clicked(sig)) + { + rd_cmd(RD_CmdKind_CloseTab); + } + } + } + + // rjf: consume events for tab clicking + { + UI_Signal sig = ui_signal_from_box(tab_box); + if(ui_pressed(sig)) + { + rd_cmd(RD_CmdKind_FocusTab); + rd_cmd(RD_CmdKind_FocusPanel); + } + else if(ui_dragging(sig) && !rd_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) + { + rd_drag_begin(RD_RegSlot_View); + } + else if(ui_right_clicked(sig)) + { + rd_cmd(RD_CmdKind_PushQuery, + .ui_key = sig.box->key, + .expr = push_str8f(scratch.arena, "query:config.$%I64x", tab->id)); + } + else if(ui_middle_clicked(sig)) + { + rd_cmd(RD_CmdKind_CloseTab); } } } + + // rjf: space for next tab + { + ui_spacer(ui_px(floor_f32(ui_top_font_size()*0.4f), 1.f)); + } } - // rjf: end on nil view - if(rd_view_is_nil(view)) + //- rjf: if this is the currently active drop site's previous tab, then build empty space + // to visualize where tab will be moved once dropped + if(tab_drop_is_active && + rd_drag_is_active() && + rd_state->drag_drop_regs_slot == RD_RegSlot_View && + tab == tab_drop_prev) { - break; + // rjf: begin vertical region for this spot + ui_set_next_child_layout_axis(Axis2_Y); + ui_set_next_pref_width(ui_px(ui_top_font_size()*4.f, 1)); + UI_Box *tab_column_box = ui_build_box_from_stringf(!is_changing_panel_boundaries*UI_BoxFlag_AnimatePosX, "tab_column_%p", tab); + + // rjf: build spot container box + UI_Parent(tab_column_box) + UI_PrefHeight(ui_px(tab_bar_vheight, 1)) + UI_TagF("hollow") + { + if(panel->tab_side == Side_Max) + { + ui_spacer(ui_px(tab_bar_rv_diff-1.f, 1.f)); + } + else + { + ui_spacer(ui_px(1.f, 1.f)); + } + ui_set_next_group_key(catchall_drop_site_key); + UI_Box *tab_box = ui_build_box_from_key(UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_Clickable, + ui_key_zero()); + } + + // rjf: space for next tab + { + ui_spacer(ui_px(floor_f32(ui_top_font_size()*0.4f), 1.f)); + } } - - // rjf: gather info for this tab - B32 view_is_selected = (view == rd_selected_tab_from_panel(panel)); - RD_IconKind icon_kind = rd_icon_kind_from_view(view); - DR_FancyStringList title_fstrs = rd_title_fstrs_from_view(scratch.arena, view, ui_top_palette()->text, ui_top_palette()->text_weak, ui_top_font_size()); - - // rjf: begin vertical region for this tab + } + + // rjf: build add-new-tab button + UI_TextAlignment(UI_TextAlign_Center) + UI_PrefWidth(ui_px(tab_bar_vheight, 1.f)) + UI_PrefHeight(ui_px(tab_bar_vheight, 1.f)) + UI_TagF(".") + { ui_set_next_child_layout_axis(Axis2_Y); - UI_Box *tab_column_box = ui_build_box_from_stringf(!is_changing_panel_boundaries*UI_BoxFlag_AnimatePosX, "tab_column_%p", view); - - // rjf: build tab container box - UI_Parent(tab_column_box) UI_PrefHeight(ui_px(tab_bar_vheight, 1)) RD_Palette(view_is_selected ? RD_PaletteCode_Tab : RD_PaletteCode_TabInactive) + UI_Box *container = ui_build_box_from_stringf(!is_changing_panel_boundaries*UI_BoxFlag_AnimatePosX, "###add_new_tab"); + UI_Parent(container) { if(panel->tab_side == Side_Max) { @@ -7647,381 +9190,104 @@ rd_window_frame(RD_Window *ws) { ui_spacer(ui_px(1.f, 1.f)); } - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Box *tab_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - (UI_BoxFlag_DrawDropShadow*view_is_selected)| - UI_BoxFlag_Clickable, - "tab_%p", view); - - // rjf: build tab contents - UI_Parent(tab_box) + UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) + UI_CornerRadius10(panel->tab_side == Side_Min ? corner_radius : 0) + UI_CornerRadius01(panel->tab_side == Side_Max ? corner_radius : 0) + UI_CornerRadius11(panel->tab_side == Side_Max ? corner_radius : 0) + RD_Font(RD_FontSlot_Icons) + UI_FontSize(ui_top_font_size()) + UI_TagF("implicit") + UI_TagF("weak") { - UI_WidthFill UI_Row - { - ui_spacer(ui_em(0.5f, 1.f)); - if(icon_kind != RD_IconKind_Null) - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - RD_Font(RD_FontSlot_Icons) - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_em(1.75f, 1.f)) - ui_label(rd_icon_kind_text_table[icon_kind]); - } - UI_PrefWidth(ui_text_dim(10, 0)) - { - UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(name_box, &title_fstrs); - } - } - UI_PrefWidth(ui_em(2.35f, 1.f)) UI_TextAlignment(UI_TextAlign_Center) - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)*0.75f) - UI_Flags(UI_BoxFlag_DrawTextWeak) - UI_CornerRadius00(0) - UI_CornerRadius01(0) - { - UI_Palette *palette = ui_build_palette(ui_top_palette()); - palette->background = v4f32(0, 0, 0, 0); - ui_set_next_palette(palette); - UI_Signal sig = ui_buttonf("%S###close_view_%p", rd_icon_kind_text_table[RD_IconKind_X], view); - if(ui_clicked(sig) || ui_middle_clicked(sig)) - { - rd_cmd(RD_CmdKind_CloseTab, .panel = rd_handle_from_panel(panel), .view = rd_handle_from_view(view)); - } - } - } - - // rjf: consume events for tab clicking - { - UI_Signal sig = ui_signal_from_box(tab_box); + UI_Box *add_new_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_Clickable| + UI_BoxFlag_DisableTextTrunc, + "%S##add_new_tab_button_%p", + rd_icon_kind_text_table[RD_IconKind_Add], + panel->cfg); + UI_Signal sig = ui_signal_from_box(add_new_box); if(ui_pressed(sig)) { - next_selected_tab_view = view; - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(panel)); - } - else if(ui_dragging(sig) && !rd_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) - { - RD_RegsScope(.panel = rd_handle_from_panel(panel), - .view = rd_handle_from_view(view)) + rd_cmd(RD_CmdKind_FocusPanel, .panel = panel->cfg->id); + if(ws->query_is_active && + ui_key_match(add_new_box->key, ws->query_regs->ui_key)) { - rd_drag_begin(RD_RegSlot_View); + rd_cmd(RD_CmdKind_CancelQuery); + } + else + { + rd_cmd(RD_CmdKind_PushQuery, + .expr = str8_lit("query:tab_commands"), + .panel = panel->cfg->id, + .do_implicit_root = 1, + .do_lister = 1, + .ui_key = add_new_box->key); } } - else if(ui_right_clicked(sig)) - { - RD_RegsScope(.panel = rd_handle_from_panel(panel), - .view = rd_handle_from_view(view)) - { - rd_open_ctx_menu(sig.box->key, v2f32(0, sig.box->rect.y1 - sig.box->rect.y0), RD_RegSlot_View); - } - } - else if(ui_middle_clicked(sig)) - { - rd_cmd(RD_CmdKind_CloseTab, .panel = rd_handle_from_panel(panel), .view = rd_handle_from_view(view)); - } - } - } - - // rjf: space for next tab - { - ui_spacer(ui_em(0.3f, 1.f)); - } - - // rjf: store off drop-site - drop_sites[view_idx].p = tab_column_box->rect.x0 - tab_spacing/2; - drop_sites[view_idx].prev_view = view->order_prev; - drop_site_max_p = Max(tab_column_box->rect.x1, drop_site_max_p); - } - - // rjf: build add-new-tab button - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_px(tab_bar_vheight, 1.f)) - UI_PrefHeight(ui_px(tab_bar_vheight, 1.f)) - UI_Column - { - if(panel->tab_side == Side_Max) - { - ui_spacer(ui_px(tab_bar_rv_diff-1.f, 1.f)); - } - else - { - ui_spacer(ui_px(1.f, 1.f)); - } - UI_CornerRadius00(panel->tab_side == Side_Min ? corner_radius : 0) - UI_CornerRadius10(panel->tab_side == Side_Min ? corner_radius : 0) - UI_CornerRadius01(panel->tab_side == Side_Max ? corner_radius : 0) - UI_CornerRadius11(panel->tab_side == Side_Max ? corner_radius : 0) - RD_Font(RD_FontSlot_Icons) - UI_FontSize(ui_top_font_size()) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_HoverCursor(OS_Cursor_HandPoint) - RD_Palette(RD_PaletteCode_ImplicitButton) - { - UI_Box *add_new_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawText| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects| - UI_BoxFlag_Clickable| - UI_BoxFlag_DisableTextTrunc, - "%S##add_new_tab_button_%p", - rd_icon_kind_text_table[RD_IconKind_Add], - panel); - UI_Signal sig = ui_signal_from_box(add_new_box); - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(panel)); - UI_Key view_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("_view_menu_key_")); - ui_ctx_menu_open(view_menu_key, add_new_box->key, v2f32(0, tab_bar_vheight)); } } } - scratch_end(scratch); + // rjf: interact with tab bar + ui_signal_from_box(tab_bar_box); } - // rjf: interact with tab bar - ui_signal_from_box(tab_bar_box); - - // rjf: fill out last drop site + ////////////////////////// + //- rjf: accept tab drops + // + if(tab_drop_is_active && rd_drag_drop() && rd_state->drag_drop_regs_slot == RD_RegSlot_View) { - drop_sites[drop_site_count-1].p = drop_site_max_p; - drop_sites[drop_site_count-1].prev_view = panel->last_tab_view; + rd_cmd(RD_CmdKind_MoveView, + .dst_panel = panel->cfg->id, + .panel = rd_state->drag_drop_regs->panel, + .view = rd_state->drag_drop_regs->view, + .prev_tab = tab_drop_prev->id); } - // rjf: more precise drop-sites on tab bar + ////////////////////////// + //- rjf: accept file drops + // { - Vec2F32 mouse = ui_mouse(); - RD_View *view = rd_view_from_handle(rd_state->drag_drop_regs->view); - if(rd_drag_is_active() && rd_state->drag_drop_regs_slot == RD_RegSlot_View && window_is_focused && contains_2f32(panel_rect, mouse) && !rd_view_is_nil(view)) + for(UI_Event *evt = 0; ui_next_event(&evt);) { - // rjf: mouse => hovered drop site - F32 min_distance = 0; - DropSite *active_drop_site = 0; - if(catchall_drop_site_hovered) + if(evt->kind == UI_EventKind_FileDrop && contains_2f32(content_rect, evt->pos)) { - for(U64 drop_site_idx = 0; drop_site_idx < drop_site_count; drop_site_idx += 1) + B32 need_drop_completion = 0; + arena_clear(ws->drop_completion_arena); + MemoryZeroStruct(&ws->drop_completion_paths); + for(String8Node *n = evt->paths.first; n != 0; n = n->next) { - F32 distance = abs_f32(drop_sites[drop_site_idx].p - mouse.x); - if(drop_site_idx == 0 || distance < min_distance) + Temp scratch = scratch_begin(0, 0); + String8 path = n->string; + if(str8_match(str8_skip_last_dot(path), str8_lit("exe"), StringMatchFlag_CaseInsensitive)) { - active_drop_site = &drop_sites[drop_site_idx]; - min_distance = distance; + str8_list_push(ws->drop_completion_arena, &ws->drop_completion_paths, push_str8_copy(ws->drop_completion_arena, path)); + need_drop_completion = 1; } + else + { + rd_cmd(RD_CmdKind_Open, .file_path = path); + } + scratch_end(scratch); } - } - - // rjf: store closest prev-view - if(active_drop_site != 0) - { - rd_last_drag_drop_prev_tab = rd_handle_from_view(active_drop_site->prev_view); - } - else - { - rd_last_drag_drop_prev_tab = rd_handle_zero(); - } - - // rjf: vis - RD_Panel *drag_panel = rd_panel_from_handle(rd_state->drag_drop_regs->panel); - if(!rd_view_is_nil(view) && active_drop_site != 0) - { - RD_Palette(RD_PaletteCode_DropSiteOverlay) UI_Rect(tab_bar_rect) - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } - - // rjf: drop - if(catchall_drop_site_hovered && (active_drop_site != 0 && rd_drag_drop())) - { - RD_View *view = rd_view_from_handle(rd_state->drag_drop_regs->view); - RD_Panel *src_panel = rd_panel_from_handle(rd_state->drag_drop_regs->panel); - if(!rd_panel_is_nil(panel) && !rd_view_is_nil(view)) + if(need_drop_completion) { - rd_cmd(RD_CmdKind_MoveTab, - .panel = rd_handle_from_panel(src_panel), - .dst_panel = rd_handle_from_panel(panel), - .view = rd_handle_from_view(view), - .prev_view = rd_handle_from_view(active_drop_site->prev_view)); + ui_ctx_menu_open(rd_state->drop_completion_key, ui_key_zero(), evt->pos); } + ui_eat_event(evt); } } } - - // rjf: apply tab change - { - panel->selected_tab_view = rd_handle_from_view(next_selected_tab_view); - } - - scratch_end(scratch); - } - - ////////////////////////// - //- rjf: less granular panel-wide drop-site - // - if(catchall_drop_site_hovered) - { - rd_last_drag_drop_panel = rd_handle_from_panel(panel); - - RD_View *dragged_view = rd_view_from_handle(rd_state->drag_drop_regs->view); - B32 view_is_in_panel = 0; - for(RD_View *view = panel->first_tab_view; !rd_view_is_nil(view); view = view->order_next) - { - if(rd_view_is_project_filtered(view)) { continue; } - if(view == dragged_view) - { - view_is_in_panel = 1; - break; - } - } - - if(view_is_in_panel == 0) - { - // rjf: vis - { - RD_Palette(RD_PaletteCode_DropSiteOverlay) UI_Rect(content_rect) - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } - - // rjf: drop - { - if(rd_drag_drop()) - { - RD_Panel *src_panel = rd_panel_from_handle(rd_state->drag_drop_regs->panel); - RD_View *view = rd_view_from_handle(rd_state->drag_drop_regs->view); - if(rd_state->drag_drop_regs_slot == RD_RegSlot_View && !rd_view_is_nil(view)) - { - rd_cmd(RD_CmdKind_MoveTab, - .prev_view = rd_handle_from_view(panel->last_tab_view), - .panel = rd_handle_from_panel(src_panel), - .dst_panel = rd_handle_from_panel(panel), - .view = rd_handle_from_view(view)); - } - } - } - } - } - - ////////////////////////// - //- rjf: accept file drops - // - { - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->kind == UI_EventKind_FileDrop && contains_2f32(content_rect, evt->pos)) - { - B32 need_drop_completion = 0; - arena_clear(ws->drop_completion_arena); - MemoryZeroStruct(&ws->drop_completion_paths); - for(String8Node *n = evt->paths.first; n != 0; n = n->next) - { - Temp scratch = scratch_begin(0, 0); - String8 path = path_normalized_from_string(scratch.arena, n->string); - if(str8_match(str8_skip_last_dot(path), str8_lit("exe"), StringMatchFlag_CaseInsensitive)) - { - str8_list_push(ws->drop_completion_arena, &ws->drop_completion_paths, push_str8_copy(ws->drop_completion_arena, path)); - need_drop_completion = 1; - } - else - { - rd_cmd(RD_CmdKind_Open, .file_path = path); - } - scratch_end(scratch); - } - if(need_drop_completion) - { - ui_ctx_menu_open(rd_state->drop_completion_key, ui_key_zero(), evt->pos); - } - ui_eat_event(evt); - } - } } } } //////////////////////////// - //- rjf: animate views - // - { - Temp scratch = scratch_begin(0, 0); - typedef struct Task Task; - struct Task - { - Task *next; - RD_Panel *panel; - RD_View *list_first; - RD_View *transient_owner; - }; - Task start_task = {0, &rd_nil_panel, ws->query_view_stack_top}; - Task *first_task = &start_task; - Task *last_task = first_task; - F32 rate = 1 - pow_f32(2, (-10.f * rd_state->frame_dt)); - F32 fast_rate = 1 - pow_f32(2, (-40.f * rd_state->frame_dt)); - for(RD_Panel *panel = ws->root_panel; - !rd_panel_is_nil(panel); - panel = rd_panel_rec_depth_first_pre(panel).next) - { - Task *t = push_array(scratch.arena, Task, 1); - SLLQueuePush(first_task, last_task, t); - t->panel = panel; - t->list_first = panel->first_tab_view; - } - for(Task *t = first_task; t != 0; t = t->next) - { - RD_View *list_first = t->list_first; - for(RD_View *view = list_first; !rd_view_is_nil(view); view = view->order_next) - { - if(!rd_view_is_nil(view->first_transient)) - { - Task *task = push_array(scratch.arena, Task, 1); - SLLQueuePush(first_task, last_task, task); - task->panel = t->panel; - task->list_first = view->first_transient; - task->transient_owner = view; - } - if(window_is_focused) - { - if(abs_f32(view->loading_t_target - view->loading_t) > 0.01f || - abs_f32(view->scroll_pos.x.off) > 0.01f || - abs_f32(view->scroll_pos.y.off) > 0.01f || - abs_f32(view->is_filtering_t - (F32)!!view->is_filtering)) - { - rd_request_frame(); - } - if(view->loading_t_target != 0 && (view == rd_selected_tab_from_panel(t->panel) || - t->transient_owner == rd_selected_tab_from_panel(t->panel))) - { - rd_request_frame(); - } - } - view->loading_t += (view->loading_t_target - view->loading_t) * rate; - view->is_filtering_t += ((F32)!!view->is_filtering - view->is_filtering_t) * fast_rate; - view->scroll_pos.x.off -= view->scroll_pos.x.off * (rd_setting_val_from_code(RD_SettingCode_ScrollingAnimations).s32 ? fast_rate : 1.f); - view->scroll_pos.y.off -= view->scroll_pos.y.off * (rd_setting_val_from_code(RD_SettingCode_ScrollingAnimations).s32 ? fast_rate : 1.f); - if(abs_f32(view->scroll_pos.x.off) < 0.01f) - { - view->scroll_pos.x.off = 0; - } - if(abs_f32(view->scroll_pos.y.off) < 0.01f) - { - view->scroll_pos.y.off = 0; - } - if(abs_f32(view->is_filtering_t - (F32)!!view->is_filtering) < 0.01f) - { - view->is_filtering_t = (F32)!!view->is_filtering; - } - if(view == rd_selected_tab_from_panel(t->panel) || - t->transient_owner == rd_selected_tab_from_panel(t->panel)) - { - view->loading_t_target = 0; - } - } - } - scratch_end(scratch); - } - - //////////////////////////// - //- rjf: drag/drop cancelling + //- rjf: @window_ui_part drag/drop cancelling // if(rd_drag_is_active() && ui_slot_press(UI_EventActionSlot_Cancel)) { @@ -8030,20 +9296,20 @@ rd_window_frame(RD_Window *ws) } //////////////////////////// - //- rjf: font size changing + //- rjf: @window_ui_part top-level font size changing // for(UI_Event *evt = 0; ui_next_event(&evt);) { - if(evt->kind == UI_EventKind_Scroll && evt->modifiers & OS_Modifier_Ctrl) + if(evt->kind == UI_EventKind_Scroll && evt->modifiers == OS_Modifier_Ctrl) { ui_eat_event(evt); if(evt->delta_2f32.y < 0) { - rd_cmd(RD_CmdKind_IncUIFontScale, .window = rd_handle_from_window(ws)); + rd_cmd(RD_CmdKind_IncWindowFontSize); } else if(evt->delta_2f32.y > 0) { - rd_cmd(RD_CmdKind_DecUIFontScale, .window = rd_handle_from_window(ws)); + rd_cmd(RD_CmdKind_DecWindowFontSize); } } } @@ -8052,77 +9318,18 @@ rd_window_frame(RD_Window *ws) } ////////////////////////////// - //- rjf: ensure hover eval is in-bounds - // - if(!ui_box_is_nil(hover_eval_box)) - { - UI_Box *root = hover_eval_box; - Rng2F32 window_rect = os_client_rect_from_window(ui_window()); - Rng2F32 root_rect = root->rect; - Vec2F32 shift = - { - -ClampBot(0, root_rect.x1 - window_rect.x1), - -ClampBot(0, root_rect.y1 - window_rect.y1), - }; - Rng2F32 new_root_rect = shift_2f32(root_rect, shift); - root->fixed_position = new_root_rect.p0; - root->fixed_size = dim_2f32(new_root_rect); - root->rect = new_root_rect; - for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) - { - ui_calc_sizes_standalone__in_place_rec(root, axis); - ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); - ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); - ui_layout_enforce_constraints__in_place_rec(root, axis); - ui_layout_position__in_place_rec(root, axis); - } - } - - ////////////////////////////// - //- rjf: attach autocomp box to root, or hide if it has not been renewed - // - if(!ui_box_is_nil(autocomp_box) && ws->autocomp_last_frame_idx+1 >= rd_state->frame_index+1) - { - UI_Box *autocomp_root_box = ui_box_from_key(ws->autocomp_root_key); - if(!ui_box_is_nil(autocomp_root_box)) - { - Vec2F32 size = autocomp_box->fixed_size; - autocomp_box->fixed_position = v2f32(autocomp_root_box->rect.x0, autocomp_root_box->rect.y1); - autocomp_box->rect = r2f32(autocomp_box->fixed_position, add_2f32(autocomp_box->fixed_position, size)); - for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) - { - ui_calc_sizes_standalone__in_place_rec(autocomp_box, axis); - ui_calc_sizes_upwards_dependent__in_place_rec(autocomp_box, axis); - ui_calc_sizes_downwards_dependent__in_place_rec(autocomp_box, axis); - ui_layout_enforce_constraints__in_place_rec(autocomp_box, axis); - ui_layout_position__in_place_rec(autocomp_box, axis); - } - } - } - else if(!ui_box_is_nil(autocomp_box) && ws->autocomp_last_frame_idx+1 < rd_state->frame_index+1) - { - UI_Box *autocomp_root_box = ui_box_from_key(ws->autocomp_root_key); - if(!ui_box_is_nil(autocomp_root_box)) - { - Vec2F32 size = autocomp_box->fixed_size; - Rng2F32 window_rect = os_client_rect_from_window(ws->os); - autocomp_box->fixed_position = v2f32(window_rect.x1, window_rect.y1); - autocomp_box->rect = r2f32(autocomp_box->fixed_position, add_2f32(autocomp_box->fixed_position, size)); - } - } - - ////////////////////////////// - //- rjf: hover eval cancelling + //- rjf: @window_frame_part hover eval cancelling // if(ws->hover_eval_string.size != 0 && ui_slot_press(UI_EventActionSlot_Cancel)) { MemoryZeroStruct(&ws->hover_eval_string); arena_clear(ws->hover_eval_arena); + ws->hover_eval_focused = 0; rd_request_frame(); } ////////////////////////////// - //- rjf: animate + //- rjf: @window_frame_part animate // if(ui_animating_from_state(ws->ui)) { @@ -8130,13 +9337,26 @@ rd_window_frame(RD_Window *ws) } ////////////////////////////// - //- rjf: draw UI + //- rjf: @window_frame_part draw UI // ws->draw_bucket = dr_bucket_make(); DR_BucketScope(ws->draw_bucket) ProfScope("draw UI") { Temp scratch = scratch_begin(0, 0); + F32 box_squish_epsilon = 0.001f; + Rng2F32 window_rect = os_client_rect_from_window(ws->os); + + //- rjf: unpack settings + F32 rounded_corner_amount = rd_setting_f32_from_name(str8_lit("rounded_corner_amount")); + F32 border_softness = 1.f; + B32 do_background_blur = rd_setting_b32_from_name(str8_lit("background_blur")); + B32 force_opaque_floating_backgrounds = rd_setting_b32_from_name(str8_lit("opaque_backgrounds")); + B32 do_drop_shadows = + rd_setting_b32_from_name(str8_lit("drop_shadows")); + Vec4F32 base_background_color = ui_color_from_name(str8_lit("background")); + Vec4F32 base_border_color = ui_color_from_name(str8_lit("border")); + Vec4F32 drop_shadow_color = ui_color_from_name(str8_lit("drop_shadow")); //- rjf: set up heatmap buckets F32 heatmap_bucket_size = 32.f; @@ -8155,20 +9375,28 @@ rd_window_frame(RD_Window *ws) //- rjf: draw background color { - Vec4F32 bg_color = rd_rgba_from_theme_color(RD_ThemeColor_BaseBackground); - dr_rect(os_client_rect_from_window(ws->os), bg_color, 0, 0, 0); + dr_rect(os_client_rect_from_window(ws->os), base_background_color, 0, 0, 0); } //- rjf: draw window border { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_BaseBorder); - dr_rect(os_client_rect_from_window(ws->os), color, 0, 1.f, 0.5f); + dr_rect(os_client_rect_from_window(ws->os), base_border_color, 0, 1.f, border_softness*0.5f); } //- rjf: recurse & draw U64 total_heatmap_sum_count = 0; + UI_Box *hover_debug_box = &ui_nil_box; for(UI_Box *box = ui_root_from_state(ws->ui); !ui_box_is_nil(box);) { + // rjf: get corner radii + F32 box_corner_radii[Corner_COUNT] = + { + box->corner_radii[Corner_00]*rounded_corner_amount, + box->corner_radii[Corner_01]*rounded_corner_amount, + box->corner_radii[Corner_10]*rounded_corner_amount, + box->corner_radii[Corner_11]*rounded_corner_amount, + }; + // rjf: get recursion UI_BoxRec rec = ui_box_rec_df_post(box, &ui_nil_box); @@ -8185,6 +9413,12 @@ rd_window_frame(RD_Window *ws) } } + // rjf: grab if debug + if(box->flags & UI_BoxFlag_Debug && contains_2f32(box->rect, ui_mouse())) + { + hover_debug_box = box; + } + // rjf: push transparency if(box->transparency != 0) { @@ -8192,88 +9426,114 @@ rd_window_frame(RD_Window *ws) } // rjf: push squish - if(box->squish != 0) + if(box->squish > box_squish_epsilon) { Vec2F32 box_dim = dim_2f32(box->rect); - Mat3x3F32 box2origin_xform = make_translate_3x3f32(v2f32(-box->rect.x0 - box_dim.x/8, -box->rect.y0)); + Vec2F32 anchor_off = {0}; + if(box->flags & UI_BoxFlag_SquishAnchored) + { + anchor_off.x = box_dim.x/2.f; + } + else + { + anchor_off.y = -box_dim.y/8.f; + } + Mat3x3F32 box2origin_xform = make_translate_3x3f32(v2f32(-box->rect.x0 - box_dim.x/2 + anchor_off.x, -box->rect.y0 + anchor_off.y)); Mat3x3F32 scale_xform = make_scale_3x3f32(v2f32(1-box->squish, 1-box->squish)); - Mat3x3F32 origin2box_xform = make_translate_3x3f32(v2f32(box->rect.x0 + box_dim.x/8, box->rect.y0)); + Mat3x3F32 origin2box_xform = make_translate_3x3f32(v2f32(box->rect.x0 + box_dim.x/2 - anchor_off.x, box->rect.y0 - anchor_off.y)); Mat3x3F32 xform = mul_3x3f32(origin2box_xform, mul_3x3f32(scale_xform, box2origin_xform)); dr_push_xform2d(xform); dr_push_tex2d_sample_kind(R_Tex2DSampleKind_Linear); } // rjf: draw drop shadow - if(box->flags & UI_BoxFlag_DrawDropShadow) + if(do_drop_shadows && box->flags & UI_BoxFlag_DrawDropShadow) { Rng2F32 drop_shadow_rect = shift_2f32(pad_2f32(box->rect, 8), v2f32(4, 4)); - Vec4F32 drop_shadow_color = rd_rgba_from_theme_color(RD_ThemeColor_DropShadow); - dr_rect(drop_shadow_rect, drop_shadow_color, 0.8f, 0, 8.f); + R_Rect2DInst *inst = dr_rect(drop_shadow_rect, drop_shadow_color, 0.8f, 0, 8.f); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } // rjf: blur background - if(box->flags & UI_BoxFlag_DrawBackgroundBlur && rd_setting_val_from_code(RD_SettingCode_BackgroundBlur).s32) + if(do_background_blur && box->flags & UI_BoxFlag_DrawBackgroundBlur) { R_PassParams_Blur *params = dr_blur(pad_2f32(box->rect, 1.f), box->blur_size*(1-box->transparency), 0); - MemoryCopyArray(params->corner_radii, box->corner_radii); + MemoryCopyArray(params->corner_radii, box_corner_radii); + } + + // rjf: compute effective active t + F32 effective_active_t = box->active_t; + if(!(box->flags & UI_BoxFlag_DrawActiveEffects)) + { + effective_active_t = 0; + } + F32 t = box->hot_t*(1-effective_active_t); + + // rjf: compute background color + Vec4F32 box_background_color = box->background_color; + if(force_opaque_floating_backgrounds && box->flags & UI_BoxFlag_Floating && box->flags & UI_BoxFlag_DrawDropShadow) + { + box_background_color.w = 1.f; } // rjf: draw background if(box->flags & UI_BoxFlag_DrawBackground) { - // rjf: main rectangle + // rjf: hot effect extension (drop shadow) + if(box->flags & UI_BoxFlag_DrawHotEffects) { - R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1), box->palette->colors[UI_ColorCode_Background], 0, 0, 1.f); - MemoryCopyArray(inst->corner_radii, box->corner_radii); + Rng2F32 drop_shadow_rect = shift_2f32(pad_2f32(box->rect, 8), v2f32(4, 4)); + Vec4F32 color = drop_shadow_color; + color.w *= t*box_background_color.w; + dr_rect(drop_shadow_rect, color, 0.8f, 0, 8.f); } + // rjf: draw background + R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1.f), box_background_color, 0, 0, border_softness*1.f); + MemoryCopyArray(inst->corner_radii, box_corner_radii); + // rjf: hot effect extension if(box->flags & UI_BoxFlag_DrawHotEffects) { - F32 effective_active_t = box->active_t; - if(!(box->flags & UI_BoxFlag_DrawActiveEffects)) - { - effective_active_t = 0; - } - F32 t = box->hot_t*(1-effective_active_t); + B32 is_hot = !ui_key_match(box->key, ui_key_zero()) && ui_key_match(box->key, ui_hot_key()); + Vec4F32 hover_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover")); // rjf: brighten { - R_Rect2DInst *inst = dr_rect(box->rect, v4f32(0, 0, 0, 0), 0, 0, 1.f); - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Hover); - color.w *= t*0.2f; + Vec4F32 color = hover_color; + color.w *= 0.05f; + if(!is_hot) + { + color.w *= t; + } + R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1.f), v4f32(0, 0, 0, 0), 0, 0, border_softness*1.f); inst->colors[Corner_00] = color; - inst->colors[Corner_01] = color; inst->colors[Corner_10] = color; - inst->colors[Corner_11] = color; - inst->colors[Corner_10].w *= t; - inst->colors[Corner_11].w *= t; - MemoryCopyArray(inst->corner_radii, box->corner_radii); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } - // rjf: slight emboss fadeoff - if(0) + // rjf: soft circle around mouse + if(box->hot_t > 0.01f) DR_ClipScope(box->rect) { - Rng2F32 rect = r2f32p(box->rect.x0, - box->rect.y0, - box->rect.x1, - box->rect.y1); - R_Rect2DInst *inst = dr_rect(rect, v4f32(0, 0, 0, 0), 0, 0, 1.f); - inst->colors[Corner_00] = v4f32(0.f, 0.f, 0.f, 0.0f*t); - inst->colors[Corner_01] = v4f32(0.f, 0.f, 0.f, 0.3f*t); - inst->colors[Corner_10] = v4f32(0.f, 0.f, 0.f, 0.0f*t); - inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.3f*t); - MemoryCopyArray(inst->corner_radii, box->corner_radii); + Vec4F32 color = hover_color; + color.w *= 0.02f; + if(!is_hot) + { + color.w *= t; + } + Vec2F32 center = ui_mouse(); + Vec2F32 box_dim = dim_2f32(box->rect); + F32 max_dim = Max(box_dim.x, box_dim.y); + F32 radius = box->font_size*12.f; + radius = Min(max_dim, radius); + dr_rect(pad_2f32(r2f32(center, center), radius), color, radius, 0, radius/3.f); } } // rjf: active effect extension if(box->flags & UI_BoxFlag_DrawActiveEffects) { - Vec4F32 shadow_color = rd_rgba_from_theme_color(RD_ThemeColor_Hover); - shadow_color.x *= 0.3f; - shadow_color.y *= 0.3f; - shadow_color.z *= 0.3f; + Vec4F32 shadow_color = drop_shadow_color; shadow_color.w *= 0.5f*box->active_t; Vec2F32 shadow_size = { @@ -8288,15 +9548,15 @@ rd_window_frame(RD_Window *ws) R_Rect2DInst *inst = dr_rect(r2f32p(box->rect.x0, box->rect.y0, box->rect.x1, box->rect.y0 + shadow_size.y), v4f32(0, 0, 0, 0), 0, 0, 1.f); inst->colors[Corner_00] = inst->colors[Corner_10] = shadow_color; inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.0f); - MemoryCopyArray(inst->corner_radii, box->corner_radii); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } // rjf: bottom -> top light effect { R_Rect2DInst *inst = dr_rect(r2f32p(box->rect.x0, box->rect.y1 - shadow_size.y, box->rect.x1, box->rect.y1), v4f32(0, 0, 0, 0), 0, 0, 1.f); inst->colors[Corner_00] = inst->colors[Corner_10] = v4f32(0, 0, 0, 0); - inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(0.4f, 0.4f, 0.4f, 0.4f*box->active_t); - MemoryCopyArray(inst->corner_radii, box->corner_radii); + inst->colors[Corner_01] = inst->colors[Corner_11] = v4f32(1.0f, 1.0f, 1.0f, 0.08f*box->active_t); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } // rjf: left -> right dark effect @@ -8305,7 +9565,7 @@ rd_window_frame(RD_Window *ws) inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(0.f, 0.f, 0.f, 0.f); inst->colors[Corner_00] = shadow_color; inst->colors[Corner_01] = shadow_color; - MemoryCopyArray(inst->corner_radii, box->corner_radii); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } // rjf: right -> left dark effect @@ -8314,7 +9574,7 @@ rd_window_frame(RD_Window *ws) inst->colors[Corner_00] = inst->colors[Corner_01] = v4f32(0.f, 0.f, 0.f, 0.f); inst->colors[Corner_10] = shadow_color; inst->colors[Corner_11] = shadow_color; - MemoryCopyArray(inst->corner_radii, box->corner_radii); + MemoryCopyArray(inst->corner_radii, box_corner_radii); } } } @@ -8332,15 +9592,24 @@ rd_window_frame(RD_Window *ws) FNT_Run ellipses_run = {0}; if(!(box->flags & UI_BoxFlag_DisableTextTrunc)) { + FNT_Tag ellipses_font = box->font; + F32 ellipses_size = box->font_size; + FNT_RasterFlags ellipses_raster_flags = box->text_raster_flags; + if(box->display_fstrs.last) + { + ellipses_font = box->display_fstrs.last->v.params.font; + ellipses_size = box->display_fstrs.last->v.params.size; + ellipses_raster_flags = box->display_fstrs.last->v.params.raster_flags; + } max_x = (box->rect.x1-text_position.x); - ellipses_run = fnt_push_run_from_string(scratch.arena, box->font, box->font_size, 0, box->tab_size, 0, str8_lit("...")); + ellipses_run = fnt_run_from_string(ellipses_font, ellipses_size, 0, box->tab_size, ellipses_raster_flags, str8_lit("...")); } - dr_truncated_fancy_run_list(text_position, &box->display_string_runs, max_x, ellipses_run); - if(box->flags & UI_BoxFlag_HasFuzzyMatchRanges) + if(box->flags & UI_BoxFlag_HasFuzzyMatchRanges) UI_TagF("match") { - Vec4F32 match_color = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); - dr_truncated_fancy_run_fuzzy_matches(text_position, &box->display_string_runs, max_x, &box->fuzzy_match_ranges, match_color); + Vec4F32 match_color = ui_color_from_tags_key_name(ui_top_tags_key(), str8_lit("background")); + dr_truncated_fancy_run_fuzzy_matches(text_position, &box->display_fruns, max_x, &box->fuzzy_match_ranges, match_color); } + dr_truncated_fancy_run_list(text_position, &box->display_fruns, max_x, ellipses_run); } // rjf: draw focus viz @@ -8425,88 +9694,108 @@ rd_window_frame(RD_Window *ws) dr_pop_clip(); } - // rjf: draw overlay - if(b->flags & UI_BoxFlag_DrawOverlay) + // rjf: get corner radii + F32 b_corner_radii[Corner_COUNT] = { - R_Rect2DInst *inst = dr_rect(b->rect, b->palette->colors[UI_ColorCode_Overlay], 0, 0, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); - } + b->corner_radii[Corner_00]*rounded_corner_amount, + b->corner_radii[Corner_01]*rounded_corner_amount, + b->corner_radii[Corner_10]*rounded_corner_amount, + b->corner_radii[Corner_11]*rounded_corner_amount, + }; // rjf: draw border if(b->flags & UI_BoxFlag_DrawBorder) { - R_Rect2DInst *inst = dr_rect(pad_2f32(b->rect, 1.f), b->palette->colors[UI_ColorCode_Border], 0, 1.f, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + Vec4F32 border_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("border")); + Rng2F32 b_border_rect = pad_2f32(b->rect, 1.f); + R_Rect2DInst *inst = dr_rect(b_border_rect, border_color, 0, 1.f, border_softness*1.f); + MemoryCopyArray(inst->corner_radii, b_corner_radii); // rjf: hover effect if(b->flags & UI_BoxFlag_DrawHotEffects) { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Hover); - color.w *= b->hot_t; - R_Rect2DInst *inst = dr_rect(pad_2f32(b->rect, 1), color, 0, 1.f, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + Vec4F32 color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover")); + if(ui_key_match(b->key, ui_key_zero()) || !ui_key_match(b->key, ui_hot_key())) + { + color.w *= b->hot_t; + } + R_Rect2DInst *inst = dr_rect(b_border_rect, color, 0, 1.f, 1.f); + inst->colors[Corner_01].w *= 0.2f; + inst->colors[Corner_11].w *= 0.2f; + MemoryCopyArray(inst->corner_radii, b_corner_radii); } } // rjf: debug border rendering - if(0) + if(b->flags & UI_BoxFlag_Debug) { - R_Rect2DInst *inst = dr_rect(pad_2f32(b->rect, 1), v4f32(1, 0, 1, 0.25f), 0, 1.f, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + R_Rect2DInst *inst = dr_rect(b->rect, v4f32(1*box->pref_size[Axis2_X].strictness, 0, 1, 0.25f), 0, 1.f, 0); + MemoryCopyArray(inst->corner_radii, b_corner_radii); } // rjf: draw sides + if(b->flags & (UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight)) { + Vec4F32 border_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("border")); Rng2F32 r = b->rect; F32 half_thickness = 1.f; - F32 softness = 0.5f; + F32 softness = 0.f; if(b->flags & UI_BoxFlag_DrawSideTop) { - dr_rect(r2f32p(r.x0, r.y0-half_thickness, r.x1, r.y0+half_thickness), b->palette->colors[UI_ColorCode_Border], 0, 0, softness); + dr_rect(r2f32p(r.x0, r.y0, r.x1, r.y0+2*half_thickness), border_color, 0, 0, softness); } if(b->flags & UI_BoxFlag_DrawSideBottom) { - dr_rect(r2f32p(r.x0, r.y1-half_thickness, r.x1, r.y1+half_thickness), b->palette->colors[UI_ColorCode_Border], 0, 0, softness); + dr_rect(r2f32p(r.x0, r.y1-2*half_thickness, r.x1, r.y1), border_color, 0, 0, softness); } if(b->flags & UI_BoxFlag_DrawSideLeft) { - dr_rect(r2f32p(r.x0-half_thickness, r.y0, r.x0+half_thickness, r.y1), b->palette->colors[UI_ColorCode_Border], 0, 0, softness); + dr_rect(r2f32p(r.x0, r.y0, r.x0+2*half_thickness, r.y1), border_color, 0, 0, softness); } if(b->flags & UI_BoxFlag_DrawSideRight) { - dr_rect(r2f32p(r.x1-half_thickness, r.y0, r.x1+half_thickness, r.y1), b->palette->colors[UI_ColorCode_Border], 0, 0, softness); + dr_rect(r2f32p(r.x1-2*half_thickness, r.y0, r.x1, r.y1), border_color, 0, 0, softness); } } // rjf: draw focus overlay if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusOverlay) && b->focus_hot_t > 0.01f) { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Focus); - color.w *= 0.2f*b->focus_hot_t; + String8 extras[] = {str8_lit("focus"), str8_lit("overlay")}; + String8Array extras_array = {extras, ArrayCount(extras)}; + Vec4F32 color = ui_color_from_tags_key_extras(b->tags_key, extras_array); + color.w *= b->focus_hot_t; R_Rect2DInst *inst = dr_rect(b->rect, color, 0, 0, 0.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + MemoryCopyArray(inst->corner_radii, b_corner_radii); } // rjf: draw focus border if(b->flags & UI_BoxFlag_Clickable && !(b->flags & UI_BoxFlag_DisableFocusBorder) && b->focus_active_t > 0.01f) { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Focus); + Rng2F32 rect = b->rect; + if(b->flags & UI_BoxFlag_Floating) + { + rect = pad_2f32(rect, 1.f); + rect = intersect_2f32(window_rect, rect); + } + String8 extras[] = {str8_lit("focus"), str8_lit("border")}; + String8Array extras_array = {extras, ArrayCount(extras)}; + Vec4F32 color = ui_color_from_tags_key_extras(b->tags_key, extras_array); color.w *= b->focus_active_t; - R_Rect2DInst *inst = dr_rect(b->rect, color, 0, 1.f, 1.f); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + R_Rect2DInst *inst = dr_rect(rect, color, 0, 1.f, border_softness*1.f); + MemoryCopyArray(inst->corner_radii, b_corner_radii); } // rjf: disabled overlay if(b->disabled_t >= 0.005f) { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_DisabledOverlay); - color.w *= b->disabled_t; - R_Rect2DInst *inst = dr_rect(b->rect, color, 0, 0, 1); - MemoryCopyArray(inst->corner_radii, b->corner_radii); + Vec4F32 disabled_overlay_color = v4f32(base_background_color.x, base_background_color.y, base_background_color.z, b->disabled_t*0.3f); + R_Rect2DInst *inst = dr_rect(b->rect, disabled_overlay_color, 0, 0, 1); + MemoryCopyArray(inst->corner_radii, b_corner_radii); } // rjf: pop squish - if(b->squish != 0) + if(b->squish > box_squish_epsilon) { dr_pop_xform2d(); dr_pop_tex2d_sample_kind(); @@ -8543,58 +9832,48 @@ rd_window_frame(RD_Window *ws) } } - //- rjf: draw border/overlay color to signify error - if(ws->error_t > 0.01f) + //- rjf: draw hover debug box + if(hover_debug_box != &ui_nil_box) { - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_NegativePopButtonBackground); + FNT_Tag font = rd_font_from_slot(RD_FontSlot_Code); + Vec2F32 p = ui_mouse(); + dr_rect(hover_debug_box->rect, v4f32(1, 1, 1, 0.2f), 0, 0, 0); + dr_text(font, 12.f, 0, 0, FNT_RasterFlag_Hinted, p, v4f32(1, 1, 1, 1), push_str8f(scratch.arena, "key: 0x%I64x", hover_debug_box->key.u64[0])); + p.y += 20.f; + dr_text(font, 12.f, 0, 0, FNT_RasterFlag_Hinted, p, v4f32(1, 1, 1, 1), push_str8f(scratch.arena, "string: '%S'", hover_debug_box->string)); + p.y += 20.f; + } + + //- rjf: draw border/overlay color to signify error + if(ws->error_t > 0.01f) UI_TagF("bad") + { + Vec4F32 color = ui_color_from_name(str8_lit("text")); color.w *= ws->error_t; Rng2F32 rect = os_client_rect_from_window(ws->os); dr_rect(pad_2f32(rect, 24.f), color, 0, 16.f, 12.f); - dr_rect(rect, v4f32(color.x, color.y, color.z, color.w*0.05f), 0, 0, 0); + dr_rect(rect, v4f32(color.x, color.y, color.z, color.w*0.025f), 0, 0, 0); } - //- rjf: scratch debug mouse drawing - if(DEV_scratch_mouse_draw) + //- rjf: draw border/overlay color to signify rebinding + if(rd_state->bind_change_active) UI_TagF("pop") { -#if 1 - Vec2F32 p = add_2f32(os_mouse_from_window(ws->os), v2f32(30, 0)); - dr_rect(os_client_rect_from_window(ws->os), v4f32(0, 0, 0, 0.9f), 0, 0, 0); - FNT_Run trailer_run = fnt_push_run_from_string(scratch.arena, rd_font_from_slot(RD_FontSlot_Main), 16.f, 0, 0, 0, str8_lit("...")); - DR_FancyStringList strs = {0}; - DR_FancyString str = {rd_font_from_slot(RD_FontSlot_Main), str8_lit("Shift + F5"), v4f32(1, 1, 1, 1), 72.f, 0.f}; - dr_fancy_string_list_push(scratch.arena, &strs, &str); - DR_FancyRunList runs = dr_fancy_run_list_from_fancy_string_list(scratch.arena, 0, FNT_RasterFlag_Smooth, &strs); - dr_truncated_fancy_run_list(p, &runs, 1000000.f, trailer_run); - dr_rect(r2f32(p, add_2f32(p, runs.dim)), v4f32(1, 0, 0, 0.5f), 0, 1, 0); - dr_rect(r2f32(sub_2f32(p, v2f32(4, 4)), add_2f32(p, v2f32(4, 4))), v4f32(1, 0, 1, 1), 0, 0, 0); -#else - Vec2F32 p = add_2f32(os_mouse_from_window(ws->os), v2f32(30, 0)); - dr_rect(os_client_rect_from_window(ws->os), v4f32(0, 0, 0, 0.4f), 0, 0, 0); - DR_FancyStringList strs = {0}; - DR_FancyString str1 = {rd_font_from_slot(RD_FontSlot_Main), str8_lit("T"), v4f32(1, 1, 1, 1), 16.f, 4.f}; - dr_fancy_string_list_push(scratch.arena, &strs, &str1); - DR_FancyString str2 = {rd_font_from_slot(RD_FontSlot_Main), str8_lit("his is a test of some "), v4f32(1, 0.5f, 0.5f, 1), 14.f, 0.f}; - dr_fancy_string_list_push(scratch.arena, &strs, &str2); - DR_FancyString str3 = {rd_font_from_slot(RD_FontSlot_Code), str8_lit("very fancy text!"), v4f32(1, 0.8f, 0.4f, 1), 18.f, 4.f, 4.f}; - dr_fancy_string_list_push(scratch.arena, &strs, &str3); - DR_FancyRunList runs = dr_fancy_run_list_from_fancy_string_list(scratch.arena, 0, 0, &strs); - FNT_Run trailer_run = fnt_push_run_from_string(scratch.arena, rd_font_from_slot(RD_FontSlot_Main), 16.f, 0, 0, 0, str8_lit("...")); - F32 limit = 500.f + sin_f32(rd_state->time_in_seconds/10.f)*200.f; - dr_truncated_fancy_run_list(p, &runs, limit, trailer_run); - dr_rect(r2f32p(p.x+limit, 0, p.x+limit+2.f, 1000), v4f32(1, 0, 0, 1), 0, 0, 0); - rd_request_frame(); -#endif + Vec4F32 color = ui_color_from_name(str8_lit("background")); + Rng2F32 rect = os_client_rect_from_window(ws->os); + dr_rect(pad_2f32(rect, 24.f), color, 0, 16.f, 12.f); + dr_rect(rect, v4f32(color.x, color.y, color.z, color.w*0.025f), 0, 0, 0); } scratch_end(scratch); } ////////////////////////////// - //- rjf: increment per-window frame counter + //- rjf: @window_frame_part update per-window frame counters/info // ws->frames_alive += 1; + ws->last_window_rect = os_client_rect_from_window(ws->os); ProfEnd(); + scratch_end(scratch); } #if COMPILER_MSVC && !BUILD_DEBUG @@ -8604,1152 +9883,28 @@ rd_window_frame(RD_Window *ws) //////////////////////////////// //~ rjf: Eval Visualization -typedef struct RD_EntityExpandAccel RD_EntityExpandAccel; -struct RD_EntityExpandAccel -{ - RD_EntityArray entities; -}; - -typedef struct RD_CtrlEntityExpandAccel RD_CtrlEntityExpandAccel; -struct RD_CtrlEntityExpandAccel -{ - CTRL_EntityArray entities; -}; - -//- rjf: meta entities - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(watches) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_Watch); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(watches) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_Watch, 0); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches) { return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_Watch, 0); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches) { return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_Watch, 0); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(targets) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_Target); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(targets) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_Target, 1); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(targets) { return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_Target, 1); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(targets) { return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_Target, 1); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(breakpoints) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_Breakpoint); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(breakpoints) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_Breakpoint, 1); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(breakpoints) { return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_Breakpoint, 1); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(breakpoints) { return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_Breakpoint, 1); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(watch_pins) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_WatchPin); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(watch_pins) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_WatchPin, 1); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watch_pins) { return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_WatchPin, 1); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watch_pins) { return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_WatchPin, 1); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(file_path_maps) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_FilePathMap); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(file_path_maps) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_FilePathMap, 1); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(file_path_maps) { return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_FilePathMap, 1); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(file_path_maps) { return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_FilePathMap, 1); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(auto_view_rules) { return rd_ev_view_rule_expr_expand_info__meta_entities(arena, view, filter, expr, params, RD_EntityKind_AutoViewRule); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(auto_view_rules) { return rd_ev_view_rule_expr_expand_range_info__meta_entities(arena, view, filter, expr, params, idx_range, user_data, RD_EntityKind_AutoViewRule, 1); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(auto_view_rules){ return rd_ev_view_rule_expr_id_from_num__meta_entities(num, user_data, RD_EntityKind_AutoViewRule, 1); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(auto_view_rules){ return rd_ev_view_rule_expr_num_from_id__meta_entities(id, user_data, RD_EntityKind_AutoViewRule, 1); } - -//- rjf: control entity groups - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(machines) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, str8_zero(), expr, params, CTRL_EntityKind_Machine); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(machines) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, str8_zero(), expr, params, idx_range, user_data, CTRL_EntityKind_Machine); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(machines) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Machine); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(machines) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Machine); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(processes) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, filter, expr, params, CTRL_EntityKind_Process); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(processes) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, filter, expr, params, idx_range, user_data, CTRL_EntityKind_Process); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(processes) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Process); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(processes) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Process); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, filter, expr, params, CTRL_EntityKind_Thread); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, filter, expr, params, idx_range, user_data, CTRL_EntityKind_Thread); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Thread); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(threads) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Thread); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(arena, view, filter, expr, params, CTRL_EntityKind_Module); } -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(arena, view, filter, expr, params, idx_range, user_data, CTRL_EntityKind_Module); } -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(num, user_data, CTRL_EntityKind_Module); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(modules) { return rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(id, user_data, CTRL_EntityKind_Module); } - -//- rjf: control entity hierarchies - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(scheduler_machine) -{ - EV_ExpandInfo info = {0}; - Temp scratch = scratch_begin(&arena, 1); - E_Eval eval = e_eval_from_expr(scratch.arena, expr); - CTRL_Entity *machine = rd_ctrl_entity_from_eval_space(eval.space); - if(machine->kind == CTRL_EntityKind_Machine) - { - CTRL_EntityList processes = {0}; - for(CTRL_Entity *child = machine->first; child != &ctrl_entity_nil; child = child->next) - { - if(child->kind == CTRL_EntityKind_Process) - { - ctrl_entity_list_push(scratch.arena, &processes, child); - } - } - CTRL_EntityArray *processes_array = push_array(arena, CTRL_EntityArray, 1); - *processes_array = ctrl_entity_array_from_list(arena, &processes); - info.user_data = processes_array; - info.row_count = processes.count; - info.rows_default_expanded = 1; - } - scratch_end(scratch); - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(scheduler_machine) -{ - EV_ExpandRangeInfo info = {0}; - { - CTRL_EntityArray *processes = (CTRL_EntityArray *)user_data; - if(processes != 0) - { - info.row_exprs_count = dim_1u64(idx_range); - info.row_strings = push_array(arena, String8, info.row_exprs_count); - info.row_view_rules = push_array(arena, String8, info.row_exprs_count); - info.row_exprs = push_array(arena, E_Expr *, info.row_exprs_count); - info.row_members = push_array(arena, E_Member *, info.row_exprs_count); - U64 row_expr_idx = 0; - for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, row_expr_idx += 1) - { - CTRL_Entity *process = processes->v[idx]; - E_Expr *expr = e_push_expr(arena, E_ExprKind_LeafOffset, 0); - expr->space = rd_eval_space_from_ctrl_entity(process, RD_EvalSpaceKind_MetaCtrlEntity); - expr->mode = E_Mode_Offset; - expr->type_key = e_type_key_cons_base(type(CTRL_ProcessMetaEval));; - info.row_exprs[row_expr_idx] = expr; - info.row_members[row_expr_idx] = &e_member_nil; - } - } - } - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(scheduler_machine) -{ - return num; -} - -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(scheduler_machine) -{ - return id; -} - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(scheduler_process) -{ - EV_ExpandInfo info = {0}; - Temp scratch = scratch_begin(&arena, 1); - E_Eval eval = e_eval_from_expr(scratch.arena, expr); - CTRL_Entity *process = rd_ctrl_entity_from_eval_space(eval.space); - if(process->kind == CTRL_EntityKind_Process) - { - CTRL_EntityList threads = {0}; - for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) - { - if(child->kind == CTRL_EntityKind_Thread) - { - B32 is_in_filter = 1; - if(filter.size != 0) - { - is_in_filter = 0; - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, child->string); - if(matches.count == matches.needle_part_count) - { - is_in_filter = 1; - } - else - { - DI_Scope *di_scope = di_scope_open(); - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(child); - CTRL_CallStack call_stack = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &unwind); - for(U64 idx = 0; idx < call_stack.concrete_frame_count && idx < 5; idx += 1) - { - CTRL_CallStackFrame *f = &call_stack.frames[idx]; - String8 name = {0}; - name.str = rdi_string_from_idx(f->rdi, f->procedure->name_string_idx, &name.size); - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, name); - if(matches.count == matches.needle_part_count) - { - is_in_filter = 1; - break; - } - } - di_scope_close(di_scope); - } - } - if(is_in_filter) - { - ctrl_entity_list_push(scratch.arena, &threads, child); - } - } - } - CTRL_EntityArray *threads_array = push_array(arena, CTRL_EntityArray, 1); - *threads_array = ctrl_entity_array_from_list(arena, &threads); - info.user_data = threads_array; - info.row_count = threads.count; - } - scratch_end(scratch); - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(scheduler_process) -{ - EV_ExpandRangeInfo info = {0}; - { - CTRL_EntityArray *threads = (CTRL_EntityArray *)user_data; - if(threads != 0) - { - info.row_exprs_count = dim_1u64(idx_range); - info.row_strings = push_array(arena, String8, info.row_exprs_count); - info.row_view_rules = push_array(arena, String8, info.row_exprs_count); - info.row_exprs = push_array(arena, E_Expr *, info.row_exprs_count); - info.row_members = push_array(arena, E_Member *, info.row_exprs_count); - U64 row_expr_idx = 0; - for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, row_expr_idx += 1) - { - CTRL_Entity *thread = threads->v[idx]; - E_Expr *expr = e_push_expr(arena, E_ExprKind_LeafOffset, 0); - expr->space = rd_eval_space_from_ctrl_entity(thread, RD_EvalSpaceKind_MetaCtrlEntity); - expr->mode = E_Mode_Offset; - expr->type_key = e_type_key_cons_base(type(CTRL_ThreadMetaEval)); - info.row_exprs[row_expr_idx] = expr; - info.row_members[row_expr_idx] = &e_member_nil; - } - } - } - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(scheduler_process) -{ - return num; -} - -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(scheduler_process) -{ - return id; -} - -//- rjf: locals - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(locals) -{ - Temp scratch = scratch_begin(&arena, 1); - E_String2NumMapNodeArray nodes = e_string2num_map_node_array_from_map(scratch.arena, e_parse_ctx->locals_map); - e_string2num_map_node_array_sort__in_place(&nodes); - String8List exprs_filtered = {0}; - for EachIndex(idx, nodes.count) - { - String8 local_expr_string = nodes.v[idx]->string; - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, local_expr_string); - if(matches.count == matches.needle_part_count) - { - str8_list_push(scratch.arena, &exprs_filtered, local_expr_string); - } - } - String8Array *accel = push_array(arena, String8Array, 1); - *accel = str8_array_from_list(arena, &exprs_filtered); - EV_ExpandInfo info = {accel, accel->count}; - scratch_end(scratch); - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(locals) -{ - String8Array *accel = (String8Array *)user_data; - EV_ExpandRangeInfo result = {0}; - { - U64 needed_row_count = dim_1u64(idx_range); - result.row_exprs_count = Min(needed_row_count, accel->count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - result.row_exprs[row_expr_idx] = e_parse_expr_from_text(arena, accel->v[idx_range.min + row_expr_idx]); - result.row_members[row_expr_idx] = &e_member_nil; - } - } - return result; -} - -//- rjf: registers - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(registers) -{ - Temp scratch = scratch_begin(&arena, 1); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - Arch arch = thread->arch; - U64 reg_count = regs_reg_code_count_from_arch(arch); - U64 alias_count = regs_alias_code_count_from_arch(arch); - String8 *reg_strings = regs_reg_code_string_table_from_arch(arch); - String8 *alias_strings = regs_alias_code_string_table_from_arch(arch); - String8List exprs_list = {0}; - for(U64 idx = 1; idx < reg_count; idx += 1) - { - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, reg_strings[idx]); - if(matches.count == matches.needle_part_count) - { - str8_list_push(scratch.arena, &exprs_list, reg_strings[idx]); - } - } - for(U64 idx = 1; idx < alias_count; idx += 1) - { - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, alias_strings[idx]); - if(matches.count == matches.needle_part_count) - { - str8_list_push(scratch.arena, &exprs_list, alias_strings[idx]); - } - } - String8Array *accel = push_array(arena, String8Array, 1); - *accel = str8_array_from_list(arena, &exprs_list); - EV_ExpandInfo info = {accel, accel->count}; - scratch_end(scratch); - return info; -} - -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(registers) -{ - String8Array *accel = (String8Array *)user_data; - EV_ExpandRangeInfo result = {0}; - { - U64 needed_row_count = dim_1u64(idx_range); - result.row_exprs_count = Min(needed_row_count, accel->count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - String8 string = push_str8f(arena, "reg:%S", accel->v[idx_range.min + row_expr_idx]); - result.row_exprs[row_expr_idx] = e_parse_expr_from_text(arena, string); - result.row_members[row_expr_idx] = &e_member_nil; - } - } - return result; -} - -//- rjf: debug info tables - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(globals) {return rd_ev_view_rule_expr_expand_info__debug_info_tables(arena, view, filter, expr, params, RDI_SectionKind_GlobalVariables);} -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(globals) {return rd_ev_view_rule_expr_expand_range_info__debug_info_tables(arena, view, filter, expr, params, idx_range, user_data, RDI_SectionKind_GlobalVariables);} -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(globals) {return rd_ev_view_rule_expr_id_from_num__debug_info_tables(num, user_data, RDI_SectionKind_GlobalVariables); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(globals) {return rd_ev_view_rule_expr_num_from_id__debug_info_tables(id, user_data, RDI_SectionKind_GlobalVariables); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(thread_locals) {return rd_ev_view_rule_expr_expand_info__debug_info_tables(arena, view, filter, expr, params, RDI_SectionKind_ThreadVariables);} -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(thread_locals) {return rd_ev_view_rule_expr_expand_range_info__debug_info_tables(arena, view, filter, expr, params, idx_range, user_data, RDI_SectionKind_ThreadVariables);} -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(thread_locals) {return rd_ev_view_rule_expr_id_from_num__debug_info_tables(num, user_data, RDI_SectionKind_ThreadVariables); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(thread_locals) {return rd_ev_view_rule_expr_num_from_id__debug_info_tables(id, user_data, RDI_SectionKind_ThreadVariables); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(types) {return rd_ev_view_rule_expr_expand_info__debug_info_tables(arena, view, filter, expr, params, RDI_SectionKind_UDTs);} -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(types) {return rd_ev_view_rule_expr_expand_range_info__debug_info_tables(arena, view, filter, expr, params, idx_range, user_data, RDI_SectionKind_UDTs);} -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(types) {return rd_ev_view_rule_expr_id_from_num__debug_info_tables(num, user_data, RDI_SectionKind_UDTs); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(types) {return rd_ev_view_rule_expr_num_from_id__debug_info_tables(id, user_data, RDI_SectionKind_UDTs); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(procedures) {return rd_ev_view_rule_expr_expand_info__debug_info_tables(arena, view, filter, expr, params, RDI_SectionKind_Procedures);} -EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_DEF(procedures) {return rd_ev_view_rule_expr_expand_range_info__debug_info_tables(arena, view, filter, expr, params, idx_range, user_data, RDI_SectionKind_Procedures);} -EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_DEF(procedures) {return rd_ev_view_rule_expr_id_from_num__debug_info_tables(num, user_data, RDI_SectionKind_Procedures); } -EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_DEF(procedures) {return rd_ev_view_rule_expr_num_from_id__debug_info_tables(id, user_data, RDI_SectionKind_Procedures); } - -internal EV_ExpandInfo -rd_ev_view_rule_expr_expand_info__meta_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, RD_EntityKind kind) -{ - RD_EntityExpandAccel *accel = push_array(arena, RD_EntityExpandAccel, 1); - Temp scratch = scratch_begin(&arena, 1); - { - RD_EntityList entities = rd_query_cached_entity_list_with_kind(kind); - RD_EntityList entities_filtered = {0}; - for(RD_EntityNode *n = entities.first; n != 0; n = n->next) - { - RD_Entity *entity = n->entity; - String8 entity_expr_string = entity->string; - B32 is_collection = 0; - for EachElement(idx, rd_collection_name_table) - { - if(str8_match(entity_expr_string, rd_collection_name_table[idx], 0)) - { - is_collection = 1; - break; - } - } - B32 is_in_filter = 1; - if(!is_collection && filter.size != 0) - { - RD_Entity *loc = rd_entity_child_from_kind(entity, RD_EntityKind_Location); - RD_Entity *exe = rd_entity_child_from_kind(entity, RD_EntityKind_Executable); - RD_Entity *args = rd_entity_child_from_kind(entity, RD_EntityKind_Arguments); - FuzzyMatchRangeList expr_matches = fuzzy_match_find(scratch.arena, filter, entity_expr_string); - FuzzyMatchRangeList loc_matches = fuzzy_match_find(scratch.arena, filter, loc->string); - FuzzyMatchRangeList exe_matches = fuzzy_match_find(scratch.arena, filter, exe->string); - FuzzyMatchRangeList args_matches = fuzzy_match_find(scratch.arena, filter, args->string); - is_in_filter = (expr_matches.count == expr_matches.needle_part_count || - loc_matches.count == loc_matches.needle_part_count || - exe_matches.count == exe_matches.needle_part_count || - args_matches.count == args_matches.needle_part_count); - } - if(is_collection || is_in_filter) - { - rd_entity_list_push(scratch.arena, &entities_filtered, entity); - } - } - accel->entities = rd_entity_array_from_list(arena, &entities_filtered); - } - scratch_end(scratch); - EV_ExpandInfo info = {accel, accel->entities.count + 1}; - info.add_new_row = 1; - return info; -} - -internal EV_ExpandRangeInfo -rd_ev_view_rule_expr_expand_range_info__meta_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, RD_EntityKind kind, B32 add_new_at_top) -{ - RD_EntityExpandAccel *accel = (RD_EntityExpandAccel *)user_data; - EV_ExpandRangeInfo result = {0}; - { - U64 entities_base_idx = (U64)!!add_new_at_top; - U64 needed_row_count = dim_1u64(idx_range); - result.row_exprs_count = Min(needed_row_count, accel->entities.count+1); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - U64 child_idx = idx_range.min + row_expr_idx; - RD_Entity *entity = &rd_nil_entity; - if(entities_base_idx <= child_idx && child_idx < entities_base_idx+accel->entities.count) - { - entity = accel->entities.v[child_idx-entities_base_idx]; - } - if(!rd_entity_is_nil(entity)) - { - String8 entity_expr_string = (kind == RD_EntityKind_Watch ? entity->string : push_str8f(arena, "entity:$%I64u", entity->id)); - if(kind == RD_EntityKind_Watch) - { - result.row_strings[row_expr_idx] = entity_expr_string; - } - result.row_exprs[row_expr_idx] = e_parse_expr_from_text(arena, entity_expr_string); - result.row_view_rules[row_expr_idx] = rd_entity_child_from_kind(entity, RD_EntityKind_ViewRule)->string; - } - else - { - result.row_exprs[row_expr_idx] = &e_expr_nil; - } - result.row_members[row_expr_idx] = &e_member_nil; - } - } - return result; -} - -internal U64 -rd_ev_view_rule_expr_id_from_num__meta_entities(U64 num, void *user_data, RD_EntityKind kind, B32 add_new_at_top) -{ - U64 id = 0; - RD_EntityExpandAccel *accel = (RD_EntityExpandAccel *)user_data; - U64 entities_base_idx = (U64)!!add_new_at_top; - if(entities_base_idx+1 <= num && num < entities_base_idx+accel->entities.count+1) - { - id = accel->entities.v[num-(entities_base_idx+1)]->id; - } - else - { - id = max_U64; - } - return id; -} - -internal U64 -rd_ev_view_rule_expr_num_from_id__meta_entities(U64 id, void *user_data, RD_EntityKind kind, B32 add_new_at_top) -{ - RD_EntityExpandAccel *accel = (RD_EntityExpandAccel *)user_data; - U64 num = 0; - U64 entities_base_idx = (U64)!!add_new_at_top; - if(id == max_U64) - { - num = add_new_at_top ? 1 : (entities_base_idx + accel->entities.count + 1); - } - else for(U64 idx = 0; idx < accel->entities.count; idx += 1) - { - if(accel->entities.v[idx]->id == id) - { - num = entities_base_idx+idx+1; - break; - } - } - return num; -} - -internal EV_ExpandInfo -rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, CTRL_EntityKind kind) -{ - RD_CtrlEntityExpandAccel *accel = push_array(arena, RD_CtrlEntityExpandAccel, 1); - Temp scratch = scratch_begin(&arena, 1); - { - CTRL_EntityList entities = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, kind); - CTRL_EntityList entities_filtered = {0}; - for(CTRL_EntityNode *n = entities.first; n != 0; n = n->next) - { - CTRL_Entity *entity = n->v; - B32 is_in_filter = 1; - if(filter.size != 0) - { - is_in_filter = 0; - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, entity->string); - if(matches.count == matches.needle_part_count) - { - is_in_filter = 1; - } - } - if(is_in_filter) - { - ctrl_entity_list_push(scratch.arena, &entities_filtered, entity); - } - } - accel->entities = ctrl_entity_array_from_list(arena, &entities_filtered); - } - scratch_end(scratch); - EV_ExpandInfo info = {accel, accel->entities.count}; - // TODO(rjf): hack - if(kind == CTRL_EntityKind_Machine) - { - info.rows_default_expanded = 1; - } - return info; -} - -internal EV_ExpandRangeInfo -rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, CTRL_EntityKind kind) -{ - RD_CtrlEntityExpandAccel *accel = (RD_CtrlEntityExpandAccel *)user_data; - EV_ExpandRangeInfo result = {0}; - { - U64 needed_row_count = dim_1u64(idx_range); - result.row_exprs_count = Min(needed_row_count, accel->entities.count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - CTRL_Entity *entity = accel->entities.v[idx_range.min + row_expr_idx]; - String8 entity_expr_string = push_str8f(arena, "ctrl_entity:$_%I64x_%I64x", entity->handle.machine_id, entity->handle.dmn_handle.u64[0]); - result.row_exprs[row_expr_idx] = e_parse_expr_from_text(arena, entity_expr_string); - result.row_members[row_expr_idx] = &e_member_nil; - } - } - return result; -} - -internal U64 -rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(U64 num, void *user_data, CTRL_EntityKind kind) -{ - RD_CtrlEntityExpandAccel *accel = (RD_CtrlEntityExpandAccel *)user_data; - U64 id = 0; - if(1 <= num && num <= accel->entities.count) - { - id = d_hash_from_string(str8_struct(&accel->entities.v[num-1]->handle)); - } - return id; -} - -internal U64 -rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(U64 id, void *user_data, CTRL_EntityKind kind) -{ - RD_CtrlEntityExpandAccel *accel = (RD_CtrlEntityExpandAccel *)user_data; - U64 num = 0; - if(id != 0) - { - for EachIndex(idx, accel->entities.count) - { - U64 idx_id = d_hash_from_string(str8_struct(&accel->entities.v[idx]->handle)); - if(idx_id == id) - { - num = idx+1; - break; - } - } - } - return num; -} - -typedef struct RD_DebugInfoTableExpandAccel RD_DebugInfoTableExpandAccel; -struct RD_DebugInfoTableExpandAccel -{ - U64 rdis_count; - RDI_Parsed **rdis; - DI_SearchItemArray items; -}; - -internal EV_ExpandInfo -rd_ev_view_rule_expr_expand_info__debug_info_tables(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, RDI_SectionKind section) -{ - RD_DebugInfoTableExpandAccel *accel = push_array(arena, RD_DebugInfoTableExpandAccel, 1); - if(section != RDI_SectionKind_NULL) - { - Temp scratch = scratch_begin(&arena, 1); - U64 endt_us = os_now_microseconds()+200; - - //- rjf: unpack context - DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena); - DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); - U64 rdis_count = dbgi_keys.count; - RDI_Parsed **rdis = push_array(arena, RDI_Parsed *, rdis_count); - for(U64 idx = 0; idx < rdis_count; idx += 1) - { - rdis[idx] = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_keys.v[idx], endt_us); - } - - //- rjf: query all filtered items from dbgi searching system - U128 fuzzy_search_key = {(U64)view, (U64)section}; - B32 items_stale = 0; - DI_SearchParams params = {section, dbgi_keys}; - accel->rdis_count = rdis_count; - accel->rdis = rdis; - accel->items = di_search_items_from_key_params_query(rd_state->frame_di_scope, fuzzy_search_key, ¶ms, filter, endt_us, &items_stale); - if(items_stale) - { - rd_request_frame(); - } - - scratch_end(scratch); - } - EV_ExpandInfo info = {accel, accel->items.count}; - return info; -} - -internal EV_ExpandRangeInfo -rd_ev_view_rule_expr_expand_range_info__debug_info_tables(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, RDI_SectionKind section) -{ - RD_DebugInfoTableExpandAccel *accel = (RD_DebugInfoTableExpandAccel *)user_data; - EV_ExpandRangeInfo result = {0}; - { - U64 needed_row_count = dim_1u64(idx_range); - result.row_exprs_count = Min(needed_row_count, accel->items.count); - result.row_exprs = push_array(arena, E_Expr *, result.row_exprs_count); - result.row_strings = push_array(arena, String8, result.row_exprs_count); - result.row_view_rules = push_array(arena, String8, result.row_exprs_count); - result.row_members = push_array(arena, E_Member *, result.row_exprs_count); - for EachIndex(row_expr_idx, result.row_exprs_count) - { - // rjf: unpack row - DI_SearchItem *item = &accel->items.v[idx_range.min + row_expr_idx]; - - // rjf: skip bad elements - if(item->dbgi_idx >= accel->rdis_count) - { - continue; - } - - // rjf: unpack row info - RDI_Parsed *rdi = accel->rdis[item->dbgi_idx]; - E_Module *module = &e_parse_ctx->modules[item->dbgi_idx]; - - // rjf: build expr - E_Expr *item_expr = &e_expr_nil; - { - U64 element_idx = item->idx; - switch(section) - { - default:{}break; - case RDI_SectionKind_Procedures: - { - RDI_Procedure *procedure = rdi_element_from_name_idx(module->rdi, Procedures, element_idx); - RDI_Scope *scope = rdi_element_from_name_idx(module->rdi, Scopes, procedure->root_scope_idx); - U64 voff = *rdi_element_from_name_idx(module->rdi, ScopeVOffData, scope->voff_range_first); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); - String8 bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = procedure->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_parse_ctx->modules)); - item_expr = e_push_expr(arena, E_ExprKind_LeafBytecode, 0); - item_expr->mode = E_Mode_Value; - item_expr->space = module->space; - item_expr->type_key = type_key; - item_expr->bytecode = bytecode; - item_expr->string.str = rdi_string_from_idx(module->rdi, procedure->name_string_idx, &item_expr->string.size); - }break; - case RDI_SectionKind_GlobalVariables: - { - RDI_GlobalVariable *gvar = rdi_element_from_name_idx(module->rdi, GlobalVariables, element_idx); - U64 voff = gvar->voff; - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); - String8 bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = gvar->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_parse_ctx->modules)); - item_expr = e_push_expr(arena, E_ExprKind_LeafBytecode, 0); - item_expr->mode = E_Mode_Offset; - item_expr->space = module->space; - item_expr->type_key = type_key; - item_expr->bytecode = bytecode; - item_expr->string.str = rdi_string_from_idx(module->rdi, gvar->name_string_idx, &item_expr->string.size); - }break; - case RDI_SectionKind_ThreadVariables: - { - RDI_ThreadVariable *tvar = rdi_element_from_name_idx(module->rdi, ThreadVariables, element_idx); - E_OpList oplist = {0}; - e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(tvar->tls_off)); - String8 bytecode = e_bytecode_from_oplist(arena, &oplist); - U32 type_idx = tvar->type_idx; - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_parse_ctx->modules)); - item_expr = e_push_expr(arena, E_ExprKind_LeafBytecode, 0); - item_expr->mode = E_Mode_Offset; - item_expr->space = module->space; - item_expr->type_key = type_key; - item_expr->bytecode = bytecode; - item_expr->string.str = rdi_string_from_idx(module->rdi, tvar->name_string_idx, &item_expr->string.size); - }break; - case RDI_SectionKind_UDTs: - { - RDI_UDT *udt = rdi_element_from_name_idx(module->rdi, UDTs, element_idx); - RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, udt->self_type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), udt->self_type_idx, (U32)(module - e_parse_ctx->modules)); - item_expr = e_push_expr(arena, E_ExprKind_TypeIdent, 0); - item_expr->type_key = type_key; - }break; - } - } - - // rjf: fill - result.row_exprs[row_expr_idx] = item_expr; - result.row_members[row_expr_idx] = &e_member_nil; - } - } - return result; -} - -internal U64 -rd_ev_view_rule_expr_id_from_num__debug_info_tables(U64 num, void *user_data, RDI_SectionKind section) -{ - RD_DebugInfoTableExpandAccel *accel = (RD_DebugInfoTableExpandAccel *)user_data; - U64 id = 0; - if(0 < num && num <= accel->items.count) - { - id = accel->items.v[num-1].idx+1; - } - return id; -} - -internal U64 -rd_ev_view_rule_expr_num_from_id__debug_info_tables(U64 id, void *user_data, RDI_SectionKind section) -{ - RD_DebugInfoTableExpandAccel *accel = (RD_DebugInfoTableExpandAccel *)user_data; - U64 num = di_search_item_num_from_array_element_idx__linear_search(&accel->items, id-1); - return num; -} - -internal EV_View * -rd_ev_view_from_key(U64 key) -{ - U64 slot_idx = key % rd_state->eval_viz_view_cache_slots_count; - RD_EvalVizViewCacheNode *node = 0; - RD_EvalVizViewCacheSlot *slot = &rd_state->eval_viz_view_cache_slots[slot_idx]; - for(RD_EvalVizViewCacheNode *n = slot->first; n != 0; n = n->next) - { - if(n->key == key) - { - node = n; - break; - } - } - if(node == 0) - { - node = rd_state->eval_viz_view_cache_node_free; - if(node) - { - SLLStackPop(rd_state->eval_viz_view_cache_node_free); - } - else - { - node = push_array(rd_state->arena, RD_EvalVizViewCacheNode, 1); - } - DLLPushBack(slot->first, slot->last, node); - node->key = key; - node->v = ev_view_alloc(); - } - return node->v; -} - -internal F32 -rd_append_value_strings_from_eval(Arena *arena, EV_StringFlags flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size, S32 depth, E_Eval eval, E_Member *member, EV_ViewRuleList *view_rules, String8List *out) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - F32 space_taken = 0; - - //- rjf: unpack view rules - U32 radix = default_radix; - U32 min_digits = 0; - B32 no_addr = 0; - B32 no_string = 0; - B32 has_array = 0; - for(EV_ViewRuleNode *n = view_rules->first; n != 0; n = n->next) - { - if(0){} - else if(str8_match(n->v.root->string, str8_lit("dec"), 0)) {radix = 10;} - else if(str8_match(n->v.root->string, str8_lit("hex"), 0)) {radix = 16;} - else if(str8_match(n->v.root->string, str8_lit("bin"), 0)) {radix = 2; } - else if(str8_match(n->v.root->string, str8_lit("oct"), 0)) {radix = 8; } - else if(str8_match(n->v.root->string, str8_lit("no_addr"), 0)) {no_addr = 1;} - else if(str8_match(n->v.root->string, str8_lit("no_string"), 0)) {no_string = 1;} - else if(str8_match(n->v.root->string, str8_lit("array"), 0)) {has_array = 1;} - else if(str8_match(n->v.root->string, str8_lit("digits"), 0)) - { - String8 expr = md_string_from_children(scratch.arena, n->v.root); - E_Eval eval = e_eval_from_string(scratch.arena, expr); - E_Eval value_eval = e_value_eval_from_eval(eval); - min_digits = (U32)value_eval.value.u64; - } - } - if(eval.space.kind == RD_EvalSpaceKind_MetaEntity || - eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity) - { - E_TypeKind kind = e_type_kind_from_key(eval.type_key); - if(kind != E_TypeKind_Ptr) - { - no_addr = 1; - } - else - { - E_Type *type = e_type_from_key(scratch.arena, eval.type_key); - if(!(type->flags & E_TypeFlag_External)) - { - no_addr = 1; - } - } - } - - //- rjf: member evaluations -> display member info - if(eval.mode == E_Mode_Null && !e_type_key_match(e_type_key_zero(), eval.type_key) && member != &e_member_nil) - { - U64 member_byte_size = e_type_byte_size_from_key(eval.type_key); - String8 offset_string = str8_from_u64(arena, member->off, radix, 0, 0); - String8 size_string = str8_from_u64(arena, member_byte_size, radix, 0, 0); - str8_list_pushf(arena, out, "member (%S offset, %S byte%s)", offset_string, size_string, member_byte_size == 1 ? "" : "s"); - } - - //- rjf: type evaluations -> display type basic information - else if(eval.mode == E_Mode_Null && !e_type_key_match(e_type_key_zero(), eval.type_key) && eval.expr->kind != E_ExprKind_MemberAccess) - { - String8 basic_type_kind_string = e_kind_basic_string_table[e_type_kind_from_key(eval.type_key)]; - U64 byte_size = e_type_byte_size_from_key(eval.type_key); - String8 size_string = str8_from_u64(arena, byte_size, radix, 0, 0); - str8_list_pushf(arena, out, "%S (%S byte%s)", basic_type_kind_string, size_string, byte_size == 1 ? "" : "s"); - } - - //- rjf: value/offset evaluations - else if(max_size > 0) switch(e_type_kind_from_key(e_type_unwrap(eval.type_key))) - { - //- rjf: default - leaf cases - default: - { - E_Eval value_eval = e_value_eval_from_eval(eval); - String8 string = ev_string_from_simple_typed_eval(arena, flags, radix, min_digits, value_eval); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string).x; - str8_list_push(arena, out, string); - }break; - - //- rjf: pointers - case E_TypeKind_Function: - case E_TypeKind_Ptr: - case E_TypeKind_LRef: - case E_TypeKind_RRef: - { - // rjf: unpack type info - E_TypeKind type_kind = e_type_kind_from_key(e_type_unwrap(eval.type_key)); - E_TypeKey direct_type_key = e_type_unwrap(e_type_ptee_from_key(e_type_unwrap(eval.type_key))); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - - // rjf: unpack info about pointer destination - E_Eval value_eval = e_value_eval_from_eval(eval); - B32 ptee_has_content = (direct_type_kind != E_TypeKind_Null && direct_type_kind != E_TypeKind_Void); - B32 ptee_has_string = ((E_TypeKind_Char8 <= direct_type_kind && direct_type_kind <= E_TypeKind_UChar32) || - direct_type_kind == E_TypeKind_S8 || - direct_type_kind == E_TypeKind_U8); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - String8 symbol_name = d_symbol_name_from_process_vaddr(arena, process, value_eval.value.u64, 1); - - // rjf: special case: push strings for textual string content - B32 did_content = 0; - B32 did_string = 0; - if(!did_content && ptee_has_string && !no_string) - { - did_content = 1; - did_string = 1; - U64 string_memory_addr = value_eval.value.u64; - U64 element_size = e_type_byte_size_from_key(direct_type_key); - U64 string_buffer_size = 256; - U8 *string_buffer = push_array(arena, U8, string_buffer_size); - for(U64 try_size = string_buffer_size; try_size >= 16; try_size /= 2) - { - B32 read_good = e_space_read(eval.space, string_buffer, r1u64(string_memory_addr, string_memory_addr+try_size)); - if(read_good) - { - break; - } - } - string_buffer[string_buffer_size-1] = 0; - String8 string = {0}; - switch(element_size) - { - default:{string = str8_cstring((char *)string_buffer);}break; - case 2: {string = str8_from_16(arena, str16_cstring((U16 *)string_buffer));}break; - case 4: {string = str8_from_32(arena, str32_cstring((U32 *)string_buffer));}break; - } - String8 string_escaped = ev_escaped_from_raw_string(arena, string); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string_escaped).x; - space_taken += 2*fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_lit("\"")).x; - str8_list_push(arena, out, str8_lit("\"")); - str8_list_push(arena, out, string_escaped); - str8_list_push(arena, out, str8_lit("\"")); - } - - // rjf: special case: push strings for symbols - if(value_eval.value.u64 != 0 && - !did_content && symbol_name.size != 0 && - flags & EV_StringFlag_ReadOnlyDisplayRules && - ((type_kind == E_TypeKind_Ptr && direct_type_kind == E_TypeKind_Void) || - (type_kind == E_TypeKind_Ptr && direct_type_kind == E_TypeKind_Function) || - (type_kind == E_TypeKind_Function))) - { - did_content = 1; - str8_list_push(arena, out, symbol_name); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, symbol_name).x; - } - - // rjf: special case: need symbol name, don't have one - if(value_eval.value.u64 != 0 && - !did_content && symbol_name.size == 0 && - flags & EV_StringFlag_ReadOnlyDisplayRules && - ((type_kind == E_TypeKind_Ptr && direct_type_kind == E_TypeKind_Function) || - (type_kind == E_TypeKind_Function)) && - (flags & EV_StringFlag_ReadOnlyDisplayRules)) - { - did_content = 1; - String8 string = str8_lit("???"); - str8_list_push(arena, out, string); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string).x; - } - - // rjf: push pointer value - B32 did_ptr_value = 0; - if(!no_addr || value_eval.value.u64 == 0) - { - did_ptr_value = 1; - if(did_content) - { - String8 left_paren = str8_lit(" ("); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, left_paren).x; - str8_list_push(arena, out, left_paren); - } - String8 string = ev_string_from_simple_typed_eval(arena, flags, radix, min_digits, value_eval); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string).x; - str8_list_push(arena, out, string); - if(did_content) - { - String8 right_paren = str8_lit(")"); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, right_paren).x; - str8_list_push(arena, out, right_paren); - } - } - - // rjf: descend for all other cases - B32 did_arrow = 0; - if(value_eval.value.u64 != 0 && !did_content && ptee_has_content && (flags & EV_StringFlag_ReadOnlyDisplayRules)) - { - if(did_ptr_value && !did_arrow) - { - did_arrow = 1; - String8 arrow = str8_lit(" -> "); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, arrow).x; - str8_list_push(arena, out, arrow); - } - did_content = 1; - if(depth < 4) - { - E_Expr *deref_expr = e_expr_ref_deref(scratch.arena, eval.expr); - E_Eval deref_eval = e_eval_from_expr(scratch.arena, deref_expr); - space_taken += rd_append_value_strings_from_eval(arena, flags, radix, font, font_size, max_size-space_taken, depth+1, deref_eval, 0, view_rules, out); - } - else - { - String8 ellipses = str8_lit("..."); - str8_list_push(arena, out, ellipses); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, ellipses).x; - } - } - }break; - - //- rjf: arrays - case E_TypeKind_Array: - { - // rjf: unpack type info - E_Type *eval_type = e_type_from_key(scratch.arena, e_type_unwrap(eval.type_key)); - E_TypeKey direct_type_key = e_type_unwrap(eval_type->direct_type_key); - E_TypeKind direct_type_kind = e_type_kind_from_key(direct_type_key); - U64 array_count = eval_type->count; - - // rjf: get pointed-at type - B32 array_is_string = ((E_TypeKind_Char8 <= direct_type_kind && direct_type_kind <= E_TypeKind_UChar32) || - direct_type_kind == E_TypeKind_S8 || - direct_type_kind == E_TypeKind_U8); - - // rjf: special case: push strings for textual string content - B32 did_content = 0; - if(!did_content && array_is_string && !no_string && (member == 0 || member->kind != E_MemberKind_Padding)) - { - U64 element_size = e_type_byte_size_from_key(direct_type_key); - did_content = 1; - U64 string_buffer_size = Clamp(1, array_count, 1024); - U8 *string_buffer = push_array(arena, U8, string_buffer_size); - switch(eval.mode) - { - default:{}break; - case E_Mode_Offset: - { - U64 string_memory_addr = eval.value.u64; - B32 read_good = e_space_read(eval.space, string_buffer, r1u64(string_memory_addr, string_memory_addr+string_buffer_size)); - }break; - case E_Mode_Value: - { - MemoryCopy(string_buffer, &eval.value.u512[0], Min(string_buffer_size, sizeof(eval.value))); - }break; - } - String8 string = {0}; - switch(element_size) - { - default:{string = str8_cstring_capped(string_buffer, string_buffer + string_buffer_size);}break; - case 2: {string = str8_from_16(arena, str16_cstring_capped(string_buffer, string_buffer + string_buffer_size));}break; - case 4: {string = str8_from_32(arena, str32_cstring((U32 *)string_buffer));}break; - } - String8 string_escaped = ev_escaped_from_raw_string(arena, string); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string_escaped).x; - space_taken += 2*fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_lit("\"")).x; - str8_list_push(arena, out, str8_lit("\"")); - str8_list_push(arena, out, string_escaped); - str8_list_push(arena, out, str8_lit("\"")); - } - - // rjf: descend in all other cases - if(!did_content && (flags & EV_StringFlag_ReadOnlyDisplayRules)) - { - did_content = 1; - - // rjf: [ - { - String8 bracket = str8_lit("["); - str8_list_push(arena, out, bracket); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, bracket).x; - } - - // rjf: build contents - if(depth < 4) - { - for(U64 idx = 0; idx < array_count && max_size > space_taken; idx += 1) - { - E_Expr *element_expr = e_expr_ref_array_index(scratch.arena, eval.expr, idx); - E_Eval element_eval = e_eval_from_expr(scratch.arena, element_expr); - space_taken += rd_append_value_strings_from_eval(arena, flags, radix, font, font_size, max_size-space_taken, depth+1, element_eval, 0, view_rules, out); - if(idx+1 < array_count) - { - String8 comma = str8_lit(", "); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, comma).x; - str8_list_push(arena, out, comma); - } - if(space_taken > max_size && idx+1 < array_count) - { - String8 ellipses = str8_lit("..."); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, ellipses).x; - str8_list_push(arena, out, ellipses); - } - } - } - else - { - String8 ellipses = str8_lit("..."); - str8_list_push(arena, out, ellipses); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, ellipses).x; - } - - // rjf: ] - { - String8 bracket = str8_lit("]"); - str8_list_push(arena, out, bracket); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, bracket).x; - } - } - }break; - - //- rjf: structs - case E_TypeKind_Struct: - case E_TypeKind_Union: - case E_TypeKind_Class: - case E_TypeKind_IncompleteStruct: - case E_TypeKind_IncompleteUnion: - case E_TypeKind_IncompleteClass: - { - // rjf: open brace - { - String8 brace = str8_lit("{"); - str8_list_push(arena, out, brace); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, brace).x; - } - - // rjf: content - if(depth < 4) - { - E_MemberArray data_members = e_type_data_members_from_key__cached(e_type_unwrap(eval.type_key)); - for(U64 member_idx = 0; member_idx < data_members.count && max_size > space_taken; member_idx += 1) - { - E_Member *mem = &data_members.v[member_idx]; - E_Expr *dot_expr = e_expr_ref_member_access(scratch.arena, eval.expr, mem->name); - E_Expr *dot_expr_resolved = ev_resolved_from_expr(scratch.arena, dot_expr, view_rules); - E_Eval dot_eval = e_eval_from_expr(scratch.arena, dot_expr_resolved); - space_taken += rd_append_value_strings_from_eval(arena, flags, radix, font, font_size, max_size-space_taken, depth+1, dot_eval, 0, view_rules, out); - if(member_idx+1 < data_members.count) - { - String8 comma = str8_lit(", "); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, comma).x; - str8_list_push(arena, out, comma); - } - if(space_taken > max_size && member_idx+1 < data_members.count) - { - String8 ellipses = str8_lit("..."); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, ellipses).x; - str8_list_push(arena, out, ellipses); - } - } - } - else - { - String8 ellipses = str8_lit("..."); - str8_list_push(arena, out, ellipses); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, ellipses).x; - } - - // rjf: close brace - { - String8 brace = str8_lit("}"); - str8_list_push(arena, out, brace); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, brace).x; - } - }break; - - //- rjf: collections - case E_TypeKind_Collection: - { - String8 placeholder = str8_lit("{...}"); - str8_list_push(arena, out, placeholder); - space_taken += fnt_dim_from_tag_size_string(font, font_size, 0, 0, placeholder).x; - }break; - } - - scratch_end(scratch); - ProfEnd(); - return space_taken; -} - internal String8 -rd_value_string_from_eval(Arena *arena, EV_StringFlags flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size, E_Eval eval, E_Member *member, EV_ViewRuleList *view_rules) +rd_value_string_from_eval(Arena *arena, String8 filter, EV_StringParams *params, FNT_Tag font, F32 font_size, F32 max_size, E_Eval eval) { Temp scratch = scratch_begin(&arena, 1); String8List strs = {0}; - rd_append_value_strings_from_eval(scratch.arena, flags, default_radix, font, font_size, max_size, 0, eval, member, view_rules, &strs); + { + EV_StringIter *iter = ev_string_iter_begin(scratch.arena, eval, params); + F32 space_taken_px = 0; + for(String8 string = {0}; ev_string_iter_next(scratch.arena, iter, &string);) + { + if(space_taken_px > max_size) + { + str8_list_push(scratch.arena, &strs, str8_lit("...")); + break; + } + else + { + str8_list_push(scratch.arena, &strs, string); + space_taken_px += fnt_dim_from_tag_size_string(font, font_size, 0, 0, string).x; + } + } + } String8 result = str8_list_join(arena, &strs, 0); scratch_end(scratch); return result; @@ -9759,538 +9914,351 @@ rd_value_string_from_eval(Arena *arena, EV_StringFlags flags, U32 default_radix, //~ rjf: Hover Eval internal void -rd_set_hover_eval(Vec2F32 pos, String8 file_path, TxtPt pt, U64 vaddr, String8 string) +rd_set_hover_eval(Vec2F32 pos, String8 string) { - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window->hover_eval_last_frame_idx+1 < rd_state->frame_index && + RD_Cfg *window_cfg = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window_cfg); + if(ws->hover_eval_lastt_us < rd_state->time_in_us && ui_key_match(ui_active_key(UI_MouseButtonKind_Left), ui_key_zero()) && ui_key_match(ui_active_key(UI_MouseButtonKind_Middle), ui_key_zero()) && ui_key_match(ui_active_key(UI_MouseButtonKind_Right), ui_key_zero())) { - B32 is_new_string = !str8_match(window->hover_eval_string, string, 0); + B32 is_new_string = (!str8_match(ws->hover_eval_string, string, 0)); if(is_new_string) { - window->hover_eval_first_frame_idx = window->hover_eval_last_frame_idx = rd_state->frame_index; - arena_clear(window->hover_eval_arena); - window->hover_eval_string = push_str8_copy(window->hover_eval_arena, string); - window->hover_eval_file_path = push_str8_copy(window->hover_eval_arena, file_path); - window->hover_eval_file_pt = pt; - window->hover_eval_vaddr = vaddr; - window->hover_eval_focused = 0; + ws->hover_eval_firstt_us = ws->hover_eval_lastt_us = rd_state->time_in_us; + arena_clear(ws->hover_eval_arena); + ws->hover_eval_string = push_str8_copy(ws->hover_eval_arena, string); + ws->hover_eval_focused = 0; } - window->hover_eval_spawn_pos = pos; - window->hover_eval_last_frame_idx = rd_state->frame_index; + ws->hover_eval_spawn_pos = pos; + ws->hover_eval_lastt_us = rd_state->time_in_us; } } //////////////////////////////// -//~ rjf: Auto-Complete Lister +//~ rjf: Autocompletion Lister internal void -rd_autocomp_lister_item_chunk_list_push(Arena *arena, RD_AutoCompListerItemChunkList *list, U64 cap, RD_AutoCompListerItem *item) +rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs) { - RD_AutoCompListerItemChunkNode *n = list->last; - if(n == 0 || n->count >= n->cap) + RD_Cfg *window_cfg = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window_cfg); + if(ws->autocomp_last_frame_index < rd_state->frame_index) { - n = push_array(arena, RD_AutoCompListerItemChunkNode, 1); - SLLQueuePush(list->first, list->last, n); - n->cap = cap; - n->v = push_array_no_zero(arena, RD_AutoCompListerItem, n->cap); - list->chunk_count += 1; - } - MemoryCopyStruct(&n->v[n->count], item); - n->count += 1; - list->total_count += 1; -} - -internal RD_AutoCompListerItemArray -rd_autocomp_lister_item_array_from_chunk_list(Arena *arena, RD_AutoCompListerItemChunkList *list) -{ - RD_AutoCompListerItemArray array = {0}; - array.count = list->total_count; - array.v = push_array_no_zero(arena, RD_AutoCompListerItem, array.count); - U64 idx = 0; - for(RD_AutoCompListerItemChunkNode *n = list->first; n != 0; n = n->next) - { - MemoryCopy(array.v+idx, n->v, sizeof(RD_AutoCompListerItem)*n->count); - idx += n->count; - } - return array; -} - -internal int -rd_autocomp_lister_item_qsort_compare(RD_AutoCompListerItem *a, RD_AutoCompListerItem *b) -{ - int result = 0; - if(a->group < b->group) - { - result = -1; - } - else if(a->group > b->group) - { - result = +1; - } - else if(a->matches.count > b->matches.count) - { - result = -1; - } - else if(a->matches.count < b->matches.count) - { - result = +1; - } - else if(a->string.size < b->string.size) - { - result = -1; - } - else if(a->string.size > b->string.size) - { - result = +1; - } - else - { - result = strncmp((char *)a->string.str, (char *)b->string.str, Min(a->string.size, b->string.size)); - } - return result; -} - -internal void -rd_autocomp_lister_item_array_sort__in_place(RD_AutoCompListerItemArray *array) -{ - quick_sort(array->v, array->count, sizeof(array->v[0]), rd_autocomp_lister_item_qsort_compare); -} - -internal String8 -rd_autocomp_query_word_from_input_string_off(String8 input, U64 cursor_off) -{ - U64 word_start_off = 0; - for(U64 off = 0; off < input.size && off < cursor_off; off += 1) - { - if(!char_is_alpha(input.str[off]) && !char_is_digit(input.str[off], 10) && input.str[off] != '_') - { - word_start_off = off+1; - } - } - String8 query = str8_skip(str8_prefix(input, cursor_off), word_start_off); - return query; -} - -internal String8 -rd_autocomp_query_path_from_input_string_off(String8 input, U64 cursor_off) -{ - // rjf: find start of path - U64 path_start_off = 0; - { - B32 single_quoted = 0; - B32 double_quoted = 0; - for(U64 off = 0; off < input.size && off < cursor_off; off += 1) - { - if(input.str[off] == '\'') - { - single_quoted ^= 1; - } - if(input.str[off] == '\"') - { - double_quoted ^= 1; - } - if(char_is_space(input.str[off]) && !single_quoted && !double_quoted) - { - path_start_off = off+1; - } - } - } - - // rjf: form path - String8 path = str8_skip(str8_prefix(input, cursor_off), path_start_off); - if(path.size >= 1 && path.str[0] == '"') { path = str8_skip(path, 1); } - if(path.size >= 1 && path.str[0] == '\'') { path = str8_skip(path, 1); } - if(path.size >= 1 && path.str[path.size-1] == '"') { path = str8_chop(path, 1); } - if(path.size >= 1 && path.str[path.size-1] == '\'') { path = str8_chop(path, 1); } - return path; -} - -internal RD_AutoCompListerParams -rd_view_rule_autocomp_lister_params_from_input_cursor(Arena *arena, String8 string, U64 cursor_off) -{ - RD_AutoCompListerParams params = {0}; - { - Temp scratch = scratch_begin(&arena, 1); + arena_clear(ws->autocomp_arena); - //- rjf: do partial parse of input - MD_TokenizeResult input_tokenize = md_tokenize_from_text(scratch.arena, string); - - //- rjf: find descension steps to cursor - typedef struct DescendStep DescendStep; - struct DescendStep + //- rjf: calculate information about the cursor: + // * what list should we generate? + // * what string in the input should we replace? + // etc. + B32 is_allowed = 0; + RD_AutocompCursorInfo cursor_info = {0}; { - DescendStep *next; - DescendStep *prev; - String8 string; - }; - DescendStep *first_step = 0; - DescendStep *last_step = 0; - DescendStep *free_step = 0; - S32 paren_nest = 0; - S32 colon_nest = 0; - String8 last_step_string = {0}; - for(U64 idx = 0; idx < input_tokenize.tokens.count; idx += 1) - { - MD_Token *token = &input_tokenize.tokens.v[idx]; - if(token->range.min >= cursor_off) + Temp scratch = scratch_begin(0, 0); + + // rjf: calculate most general list expression, given the dst_eval space + B32 force_allow = 0; + B32 expr_based_replace = 1; + String8 list_expr = str8_lit("query:locals, query:globals, query:thread_locals, query:procedures, query:types"); { - break; - } - String8 token_string = str8_substr(string, token->range); - if(token->flags & (MD_TokenFlag_Identifier|MD_TokenFlag_StringLiteral)) - { - last_step_string = token_string; - } - if(str8_match(token_string, str8_lit("("), 0) || str8_match(token_string, str8_lit("["), 0) || str8_match(token_string, str8_lit("{"), 0)) - { - paren_nest += 1; - } - if(str8_match(token_string, str8_lit(")"), 0) || str8_match(token_string, str8_lit("]"), 0) || str8_match(token_string, str8_lit("}"), 0)) - { - paren_nest -= 1; - for(;colon_nest > paren_nest; colon_nest -= 1) + E_TypeKey maybe_enum_type = e_type_key_unwrap(dst_eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative & ~E_TypeUnwrapFlag_Enums); + if(dst_eval.space.kind == RD_EvalSpaceKind_MetaCfg) { - if(last_step != 0) + RD_Cfg *parent = rd_cfg_from_eval_space(dst_eval.space); + String8 child_key = e_string_from_id(dst_eval.space.u64s[1]); + MD_NodePtrList schemas = rd_schemas_from_name(parent->string); + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = schemas.first; n != 0 && md_node_is_nil(child_schema); n = n->next) { - DescendStep *step = last_step; - DLLRemove(first_step, last_step, step); - SLLStackPush(free_step, step); + child_schema = md_child_from_string(n->v, child_key, 0); } - } - if(paren_nest == 0 && last_step != 0) - { - DescendStep *step = last_step; - DLLRemove(first_step, last_step, step); - SLLStackPush(free_step, step); - } - } - if(str8_match(token_string, str8_lit(":"), 0)) - { - colon_nest += 1; - if(last_step_string.size != 0) - { - DescendStep *step = free_step; - if(step != 0) + if(str8_match(child_key, str8_lit("theme"), 0)) { - SLLStackPop(free_step); - MemoryZeroStruct(step); + list_expr = str8_lit("query:themes"); + expr_based_replace = 0; + force_allow = 1; } - else + else if(!str8_match(child_schema->first->string, str8_lit("expr_string"), 0)) { - step = push_array(scratch.arena, DescendStep, 1); - } - step->string = last_step_string; - DLLPushBack(first_step, last_step, step); - } - } - if(str8_match(token_string, str8_lit(";"), 0) || str8_match(token_string, str8_lit(","), 0)) - { - for(;colon_nest > paren_nest; colon_nest -= 1) - { - if(last_step != 0) - { - DescendStep *step = last_step; - DLLRemove(first_step, last_step, step); - SLLStackPush(free_step, step); + MemoryZeroStruct(&list_expr); } } } - } - - //- rjf: map view rule root to spec - D_ViewRuleSpec *spec = d_view_rule_spec_from_string(first_step ? first_step->string : str8_zero()); - - //- rjf: do parse of schema - MD_TokenizeResult schema_tokenize = md_tokenize_from_text(scratch.arena, spec->info.schema); - MD_ParseResult schema_parse = md_parse_from_text_tokens(scratch.arena, str8_zero(), spec->info.schema, schema_tokenize.tokens); - MD_Node *schema_rule_root = md_child_from_string(schema_parse.root, str8_lit("x"), 0); - - //- rjf: follow schema according to descend steps, gather flags from schema node matching cursor descension steps - if(first_step != 0) - { - MD_Node *schema_node = schema_rule_root; - for(DescendStep *step = first_step->next;;) + + // rjf: determine if autocompletion lister is allowed + is_allowed = (force_allow || rd_setting_b32_from_name(str8_lit("autocompletion_lister"))); + + // rjf: tighten list_expr, and filter / replaced-range, if needed + String8 filter = regs->string; + Rng1U64 replaced_range = r1u64(0, filter.size); + String8 callee_expr = {0}; + U64 cursor_arg_idx = 0; + if(expr_based_replace) { - if(step == 0) + U64 cursor_off = (U64)(regs->cursor.column-1); + E_Parse parse = e_parse_from_string(regs->string); + + //- rjf: cursor offset -> cursor containing node + E_Expr *cursor_expr = &e_expr_nil; + E_Expr *cursor_expr_parent = &e_expr_nil; { - for MD_EachNode(child, schema_node->first) + typedef struct ExprWalkTask ExprWalkTask; + struct ExprWalkTask { - if(0){} - else if(str8_match(child->string, str8_lit("expr"), StringMatchFlag_CaseInsensitive)) {params.flags |= RD_AutoCompListerFlag_Locals;} - else if(str8_match(child->string, str8_lit("member"), StringMatchFlag_CaseInsensitive)) {params.flags |= RD_AutoCompListerFlag_Members;} - else if(str8_match(child->string, str8_lit("lang"), StringMatchFlag_CaseInsensitive)) {params.flags |= RD_AutoCompListerFlag_Languages;} - else if(str8_match(child->string, str8_lit("arch"), StringMatchFlag_CaseInsensitive)) {params.flags |= RD_AutoCompListerFlag_Architectures;} - else if(str8_match(child->string, str8_lit("tex2dformat"), StringMatchFlag_CaseInsensitive)) {params.flags |= RD_AutoCompListerFlag_Tex2DFormats;} - else if(child->flags & (MD_NodeFlag_StringSingleQuote|MD_NodeFlag_StringDoubleQuote|MD_NodeFlag_StringTick)) + ExprWalkTask *next; + E_Expr *parent; + E_Expr *expr; + S32 depth; + }; + ExprWalkTask start_task = {0, &e_expr_nil, parse.expr}; + ExprWalkTask *first_task = &start_task; + ExprWalkTask *last_task = first_task; + S32 best_depth = 0; + for(E_Expr *chain = parse.expr->next; chain != &e_expr_nil; chain = chain->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + SLLQueuePush(first_task, last_task, task); + task->parent = &e_expr_nil; + task->expr = chain; + } + for(ExprWalkTask *t = first_task; t != 0; t = t->next) + { + E_Expr *e = t->expr; + if(t->depth >= best_depth && (contains_1u64(e->range, cursor_off) || cursor_off == e->range.max)) { - str8_list_push(arena, ¶ms.strings, child->string); - params.flags |= RD_AutoCompListerFlag_ViewRuleParams; + cursor_expr_parent = t->parent; + cursor_expr = e; + best_depth = t->depth; + } + for(E_Expr *child = e->first; child != &e_expr_nil; child = child->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + SLLQueuePush(first_task, last_task, task); + task->parent = e; + task->expr = child; + task->depth = t->depth+1; } } - break; } - if(step != 0) + + //- rjf: cursor is within a call? -> generate an expression for the callee, determine + // which argument the cursor is on + if(cursor_expr_parent->kind == E_ExprKind_Call) { - MD_Node *next_node = md_child_from_string(schema_node, step->string, StringMatchFlag_CaseInsensitive); - schema_node = next_node; - step = step->next; + E_Key callee_key = e_key_from_expr(cursor_expr_parent->first); + callee_expr = e_full_expr_string_from_key(scratch.arena, callee_key); + for(E_Expr *arg = cursor_expr->prev; arg != cursor_expr_parent->first && arg != &e_expr_nil; arg = arg->prev) + { + cursor_arg_idx += 1; + } } - else + else if(cursor_expr->kind == E_ExprKind_Call) { - schema_node = schema_node->first; + E_Key callee_key = e_key_from_expr(cursor_expr->first); + callee_expr = e_full_expr_string_from_key(scratch.arena, callee_key); + for(E_Expr *arg = cursor_expr->first->next; arg != &e_expr_nil; arg = arg->next) + { + cursor_arg_idx += 1; + } + } + + //- rjf: cursor is on right-hand-side of dot? -> show members of left-hand-side + B32 did_special_cursor_case = 0; + if(!did_special_cursor_case) + { + E_Expr *dot_expr = &e_expr_nil; + if(cursor_expr->kind == E_ExprKind_MemberAccess && cursor_off == cursor_expr->range.max) + { + dot_expr = cursor_expr; + } + else if(cursor_expr_parent->kind == E_ExprKind_MemberAccess && cursor_expr == cursor_expr_parent->first->next) + { + dot_expr = cursor_expr_parent; + } + if(dot_expr != &e_expr_nil) + { + did_special_cursor_case = 1; + E_Eval lhs_eval = e_eval_from_expr(dot_expr->first); + E_Eval type_of_lhs_eval = e_eval_wrapf(lhs_eval, "typeof($)"); + list_expr = e_full_expr_string_from_key(scratch.arena, type_of_lhs_eval.key); + filter = cursor_expr->string; + replaced_range = union_1u64(dot_expr->range, cursor_expr->range); + } + } + + //- rjf: cursor is on a leaf-identifier? -> replace just that identifier, keep the original list expression + if(!did_special_cursor_case && cursor_expr->kind == E_ExprKind_LeafIdentifier) + { + did_special_cursor_case = 1; + filter = str8_prefix(cursor_expr->string, cursor_off - cursor_expr->range.min); + replaced_range = cursor_expr->range; } } + + // rjf: try to map the cursor, within a call, to some schema + MD_Node *arg_schema = &md_nil_node; + if(callee_expr.size != 0) + { + E_Eval callee_eval = e_eval_from_string(callee_expr); + E_Type *callee_type = e_type_from_key(callee_eval.irtree.type_key); + if(callee_type->kind == E_TypeKind_LensSpec) + { + U64 arg_idx = 0; + MD_NodePtrList schemas = rd_schemas_from_name(callee_type->name); + for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + for MD_EachNode(child, schema->first) + { + if(!md_node_has_tag(child, str8_lit("no_callee_helper"), 0)) + { + if(cursor_arg_idx == arg_idx) + { + arg_schema = child; + goto end_schema_search; + } + arg_idx += 1; + } + } + } + end_schema_search:; + } + } + + // rjf: fill bundle + cursor_info.list_expr = push_str8_copy(ws->autocomp_arena, list_expr); + cursor_info.filter = push_str8_copy(ws->autocomp_arena, filter); + cursor_info.replaced_range = replaced_range; + cursor_info.callee_expr = push_str8_copy(ws->autocomp_arena, callee_expr); + cursor_info.arg_schema = arg_schema; + + scratch_end(scratch); } - scratch_end(scratch); + //- rjf: commit autocompletion info + if(is_allowed) + { + ws->autocomp_last_frame_index = rd_state->frame_index; + ws->autocomp_regs = rd_regs_copy(ws->autocomp_arena, regs); + ws->autocomp_cursor_info = cursor_info; + } } - return params; -} - -internal void -rd_set_autocomp_lister_query(UI_Key root_key, RD_AutoCompListerParams *params, String8 input, U64 cursor_off) -{ - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(cursor_off != window->autocomp_cursor_off) - { - window->autocomp_input_dirty = 1; - window->autocomp_cursor_off = cursor_off; - } - if(!ui_key_match(window->autocomp_root_key, root_key)) - { - window->autocomp_num_visible_rows_t = 0; - window->autocomp_open_t = 0; - } - if(window->autocomp_last_frame_idx+1 < rd_state->frame_index) - { - window->autocomp_num_visible_rows_t = 0; - window->autocomp_open_t = 0; - } - window->autocomp_root_key = root_key; - arena_clear(window->autocomp_lister_params_arena); - MemoryCopyStruct(&window->autocomp_lister_params, params); - window->autocomp_lister_params.strings = str8_list_copy(window->autocomp_lister_params_arena, &window->autocomp_lister_params.strings); - window->autocomp_lister_input_size = Min(input.size, sizeof(window->autocomp_lister_input_buffer)); - MemoryCopy(window->autocomp_lister_input_buffer, input.str, window->autocomp_lister_input_size); - window->autocomp_last_frame_idx = rd_state->frame_index; -} - -//////////////////////////////// -//~ rjf: Search Strings - -internal void -rd_set_search_string(String8 string) -{ - arena_clear(rd_state->string_search_arena); - rd_state->string_search_string = push_str8_copy(rd_state->string_search_arena, string); -} - -internal String8 -rd_push_search_string(Arena *arena) -{ - String8 result = push_str8_copy(arena, rd_state->string_search_string); - return result; } //////////////////////////////// //~ rjf: Colors, Fonts, Config -//- rjf: keybindings - -internal OS_Key -rd_os_key_from_cfg_string(String8 string) -{ - OS_Key result = OS_Key_Null; - { - for(OS_Key key = OS_Key_Null; key < OS_Key_COUNT; key = (OS_Key)(key+1)) - { - if(str8_match(string, os_g_key_cfg_string_table[key], StringMatchFlag_CaseInsensitive)) - { - result = key; - break; - } - } - } - return result; -} - -internal void -rd_clear_bindings(void) -{ - arena_clear(rd_state->key_map_arena); - rd_state->key_map_table_size = 1024; - rd_state->key_map_table = push_array(rd_state->key_map_arena, RD_KeyMapSlot, rd_state->key_map_table_size); - rd_state->key_map_total_count = 0; -} - -internal RD_BindingList -rd_bindings_from_name(Arena *arena, String8 name) -{ - RD_BindingList result = {0}; - U64 hash = d_hash_from_string(name); - U64 slot = hash%rd_state->key_map_table_size; - for(RD_KeyMapNode *n = rd_state->key_map_table[slot].first; n != 0; n = n->hash_next) - { - if(str8_match(n->name, name, 0)) - { - RD_BindingNode *node = push_array(arena, RD_BindingNode, 1); - node->binding = n->binding; - SLLQueuePush(result.first, result.last, node); - result.count += 1; - } - } - return result; -} - -internal void -rd_bind_name(String8 name, RD_Binding binding) -{ - if(binding.key != OS_Key_Null) - { - U64 hash = d_hash_from_string(name); - U64 slot = hash%rd_state->key_map_table_size; - RD_KeyMapNode *existing_node = 0; - for(RD_KeyMapNode *n = rd_state->key_map_table[slot].first; n != 0; n = n->hash_next) - { - if(str8_match(n->name, name, 0) && n->binding.key == binding.key && n->binding.modifiers == binding.modifiers) - { - existing_node = n; - break; - } - } - if(existing_node == 0) - { - RD_KeyMapNode *n = rd_state->free_key_map_node; - if(n == 0) - { - n = push_array(rd_state->arena, RD_KeyMapNode, 1); - } - else - { - rd_state->free_key_map_node = rd_state->free_key_map_node->hash_next; - } - n->name = push_str8_copy(rd_state->arena, name); - n->binding = binding; - DLLPushBack_NP(rd_state->key_map_table[slot].first, rd_state->key_map_table[slot].last, n, hash_next, hash_prev); - rd_state->key_map_total_count += 1; - } - } -} - -internal void -rd_unbind_name(String8 name, RD_Binding binding) -{ - U64 hash = d_hash_from_string(name); - U64 slot = hash%rd_state->key_map_table_size; - for(RD_KeyMapNode *n = rd_state->key_map_table[slot].first, *next = 0; n != 0; n = next) - { - next = n->hash_next; - if(str8_match(n->name, name, 0) && n->binding.key == binding.key && n->binding.modifiers == binding.modifiers) - { - DLLRemove_NP(rd_state->key_map_table[slot].first, rd_state->key_map_table[slot].last, n, hash_next, hash_prev); - n->hash_next = rd_state->free_key_map_node; - rd_state->free_key_map_node = n; - rd_state->key_map_total_count -= 1; - } - } -} - -internal String8List -rd_cmd_name_list_from_binding(Arena *arena, RD_Binding binding) -{ - String8List result = {0}; - for(U64 idx = 0; idx < rd_state->key_map_table_size; idx += 1) - { - for(RD_KeyMapNode *n = rd_state->key_map_table[idx].first; n != 0; n = n->hash_next) - { - if(n->binding.key == binding.key && n->binding.modifiers == binding.modifiers) - { - str8_list_push(arena, &result, n->name); - } - } - } - return result; -} - //- rjf: colors -internal Vec4F32 -rd_rgba_from_theme_color(RD_ThemeColor color) +internal MD_Node * +rd_theme_tree_from_name(Arena *arena, HS_Scope *scope, String8 theme_name) { - return rd_state->cfg_theme.colors[color]; + Temp scratch = scratch_begin(&arena, 1); + MD_Node *theme_tree = &md_nil_node; + if(theme_name.size != 0) + { + for EachEnumVal(RD_ThemePreset, p) + { + if(str8_match(theme_name, rd_theme_preset_display_string_table[p], 0)) + { + theme_tree = rd_state->theme_preset_trees[p]; + break; + } + } + if(theme_tree == &md_nil_node) + { + String8 path = push_str8f(scratch.arena, "%S/raddbg/themes/%S", os_get_process_info()->user_program_data_path, theme_name); + U64 endt_us = os_now_microseconds()+100; + if(rd_state->frame_index <= 5) + { + endt_us = os_now_microseconds()+50000; + } + U128 hash = fs_hash_from_path_range(path, r1u64(0, max_U64), endt_us); + String8 data = hs_data_from_hash(scope, hash); + theme_tree = md_tree_from_string(arena, data); + } + } + scratch_end(scratch); + return theme_tree; } -internal RD_ThemeColor -rd_theme_color_from_txt_token_kind(TXT_TokenKind kind) +internal Vec4F32 +rd_rgba_from_code_color_slot(RD_CodeColorSlot slot) { - RD_ThemeColor color = RD_ThemeColor_CodeDefault; + RD_WindowState *ws = rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window)); + Vec4F32 result = ws->theme_code_colors[slot]; + return result; +} + +internal RD_CodeColorSlot +rd_code_color_slot_from_txt_token_kind(TXT_TokenKind kind) +{ + RD_CodeColorSlot color = RD_CodeColorSlot_CodeDefault; switch(kind) { default:break; - case TXT_TokenKind_Keyword:{color = RD_ThemeColor_CodeKeyword;}break; - case TXT_TokenKind_Numeric:{color = RD_ThemeColor_CodeNumeric;}break; - case TXT_TokenKind_String: {color = RD_ThemeColor_CodeString;}break; - case TXT_TokenKind_Meta: {color = RD_ThemeColor_CodeMeta;}break; - case TXT_TokenKind_Comment:{color = RD_ThemeColor_CodeComment;}break; - case TXT_TokenKind_Symbol: {color = RD_ThemeColor_CodeDelimiterOperator;}break; + case TXT_TokenKind_Keyword:{color = RD_CodeColorSlot_CodeKeyword;}break; + case TXT_TokenKind_Numeric:{color = RD_CodeColorSlot_CodeNumeric;}break; + case TXT_TokenKind_String: {color = RD_CodeColorSlot_CodeString;}break; + case TXT_TokenKind_Meta: {color = RD_CodeColorSlot_CodeMeta;}break; + case TXT_TokenKind_Comment:{color = RD_CodeColorSlot_CodeComment;}break; + case TXT_TokenKind_Symbol: {color = RD_CodeColorSlot_CodeDelimiterOperator;}break; } return color; } -internal RD_ThemeColor -rd_theme_color_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string) +internal RD_CodeColorSlot +rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string) { - RD_ThemeColor color = RD_ThemeColor_CodeDefault; + RD_CodeColorSlot color = RD_CodeColorSlot_CodeDefault; if(kind == TXT_TokenKind_Identifier || kind == TXT_TokenKind_Keyword) { - CTRL_Entity *module = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->module); + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); B32 mapped = 0; // rjf: try to map as local if(!mapped && kind == TXT_TokenKind_Identifier) { - U64 local_num = e_num_from_string(e_parse_ctx->locals_map, string); + U64 local_num = e_num_from_string(e_ir_ctx->locals_map, string); if(local_num != 0) { mapped = 1; - color = RD_ThemeColor_CodeLocal; + color = RD_CodeColorSlot_CodeLocal; } } // rjf: try to map as member if(!mapped && kind == TXT_TokenKind_Identifier) { - U64 member_num = e_num_from_string(e_parse_ctx->member_map, string); + U64 member_num = e_num_from_string(e_ir_ctx->member_map, string); if(member_num != 0) { mapped = 1; - color = RD_ThemeColor_CodeLocal; + color = RD_CodeColorSlot_CodeLocal; } } // rjf: try to map as register if(!mapped) { - U64 reg_num = e_num_from_string(e_parse_ctx->regs_map, string); + U64 reg_num = e_num_from_string(e_ir_ctx->regs_map, string); if(reg_num != 0) { mapped = 1; - color = RD_ThemeColor_CodeRegister; + color = RD_CodeColorSlot_CodeRegister; } } // rjf: try to map as register alias if(!mapped) { - U64 alias_num = e_num_from_string(e_parse_ctx->reg_alias_map, string); + U64 alias_num = e_num_from_string(e_ir_ctx->reg_alias_map, string); if(alias_num != 0) { mapped = 1; - color = RD_ThemeColor_CodeRegister; + color = RD_CodeColorSlot_CodeRegister; } } @@ -10306,686 +10274,44 @@ rd_theme_color_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 str case RDI_SectionKind_GlobalVariables: case RDI_SectionKind_ThreadVariables: { - color = RD_ThemeColor_CodeSymbol; + color = RD_CodeColorSlot_CodeSymbol; }break; case RDI_SectionKind_TypeNodes: { - color = RD_ThemeColor_CodeType; + color = RD_CodeColorSlot_CodeType; }break; } } - -#if 0 - // rjf: try to map as symbol - if(!mapped && kind == TXT_TokenKind_Identifier) - { - U64 voff = d_voff_from_dbgi_key_symbol_name(&dbgi_key, string); - if(voff != 0) - { - mapped = 1; - color = RD_ThemeColor_CodeSymbol; - } - } - - // rjf: try to map as type - if(!mapped && kind == TXT_TokenKind_Identifier) - { - U64 type_num = d_type_num_from_dbgi_key_name(&dbgi_key, string); - if(type_num != 0) - { - mapped = 1; - color = RD_ThemeColor_CodeType; - } - } -#endif } return color; } -//- rjf: code -> palette - -internal UI_Palette * -rd_palette_from_code(RD_PaletteCode code) -{ - RD_Window *window = rd_window_from_handle(rd_regs()->window); - UI_Palette *result = &window->cfg_palettes[code]; - return result; -} - //- rjf: fonts/sizes +internal F32 +rd_font_size(void) +{ + F32 size = rd_setting_f32_from_name(str8_lit("font_size")); + size = Clamp(6.f, size, 72.f); + return size; +} + internal FNT_Tag rd_font_from_slot(RD_FontSlot slot) { - FNT_Tag result = rd_state->cfg_font_tags[slot]; - return result; -} - -internal F32 -rd_font_size_from_slot(RD_FontSlot slot) -{ - F32 result = 0; - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - F32 dpi = os_dpi_from_window(ws->os); - if(dpi != ws->last_dpi) - { - F32 old_dpi = ws->last_dpi; - F32 new_dpi = dpi; - ws->last_dpi = dpi; - S32 *pt_sizes[] = - { - &ws->setting_vals[RD_SettingCode_MainFontSize].s32, - &ws->setting_vals[RD_SettingCode_CodeFontSize].s32, - }; - for(U64 idx = 0; idx < ArrayCount(pt_sizes); idx += 1) - { - F32 ratio = pt_sizes[idx][0] / old_dpi; - F32 new_pt_size = ratio*new_dpi; - pt_sizes[idx][0] = (S32)new_pt_size; - } - } - switch(slot) - { - case RD_FontSlot_Code: - { - result = (F32)ws->setting_vals[RD_SettingCode_CodeFontSize].s32; - }break; - default: - case RD_FontSlot_Main: - case RD_FontSlot_Icons: - { - result = (F32)ws->setting_vals[RD_SettingCode_MainFontSize].s32; - }break; - } - return result; + FNT_Tag tag = rd_state->font_slot_table[slot]; + return tag; } internal FNT_RasterFlags rd_raster_flags_from_slot(RD_FontSlot slot) { - FNT_RasterFlags flags = FNT_RasterFlag_Smooth|FNT_RasterFlag_Hinted; - switch(slot) - { - default:{}break; - case RD_FontSlot_Icons:{flags = FNT_RasterFlag_Smooth;}break; - case RD_FontSlot_Main: {flags = (!!rd_setting_val_from_code(RD_SettingCode_SmoothUIText).s32*FNT_RasterFlag_Smooth)|(!!rd_setting_val_from_code(RD_SettingCode_HintUIText).s32*FNT_RasterFlag_Hinted);}break; - case RD_FontSlot_Code: {flags = (!!rd_setting_val_from_code(RD_SettingCode_SmoothCodeText).s32*FNT_RasterFlag_Smooth)|(!!rd_setting_val_from_code(RD_SettingCode_HintCodeText).s32*FNT_RasterFlag_Hinted);}break; - } + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + FNT_RasterFlags flags = ws->font_slot_raster_flags[slot]; return flags; } -//- rjf: settings - -internal RD_SettingVal -rd_setting_val_from_code(RD_SettingCode code) -{ - RD_Window *window = rd_window_from_handle(rd_regs()->window); - RD_SettingVal result = {0}; - if(window != 0) - { - result = window->setting_vals[code]; - } - if(result.set == 0) - { - for EachEnumVal(RD_CfgSrc, src) - { - if(rd_state->cfg_setting_vals[src][code].set) - { - result = rd_state->cfg_setting_vals[src][code]; - break; - } - } - } - return result; -} - -//- rjf: config serialization - -internal int -rd_qsort_compare__cfg_string_bindings(RD_StringBindingPair *a, RD_StringBindingPair *b) -{ - return strncmp((char *)a->string.str, (char *)b->string.str, Min(a->string.size, b->string.size)); -} - -internal String8List -rd_cfg_strings_from_gfx(Arena *arena, String8 root_path, RD_CfgSrc source) -{ - ProfBeginFunction(); - local_persist char *spaces = " "; - local_persist char *slashes= "////////////////////////////////////////////////////////////////////////////////"; - String8List strs = {0}; - - //- rjf: write all entities - { - for EachEnumVal(RD_EntityKind, k) - { - RD_EntityKindFlags k_flags = rd_entity_kind_flags_table[k]; - if(!(k_flags & RD_EntityKindFlag_IsSerializedToConfig)) - { - continue; - } - B32 first = 1; - RD_EntityList entities = rd_query_cached_entity_list_with_kind(k); - for(RD_EntityNode *n = entities.first; n != 0; n = n->next) - { - RD_Entity *entity = n->entity; - if(entity->cfg_src != source) - { - continue; - } - if(first) - { - first = 0; - String8 title_name = d_entity_kind_name_lower_plural_table[k]; - str8_list_pushf(arena, &strs, "/// %S %.*s\n\n", - title_name, - (int)Max(0, 79 - (title_name.size + 5)), - slashes); - } - RD_EntityRec rec = {0}; - S64 depth = 0; - for(RD_Entity *e = entity; !rd_entity_is_nil(e); e = rec.next) - { - //- rjf: get next iteration - rec = rd_entity_rec_depth_first_pre(e, entity); - - //- rjf: unpack entity info - typedef U32 EntityInfoFlags; - enum - { - EntityInfoFlag_HasName = (1<<0), - EntityInfoFlag_HasDisabled = (1<<1), - EntityInfoFlag_HasTxtPt = (1<<2), - EntityInfoFlag_HasVAddr = (1<<3), - EntityInfoFlag_HasColor = (1<<4), - EntityInfoFlag_HasChildren = (1<<5), - EntityInfoFlag_HasDebugSubprocesses = (1<<6), - }; - String8 entity_name_escaped = e->string; - // TODO(rjf): @hack - hardcoding in the "EntityKind_Location" here - this is because - // i am assuming an entity *kind* can 'know' about the 'pathness' of a string. this is - // not the case. post-0.9.12 i need to fix this. - if(rd_entity_kind_flags_table[e->kind] & RD_EntityKindFlag_NameIsPath && - (e->kind != RD_EntityKind_Location || e->flags & RD_EntityFlag_HasTextPoint)) - { - Temp scratch = scratch_begin(&arena, 1); - String8 path_normalized = path_normalized_from_string(scratch.arena, e->string); - entity_name_escaped = path_relative_dst_from_absolute_dst_src(arena, path_normalized, root_path); - scratch_end(scratch); - } - else - { - entity_name_escaped = escaped_from_raw_str8(arena, e->string); - } - EntityInfoFlags info_flags = 0; - if(entity_name_escaped.size != 0) { info_flags |= EntityInfoFlag_HasName; } - if(!!e->disabled) { info_flags |= EntityInfoFlag_HasDisabled; } - if(e->flags & RD_EntityFlag_HasTextPoint) { info_flags |= EntityInfoFlag_HasTxtPt; } - if(e->flags & RD_EntityFlag_HasVAddr) { info_flags |= EntityInfoFlag_HasVAddr; } - if(e->flags & RD_EntityFlag_HasColor) { info_flags |= EntityInfoFlag_HasColor; } - if(!rd_entity_is_nil(e->first)) { info_flags |= EntityInfoFlag_HasChildren; } - if(e->debug_subprocesses) { info_flags |= EntityInfoFlag_HasDebugSubprocesses; } - - //- rjf: write entity info - B32 opened_brace = 0; - switch(info_flags) - { - //- rjf: default path -> entity has lots of stuff, so write all info generically - default: - { - opened_brace = 1; - - // rjf: write entity title - str8_list_pushf(arena, &strs, "%S:\n{\n", d_entity_kind_name_lower_table[e->kind]); - - // rjf: write this entity's info - if(entity_name_escaped.size != 0) - { - str8_list_pushf(arena, &strs, "name: \"%S\"\n", entity_name_escaped); - } - if(e->disabled) - { - str8_list_pushf(arena, &strs, "disabled: 1\n"); - } - if(e->debug_subprocesses) - { - str8_list_pushf(arena, &strs, "debug_subprocesses: 1\n"); - } - if(e->flags & RD_EntityFlag_HasColor) - { - Vec4F32 hsva = rd_hsva_from_entity(e); - Vec4F32 rgba = rgba_from_hsva(hsva); - U32 rgba_hex = u32_from_rgba(rgba); - str8_list_pushf(arena, &strs, "color: 0x%x\n", rgba_hex); - } - if(e->flags & RD_EntityFlag_HasTextPoint) - { - str8_list_pushf(arena, &strs, "line: %I64d\n", e->text_point.line); - } - if(e->flags & RD_EntityFlag_HasVAddr) - { - str8_list_pushf(arena, &strs, "vaddr: (0x%I64x)\n", e->vaddr); - } - }break; - - //- rjf: single-line fast-paths - case EntityInfoFlag_HasName: - {str8_list_pushf(arena, &strs, "%S: \"%S\"\n", d_entity_kind_name_lower_table[e->kind], entity_name_escaped);}break; - case EntityInfoFlag_HasName|EntityInfoFlag_HasTxtPt: - {str8_list_pushf(arena, &strs, "%S: (\"%S\":%I64d)\n", d_entity_kind_name_lower_table[e->kind], entity_name_escaped, e->text_point.line);}break; - case EntityInfoFlag_HasVAddr: - {str8_list_pushf(arena, &strs, "%S: (0x%I64x)\n", d_entity_kind_name_lower_table[e->kind], e->vaddr);}break; - - //- rjf: empty - case 0: - {}break; - } - - // rjf: push - depth += rec.push_count; - - // rjf: pop - if(rec.push_count == 0) - { - for(S64 pop_idx = 0; pop_idx < rec.pop_count + opened_brace; pop_idx += 1) - { - if(depth > 0) - { - depth -= 1; - } - str8_list_pushf(arena, &strs, "}\n"); - } - } - - // rjf: separate top-level entities with extra newline - if(rd_entity_is_nil(rec.next) && (rec.pop_count != 0 || n->next == 0)) - { - str8_list_pushf(arena, &strs, "\n"); - } - } - } - } - } - - //- rjf: write exception code filters - if(source == RD_CfgSrc_Project) - { - str8_list_push(arena, &strs, str8_lit("/// exception code filters ////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - str8_list_push(arena, &strs, str8_lit("exception_code_filters:\n")); - str8_list_push(arena, &strs, str8_lit("{\n")); - for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); - k < CTRL_ExceptionCodeKind_COUNT; - k = (CTRL_ExceptionCodeKind)(k+1)) - { - String8 name = ctrl_exception_code_kind_lowercase_code_string_table[k]; - B32 value = !!(rd_state->ctrl_exception_code_filters[k/64] & (1ull<<(k%64))); - str8_list_pushf(arena, &strs, " %S: %i\n", name, value); - } - str8_list_push(arena, &strs, str8_lit("}\n\n")); - } - - //- rjf: serialize windows - { - B32 first = 1; - for(RD_Window *window = rd_state->first_window; window != 0; window = window->next) - { - if(window->cfg_src != source) - { - continue; - } - if(first) - { - first = 0; - str8_list_push(arena, &strs, str8_lit("/// windows ///////////////////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - } - OS_Handle monitor = os_monitor_from_window(window->os); - String8 monitor_name = os_name_from_monitor(arena, monitor); - RD_Panel *root_panel = window->root_panel; - Rng2F32 rect = os_rect_from_window(window->os); - Vec2F32 size = dim_2f32(rect); - str8_list_push (arena, &strs, str8_lit("window:\n")); - str8_list_push (arena, &strs, str8_lit("{\n")); - str8_list_pushf(arena, &strs, " %s%s%s\n", - root_panel->split_axis == Axis2_X ? "split_x" : "split_y", - os_window_is_fullscreen(window->os) ? " fullscreen" : "", - os_window_is_maximized(window->os) ? " maximized" : ""); - str8_list_pushf(arena, &strs, " monitor: \"%S\"\n", monitor_name); - str8_list_pushf(arena, &strs, " size: (%i %i)\n", (int)size.x, (int)size.y); - str8_list_pushf(arena, &strs, " dpi: %f\n", os_dpi_from_window(window->os)); - for EachEnumVal(RD_SettingCode, code) - { - RD_SettingVal current = window->setting_vals[code]; - if(current.set) - { - str8_list_pushf(arena, &strs, " %S: %i\n", rd_setting_code_lower_string_table[code], current.s32); - } - } - { - RD_PanelRec rec = {0}; - S32 indentation = 2; - String8 indent_str = str8_lit(" "); - str8_list_pushf(arena, &strs, " panels:\n"); - str8_list_pushf(arena, &strs, " {\n"); - for(RD_Panel *p = root_panel; !rd_panel_is_nil(p); p = rec.next) - { - // rjf: get recursion - rec = rd_panel_rec_depth_first_pre(p); - - // rjf: non-root needs pct node - if(p != root_panel) - { - str8_list_pushf(arena, &strs, "%.*s%g:\n", indentation*2, indent_str.str, p->pct_of_parent); - str8_list_pushf(arena, &strs, "%.*s{\n", indentation*2, indent_str.str); - indentation += 1; - } - - // rjf: per-panel options - struct { String8 key; B32 value; } options[] = - { - {str8_lit_comp("tabs_on_bottom"), p->tab_side == Side_Max}, - }; - B32 has_options = 0; - for(U64 op_idx = 0; op_idx < ArrayCount(options); op_idx += 1) - { - if(options[op_idx].value) - { - if(has_options == 0) - { - str8_list_pushf(arena, &strs, "%.*s", indentation*2, indent_str.str); - } - else - { - str8_list_pushf(arena, &strs, " "); - } - has_options = 1; - str8_list_push(arena, &strs, options[op_idx].key); - } - } - if(has_options) - { - str8_list_pushf(arena, &strs, "\n"); - } - - // rjf: views - for(RD_View *view = p->first_tab_view; !rd_view_is_nil(view); view = view->order_next) - { - String8 view_string = view->spec->string; - - // rjf: serialize views - { - str8_list_pushf(arena, &strs, "%.*s", indentation*2, indent_str.str); - - // rjf: serialize view string - str8_list_push(arena, &strs, view_string); - - // rjf: serialize view parameterizations - str8_list_push(arena, &strs, str8_lit(": {")); - if(view == rd_selected_tab_from_panel(p)) - { - str8_list_push(arena, &strs, str8_lit("selected ")); - } - { - if(view->project_path.size != 0) - { - Temp scratch = scratch_begin(&arena, 1); - String8 project_path_absolute = path_normalized_from_string(scratch.arena, view->project_path); - String8 project_path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, project_path_absolute, root_path); - str8_list_pushf(arena, &strs, "project:{\"%S\"} ", project_path_relative); - scratch_end(scratch); - } - } - if(view->query_string_size != 0) - { - Temp scratch = scratch_begin(&arena, 1); - String8 query_raw = str8(view->query_buffer, view->query_string_size); - { - String8 query_file_path = rd_file_path_from_eval_string(scratch.arena, query_raw); - if(query_file_path.size != 0) - { - query_file_path = path_relative_dst_from_absolute_dst_src(scratch.arena, query_file_path, root_path); - query_raw = push_str8f(scratch.arena, "file:\"%S\"", query_file_path); - } - } - String8 query_sanitized = escaped_from_raw_str8(scratch.arena, query_raw); - str8_list_pushf(arena, &strs, "query:{\"%S\"} ", query_sanitized); - scratch_end(scratch); - } - { - String8 reserved_keys[] = - { - str8_lit("project"), - str8_lit("query"), - str8_lit("selected"), - }; - MD_NodeRec rec = {0}; - MD_Node *params_root = view->params_roots[view->params_read_gen%ArrayCount(view->params_roots)]; - for(MD_Node *n = params_root; - !md_node_is_nil(n); - n = rec.next) - { - rec = md_node_rec_depth_first_pre(n, params_root); - B32 is_reserved_key = 0; - for(U64 idx = 0; idx < ArrayCount(reserved_keys); idx += 1) - { - if(str8_match(n->string, reserved_keys[idx], 0)) - { - is_reserved_key = 1; - break; - } - } - if(is_reserved_key) - { - rec = md_node_rec_depth_first(n, params_root, OffsetOf(MD_Node, next), OffsetOf(MD_Node, next)); - } - if(!is_reserved_key && n != params_root) - { - str8_list_pushf(arena, &strs, "%S", n->string); - if(n->first != &md_nil_node) - { - str8_list_pushf(arena, &strs, ":{"); - } - for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - if(pop_idx == rec.pop_count-1 && rec.next == &md_nil_node) - { - break; - } - str8_list_pushf(arena, &strs, "}"); - } - if(rec.pop_count != 0 || n->next != &md_nil_node) - { - str8_list_pushf(arena, &strs, " "); - } - } - } - } - str8_list_push(arena, &strs, str8_lit("}\n")); - } - } - - // rjf: non-roots need closer - if(p != root_panel && rec.push_count == 0) - { - indentation -= 1; - str8_list_pushf(arena, &strs, "%.*s}\n", indentation*2, indent_str.str); - } - - // rjf: pop - for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1) - { - indentation -= 1; - if(pop_idx == rec.pop_count-1 && rec.next == &rd_nil_panel) - { - break; - } - str8_list_pushf(arena, &strs, "%.*s}\n", indentation*2, indent_str.str); - } - } - str8_list_pushf(arena, &strs, " }\n"); - } - str8_list_push (arena, &strs, str8_lit("}\n")); - str8_list_push (arena, &strs, str8_lit("\n")); - } - } - - //- rjf: serialize keybindings - if(source == RD_CfgSrc_User) - { - Temp scratch = scratch_begin(&arena, 1); - String8 indent_str = str8_lit(" "); - U64 string_binding_pair_count = 0; - RD_StringBindingPair *string_binding_pairs = push_array(scratch.arena, RD_StringBindingPair, rd_state->key_map_total_count); - for(U64 idx = 0; - idx < rd_state->key_map_table_size && string_binding_pair_count < rd_state->key_map_total_count; - idx += 1) - { - for(RD_KeyMapNode *n = rd_state->key_map_table[idx].first; - n != 0 && string_binding_pair_count < rd_state->key_map_total_count; - n = n->hash_next) - { - RD_StringBindingPair *pair = string_binding_pairs + string_binding_pair_count; - pair->string = n->name; - pair->binding = n->binding; - string_binding_pair_count += 1; - } - } - quick_sort(string_binding_pairs, string_binding_pair_count, sizeof(RD_StringBindingPair), rd_qsort_compare__cfg_string_bindings); - if(string_binding_pair_count != 0) - { - str8_list_push(arena, &strs, str8_lit("/// keybindings ///////////////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - str8_list_push(arena, &strs, str8_lit("keybindings:\n")); - str8_list_push(arena, &strs, str8_lit("{\n")); - for(U64 idx = 0; idx < string_binding_pair_count; idx += 1) - { - RD_StringBindingPair *pair = string_binding_pairs + idx; - String8List modifiers_strings = os_string_list_from_modifiers(scratch.arena, pair->binding.modifiers); - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - String8 event_flags_string = str8_list_join(scratch.arena, &modifiers_strings, &join); - String8 key_string = push_str8_copy(scratch.arena, os_g_key_cfg_string_table[pair->binding.key]); - for(U64 i = 0; i < event_flags_string.size; i += 1) - { - event_flags_string.str[i] = char_to_lower(event_flags_string.str[i]); - } - String8 binding_string = push_str8f(scratch.arena, "%S%s%S", - event_flags_string, - event_flags_string.size > 0 ? " " : "", - key_string); - str8_list_pushf(arena, &strs, " {\"%S\"%.*s%S%.*s}\n", - pair->string, - 40 > pair->string.size ? ((int)(40 - pair->string.size)) : 0, indent_str.str, - binding_string, - 20 > binding_string.size ? ((int)(20 - binding_string.size)) : 0, indent_str.str); - } - str8_list_push(arena, &strs, str8_lit("}\n\n")); - } - scratch_end(scratch); - } - - //- rjf: serialize theme colors - if(source == RD_CfgSrc_User) - { - // rjf: determine if this theme matches an existing preset - B32 is_preset = 0; - RD_ThemePreset matching_preset = RD_ThemePreset_DefaultDark; - { - for(RD_ThemePreset p = (RD_ThemePreset)0; p < RD_ThemePreset_COUNT; p = (RD_ThemePreset)(p+1)) - { - B32 matches_this_preset = 1; - for(RD_ThemeColor c = (RD_ThemeColor)(RD_ThemeColor_Null+1); c < RD_ThemeColor_COUNT; c = (RD_ThemeColor)(c+1)) - { - if(!MemoryMatchStruct(&rd_state->cfg_theme_target.colors[c], &rd_theme_preset_colors_table[p][c])) - { - matches_this_preset = 0; - break; - } - } - if(matches_this_preset) - { - is_preset = 1; - matching_preset = p; - break; - } - } - } - - // rjf: serialize header - String8 indent_str = str8_lit(" "); - str8_list_push(arena, &strs, str8_lit("/// colors ////////////////////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - - // rjf: serialize preset theme - if(is_preset) - { - str8_list_pushf(arena, &strs, "color_preset: \"%S\"\n\n", rd_theme_preset_code_string_table[matching_preset]); - } - - // rjf: serialize non-preset theme - if(!is_preset) - { - str8_list_push(arena, &strs, str8_lit("colors:\n")); - str8_list_push(arena, &strs, str8_lit("{\n")); - for(RD_ThemeColor color = (RD_ThemeColor)(RD_ThemeColor_Null+1); - color < RD_ThemeColor_COUNT; - color = (RD_ThemeColor)(color+1)) - { - String8 color_name = rd_theme_color_cfg_string_table[color]; - Vec4F32 color_rgba = rd_state->cfg_theme_target.colors[color]; - String8 color_hex = hex_string_from_rgba_4f32(arena, color_rgba); - str8_list_pushf(arena, &strs, " %S:%.*s0x%S\n", - color_name, - 30 > color_name.size ? ((int)(30 - color_name.size)) : 0, indent_str.str, - color_hex); - } - str8_list_push(arena, &strs, str8_lit("}\n\n")); - } - } - - //- rjf: serialize fonts - if(source == RD_CfgSrc_User) - { - String8 code_font_path_escaped = escaped_from_raw_str8(arena, rd_state->cfg_code_font_path); - String8 main_font_path_escaped = escaped_from_raw_str8(arena, rd_state->cfg_main_font_path); - str8_list_push(arena, &strs, str8_lit("/// fonts /////////////////////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - str8_list_pushf(arena, &strs, "code_font: \"%S\"\n", code_font_path_escaped); - str8_list_pushf(arena, &strs, "main_font: \"%S\"\n", main_font_path_escaped); - str8_list_push(arena, &strs, str8_lit("\n")); - } - - //- rjf: serialize global settings - { - B32 first = 1; - for EachEnumVal(RD_SettingCode, code) - { - if(rd_setting_code_default_is_per_window_table[code]) - { - continue; - } - RD_SettingVal current = rd_state->cfg_setting_vals[source][code]; - if(current.set) - { - if(first) - { - first = 0; - str8_list_push(arena, &strs, str8_lit("/// global settings ///////////////////////////////////////////////////////////\n")); - str8_list_push(arena, &strs, str8_lit("\n")); - } - str8_list_pushf(arena, &strs, "%S: %i\n", rd_setting_code_lower_string_table[code], current.s32); - } - } - if(!first) - { - str8_list_push(arena, &strs, str8_lit("\n")); - } - } - - ProfEnd(); - return strs; -} - //////////////////////////////// //~ rjf: Process Control Info Stringification @@ -11004,27 +10330,31 @@ rd_string_from_exception_code(U32 code) return string; } -internal DR_FancyStringList +internal DR_FStrList rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, event->entity); - DR_FancyStringList thread_fstrs = rd_title_fstrs_from_ctrl_entity(arena, thread, ui_top_palette()->text, ui_top_font_size(), 0); - DR_FancyStringList fstrs = {0}; + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, event->entity); + DR_FStrList thread_fstrs = rd_title_fstrs_from_ctrl_entity(arena, thread, 0); + DR_FStrList fstrs = {0}; + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; switch(event->cause) { - default:{}break; + default: + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit("Not running")); + }break; //- rjf: finished operation; if active thread, completed thread, otherwise we're just stopped case CTRL_EventCause_Finished: { if(thread != &ctrl_entity_nil) { - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" completed step")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" completed step")); } else { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit("Stopped")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit("Stopped")); } }break; @@ -11033,12 +10363,12 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) { if(thread != &ctrl_entity_nil) { - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" stopped at entry point")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" stopped at entry point")); } else { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit("Stopped at entry point")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit("Stopped at entry point")); } }break; @@ -11047,10 +10377,10 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) { if(thread != &ctrl_entity_nil) { - dr_fancy_string_list_push_new(arena, &fstrs, rd_font_from_slot(RD_FontSlot_Icons), ui_top_font_size(), ui_top_palette()->text, rd_icon_kind_text_table[RD_IconKind_CircleFilled]); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit a breakpoint")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_CircleFilled], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit a breakpoint")); } }break; @@ -11059,14 +10389,15 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) { if(thread != &ctrl_entity_nil) { - dr_fancy_string_list_push_new(arena, &fstrs, rd_font_from_slot(RD_FontSlot_Icons), ui_top_font_size(), ui_top_palette()->text, rd_icon_kind_text_table[RD_IconKind_WarningBig]); + dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_WarningBig], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); switch(event->exception_kind) { default: { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit an exception - ")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit an exception: ")); String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); String8 exception_explanation_string = rd_string_from_exception_code(event->exception_code); String8 exception_info_string = push_str8f(arena, "%S%s%S%s", @@ -11074,49 +10405,47 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) exception_explanation_string.size != 0 ? " (" : "", exception_explanation_string, exception_explanation_string.size != 0 ? ")" : ""); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_info_string); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_info_string); }break; case CTRL_ExceptionKind_CppThrow: { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit a C++ exception - ")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit a C++ exception: ")); String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_code_string); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_code_string); }break; case CTRL_ExceptionKind_MemoryRead: { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit an exception - ")); - String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); - String8 exception_info_string = push_str8f(arena, "%S (Access violation reading 0x%I64x)", exception_code_string, event->vaddr_rng.min); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_info_string); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit an exception: ")); + String8 exception_info_string = push_str8f(arena, "Access violation reading from address 0x%I64x", event->vaddr_rng.min); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_info_string); }break; case CTRL_ExceptionKind_MemoryWrite: { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit an exception - ")); - String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); - String8 exception_info_string = push_str8f(arena, "%S (Access violation writing 0x%I64x)", exception_code_string, event->vaddr_rng.min); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_info_string); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit an exception: ")); + String8 exception_info_string = push_str8f(arena, "Access violation writing to address 0x%I64x", event->vaddr_rng.min); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_info_string); }break; case CTRL_ExceptionKind_MemoryExecute: { - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit an exception - ")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit an exception: ")); String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); - String8 exception_info_string = push_str8f(arena, "%S (Access violation executing 0x%I64x)", exception_code_string, event->vaddr_rng.min); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_info_string); + String8 exception_info_string = push_str8f(arena, "Access violation executing at address 0x%I64x", event->vaddr_rng.min); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_info_string); }break; } } else { - dr_fancy_string_list_push_new(arena, &fstrs, rd_font_from_slot(RD_FontSlot_Icons), ui_top_font_size(), ui_top_palette()->text, rd_icon_kind_text_table[RD_IconKind_WarningBig]); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit("Hit an exception - ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_WarningBig], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" Hit an exception: ")); String8 exception_code_string = str8_from_u64(arena, event->exception_code, 16, 0, 0); String8 exception_explanation_string = rd_string_from_exception_code(event->exception_code); String8 exception_info_string = push_str8f(arena, "%S%s%S%s", @@ -11124,29 +10453,76 @@ rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event) exception_explanation_string.size != 0 ? " (" : "", exception_explanation_string, exception_explanation_string.size != 0 ? ")" : ""); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, exception_info_string); + dr_fstrs_push_new(arena, &fstrs, ¶ms, exception_info_string); } }break; //- rjf: trap case CTRL_EventCause_InterruptedByTrap: { - dr_fancy_string_list_push_new(arena, &fstrs, rd_font_from_slot(RD_FontSlot_Icons), ui_top_font_size(), ui_top_palette()->text, rd_icon_kind_text_table[RD_IconKind_WarningBig]); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" ")); - dr_fancy_string_list_concat_in_place(&fstrs, &thread_fstrs); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit(" hit a trap")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_WarningBig], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_concat_in_place(&fstrs, &thread_fstrs); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" hit a trap")); }break; //- rjf: halt case CTRL_EventCause_InterruptedByHalt: { - dr_fancy_string_list_push_new(arena, &fstrs, rd_font_from_slot(RD_FontSlot_Icons), ui_top_font_size(), ui_top_palette()->text, rd_icon_kind_text_table[RD_IconKind_Pause]); - dr_fancy_string_list_push_new(arena, &fstrs, ui_top_font(), ui_top_font_size(), ui_top_palette()->text, str8_lit("Halted")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, rd_icon_kind_text_table[RD_IconKind_Pause], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" Halted")); }break; } return fstrs; } +//////////////////////////////// +//~ rjf: Vocab Info Lookups + +internal RD_VocabInfo * +rd_vocab_info_from_code_name(String8 code_name) +{ + RD_VocabInfo *result = &rd_nil_vocab_info; + if(code_name.size != 0) + { + U64 hash = d_hash_from_string(code_name); + U64 slot_idx = hash%rd_state->vocab_info_map.single_slots_count; + for(RD_VocabInfoMapNode *n = rd_state->vocab_info_map.single_slots[slot_idx].first; + n != 0; + n = n->single_next) + { + if(str8_match(n->v.code_name, code_name, 0)) + { + result = &n->v; + break; + } + } + } + return result; +} + +internal RD_VocabInfo * +rd_vocab_info_from_code_name_plural(String8 code_name_plural) +{ + RD_VocabInfo *result = &rd_nil_vocab_info; + if(code_name_plural.size != 0) + { + U64 hash = d_hash_from_string(code_name_plural); + U64 slot_idx = hash%rd_state->vocab_info_map.plural_slots_count; + for(RD_VocabInfoMapNode *n = rd_state->vocab_info_map.plural_slots[slot_idx].first; + n != 0; + n = n->plural_next) + { + if(str8_match(n->v.code_name_plural, code_name_plural, 0)) + { + result = &n->v; + break; + } + } + } + return result; +} + //////////////////////////////// //~ rjf: Continuous Frame Requests @@ -11167,97 +10543,9 @@ rd_frame_arena(void) return rd_state->frame_arenas[rd_state->frame_index%ArrayCount(rd_state->frame_arenas)]; } -//- rjf: config paths - -internal String8 -rd_cfg_path_from_src(RD_CfgSrc src) -{ - return rd_state->cfg_paths[src]; -} - -//- rjf: entity cache queries - -internal RD_EntityList -rd_query_cached_entity_list_with_kind(RD_EntityKind kind) -{ - ProfBeginFunction(); - RD_EntityListCache *cache = &rd_state->kind_caches[kind]; - - // rjf: build cached list if we're out-of-date - if(cache->alloc_gen != rd_state->kind_alloc_gens[kind]) - { - cache->alloc_gen = rd_state->kind_alloc_gens[kind]; - if(cache->arena == 0) - { - cache->arena = arena_alloc(); - } - arena_clear(cache->arena); - cache->list = rd_push_entity_list_with_kind(cache->arena, kind); - } - - // rjf: grab & return cached list - RD_EntityList result = cache->list; - ProfEnd(); - return result; -} - -internal RD_EntityList -rd_push_active_target_list(Arena *arena) -{ - RD_EntityList active_targets = {0}; - RD_EntityList all_targets = rd_query_cached_entity_list_with_kind(RD_EntityKind_Target); - for(RD_EntityNode *n = all_targets.first; n != 0; n = n->next) - { - if(!n->entity->disabled) - { - rd_entity_list_push(arena, &active_targets, n->entity); - } - } - return active_targets; -} - -internal RD_Entity * -rd_entity_from_ev_key_and_kind(EV_Key key, RD_EntityKind kind) -{ - RD_Entity *result = &rd_nil_entity; - RD_EntityList list = rd_query_cached_entity_list_with_kind(kind); - for(RD_EntityNode *n = list.first; n != 0; n = n->next) - { - RD_Entity *entity = n->entity; - if(ev_key_match(rd_ev_key_from_entity(entity), key)) - { - result = entity; - break; - } - } - return result; -} - -//- rjf: config state - -internal RD_CfgTable * -rd_cfg_table(void) -{ - return &rd_state->cfg_table; -} - //////////////////////////////// //~ rjf: Registers -internal RD_Regs * -rd_regs(void) -{ - RD_Regs *regs = &rd_state->top_regs->v; - return regs; -} - -internal RD_Regs * -rd_base_regs(void) -{ - RD_Regs *regs = &rd_state->base_regs.v; - return regs; -} - internal RD_Regs * rd_push_regs_(RD_Regs *regs) { @@ -11300,6 +10588,10 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 string) rd_regs()->cursor = pair.pt; } }break; + case RD_RegSlot_Expr: + { + rd_regs()->expr = push_str8_copy(rd_frame_arena(), string); + }break; case RD_RegSlot_Cursor: { U64 v = 0; @@ -11320,11 +10612,10 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 string) case RD_RegSlot_PID: goto use_numeric_eval; use_numeric_eval: { - Temp scratch = scratch_begin(0, 0); - E_Eval eval = e_eval_from_string(scratch.arena, string); + E_Eval eval = e_eval_from_string(string); if(eval.msgs.max_kind == E_MsgKind_Null) { - E_TypeKind eval_type_kind = e_type_kind_from_key(e_type_unwrap(eval.type_key)); + E_TypeKind eval_type_kind = e_type_kind_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)); if(eval_type_kind == E_TypeKind_Ptr || eval_type_kind == E_TypeKind_LRef || eval_type_kind == E_TypeKind_RRef) @@ -11359,9 +10650,8 @@ rd_regs_fill_slot_from_string(RD_RegSlot slot, String8 string) } else { - log_user_errorf("Couldn't evaluate \"%S\" as an address.", string); + log_user_errorf("Couldn't evaluate `%S` as an address.", string); } - scratch_end(scratch); }break; } } @@ -11391,7 +10681,7 @@ rd_cmd_kind_info_from_string(String8 string) { RD_CmdKindInfo *info = &rd_nil_cmd_kind_info; { - // TODO(rjf): extend this by looking up into dynamically-registered commands by views + // TODO(rjf): @dynamic_cmds extend this by looking up into dynamically-registered commands by views RD_CmdKind kind = rd_cmd_kind_from_string(string); if(kind != RD_CmdKind_Null) { @@ -11429,6 +10719,20 @@ rd_next_cmd(RD_Cmd **cmd) return !!cmd[0]; } +internal B32 +rd_next_view_cmd(RD_Cmd **cmd) +{ + for(;rd_next_cmd(cmd);) + { + if(rd_regs()->view == cmd[0]->regs->view) + { + break; + } + } + B32 result = !!cmd[0]; + return result; +} + //////////////////////////////// //~ rjf: Main Layer Top-Level Calls @@ -11448,6 +10752,13 @@ rd_init(CmdLine *cmdln) rd_state->arena = arena; rd_state->quit_after_success = (cmd_line_has_flag(cmdln, str8_lit("quit_after_success")) || cmd_line_has_flag(cmdln, str8_lit("q"))); + rd_state->user_path_arena = arena_alloc(); + rd_state->project_path_arena = arena_alloc(); + rd_state->theme_path_arena = arena_alloc(); + rd_state->user_cfg_string_key = hs_hash_from_data(str8_lit("raddbg_user_data_string_key")); + rd_state->project_cfg_string_key = hs_hash_from_data(str8_lit("raddbg_project_data_string_key")); + rd_state->cmdln_cfg_string_key = hs_hash_from_data(str8_lit("raddbg_cmdln_data_string_key")); + rd_state->transient_cfg_string_key = hs_hash_from_data(str8_lit("raddbg_transient_data_string_key")); for(U64 idx = 0; idx < ArrayCount(rd_state->frame_arenas); idx += 1) { rd_state->frame_arenas[idx] = arena_alloc(); @@ -11466,32 +10777,97 @@ rd_init(CmdLine *cmdln) rd_state->num_frames_requested = 2; rd_state->seconds_until_autosave = 0.5f; rd_state->match_store = di_match_store_alloc(); + rd_state->eval_cache = e_cache_alloc(); for(U64 idx = 0; idx < ArrayCount(rd_state->cmds_arenas); idx += 1) { rd_state->cmds_arenas[idx] = arena_alloc(); } - rd_state->entities_arena = arena_alloc(.reserve_size = GB(64), .commit_size = KB(64)); - rd_state->entities_root = &rd_nil_entity; - rd_state->entities_base = push_array(rd_state->entities_arena, RD_Entity, 0); - rd_state->entities_count = 0; - rd_state->entities_root = rd_entity_alloc(&rd_nil_entity, RD_EntityKind_Root); - rd_state->key_map_arena = arena_alloc(); rd_state->popup_arena = arena_alloc(); rd_state->ctx_menu_key = ui_key_from_string(ui_key_zero(), str8_lit("top_level_ctx_menu")); rd_state->drop_completion_key = ui_key_from_string(ui_key_zero(), str8_lit("drop_completion_ctx_menu")); - rd_state->string_search_arena = arena_alloc(); - rd_state->eval_viz_view_cache_slots_count = 1024; - rd_state->eval_viz_view_cache_slots = push_array(arena, RD_EvalVizViewCacheSlot, rd_state->eval_viz_view_cache_slots_count); - rd_state->cfg_main_font_path_arena = arena_alloc(); - rd_state->cfg_code_font_path_arena = arena_alloc(); rd_state->bind_change_arena = arena_alloc(); rd_state->drag_drop_arena = arena_alloc(); rd_state->drag_drop_regs = push_array(rd_state->drag_drop_arena, RD_Regs, 1); rd_state->top_regs = &rd_state->base_regs; - rd_clear_bindings(); - // rjf: set up top-level config entity trees + // rjf: set up schemas { + U64 schemas_count = ArrayCount(rd_name_schema_info_table); + rd_state->schemas = push_array(rd_state->arena, MD_NodePtrList, schemas_count); + for EachIndex(idx, schemas_count) + { + Temp scratch = scratch_begin(0, 0); + typedef struct SchemaParseTask SchemaParseTask; + struct SchemaParseTask + { + SchemaParseTask *next; + String8 schema_text; + }; + SchemaParseTask start_task = {0, rd_name_schema_info_table[idx].schema}; + SchemaParseTask *first_task = &start_task; + SchemaParseTask *last_task = first_task; + for(SchemaParseTask *t = first_task; t != 0; t = t->next) + { + MD_Node *schema = md_tree_from_string(rd_state->arena, t->schema_text)->first; + md_node_ptr_list_push_front(rd_state->arena, &rd_state->schemas[idx], schema); + for MD_EachNode(tag, schema->first_tag) + { + if(str8_match(tag->string, str8_lit("inherit"), 0)) + { + for EachIndex(idx2, schemas_count) + { + if(str8_match(rd_name_schema_info_table[idx2].name, tag->first->string, 0)) + { + SchemaParseTask *new_task = push_array(scratch.arena, SchemaParseTask, 1); + SLLQueuePush(first_task, last_task, new_task); + new_task->schema_text = rd_name_schema_info_table[idx2].schema; + break; + } + } + } + } + } + scratch_end(scratch); + } + } + + // rjf: set up theme presets + { + for EachEnumVal(RD_ThemePreset, p) + { + rd_state->theme_preset_trees[p] = md_tree_from_string(rd_state->arena, rd_theme_preset_cfg_string_table[p])->first; + } + } + + // rjf: set up vocab info map + { + rd_state->vocab_info_map.single_slots_count = 1024; + rd_state->vocab_info_map.single_slots = push_array(rd_state->arena, RD_VocabInfoMapSlot, rd_state->vocab_info_map.single_slots_count); + rd_state->vocab_info_map.plural_slots_count = 1024; + rd_state->vocab_info_map.plural_slots = push_array(rd_state->arena, RD_VocabInfoMapSlot, rd_state->vocab_info_map.plural_slots_count); + for EachElement(idx, rd_vocab_info_table) + { + RD_VocabInfoMapNode *n = push_array(rd_state->arena, RD_VocabInfoMapNode, 1); + MemoryCopyStruct(&n->v, &rd_vocab_info_table[idx]); + U64 single_hash = d_hash_from_string(n->v.code_name); + U64 plural_hash = d_hash_from_string(n->v.code_name_plural); + U64 single_slot_idx = single_hash%rd_state->vocab_info_map.single_slots_count; + U64 plural_slot_idx = plural_hash%rd_state->vocab_info_map.plural_slots_count; + if(n->v.code_name.size != 0) + { + SLLQueuePush_N(rd_state->vocab_info_map.single_slots[single_slot_idx].first, rd_state->vocab_info_map.single_slots[single_slot_idx].last, n, single_next); + } + if(n->v.code_name_plural.size != 0) + { + SLLQueuePush_N(rd_state->vocab_info_map.plural_slots[plural_slot_idx].first, rd_state->vocab_info_map.plural_slots[plural_slot_idx].last, n, plural_next); + } + } + } + + // rjf: set up top-level config entity trees & tables + { + rd_state->cfg_id_slots_count = 1024; + rd_state->cfg_id_slots = push_array(arena, RD_CfgSlot, rd_state->cfg_id_slots_count); rd_state->root_cfg = rd_cfg_alloc(); RD_Cfg *user_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("user")); RD_Cfg *project_tree = rd_cfg_new(rd_state->root_cfg, str8_lit("project")); @@ -11499,53 +10875,66 @@ rd_init(CmdLine *cmdln) RD_Cfg *transient = rd_cfg_new(rd_state->root_cfg, str8_lit("transient")); } + // rjf: set up window cache + { + rd_state->window_state_slots_count = 64; + rd_state->window_state_slots = push_array(arena, RD_WindowStateSlot, rd_state->window_state_slots_count); + rd_state->first_window_state = rd_state->last_window_state = &rd_nil_window_state; + } + + // rjf: set up view cache + { + rd_state->view_state_slots_count = 4096; + rd_state->view_state_slots = push_array(arena, RD_ViewStateSlot, rd_state->view_state_slots_count); + } + // rjf: set up user / project paths { Temp scratch = scratch_begin(0, 0); // rjf: unpack command line arguments - String8 user_cfg_path = cmd_line_string(cmdln, str8_lit("user")); - String8 project_cfg_path = cmd_line_string(cmdln, str8_lit("project")); - if(project_cfg_path.size == 0) + String8 user_path = cmd_line_string(cmdln, str8_lit("user")); + String8 project_path = cmd_line_string(cmdln, str8_lit("project")); { - project_cfg_path = cmd_line_string(cmdln, str8_lit("profile")); + if(user_path.size != 0) + { + user_path = path_absolute_dst_from_relative_dst_src(scratch.arena, user_path, os_get_process_info()->initial_path); + } + if(project_path.size != 0) + { + project_path = path_absolute_dst_from_relative_dst_src(scratch.arena, project_path, os_get_process_info()->initial_path); + } } { String8 user_program_data_path = os_get_process_info()->user_program_data_path; - String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg")); + String8 user_data_folder = push_str8f(scratch.arena, "%S/raddbg", user_program_data_path); os_make_directory(user_data_folder); - if(user_cfg_path.size == 0) + if(user_path.size == 0) { - user_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_user", user_data_folder); + String8 last_user_path = push_str8f(scratch.arena, "%S/last_user", user_data_folder); + user_path = os_data_from_file_path(scratch.arena, last_user_path); } - if(project_cfg_path.size == 0) + if(user_path.size == 0) { - project_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_project", user_data_folder); + user_path = push_str8f(scratch.arena, "%S/default.raddbg_user", user_data_folder); } } - - // rjf: set up config path state - String8 cfg_src_paths[RD_CfgSrc_COUNT] = {user_cfg_path, project_cfg_path}; - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) + if(project_path.size != 0) { - rd_state->cfg_path_arenas[src] = arena_alloc(); - rd_cmd(rd_cfg_src_load_cmd_kind_table[src], .file_path = path_normalized_from_string(scratch.arena, cfg_src_paths[src])); + arena_clear(rd_state->project_path_arena); + rd_state->project_path = push_str8_copy(rd_state->project_path_arena, project_path); + } + + // rjf: do initial load of user (project will be loaded by the initial user load if not specified) + rd_cmd(RD_CmdKind_OpenUser, .file_path = user_path); + if(project_path.size != 0) + { + rd_cmd(RD_CmdKind_OpenProject, .file_path = project_path); } - // rjf: set up config table arena - rd_state->cfg_arena = arena_alloc(); scratch_end(scratch); } - // rjf: set up initial exception filtering rules - 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]) - { - rd_state->ctrl_exception_code_filters[k/64] |= 1ull<<(k%64); - } - } - // rjf: unpack icon image data { Temp scratch = scratch_begin(0, 0); @@ -11641,16 +11030,6 @@ rd_init(CmdLine *cmdln) scratch_end(scratch); } - // rjf: set up initial browse path - { - Temp scratch = scratch_begin(0, 0); - String8 current_path = os_get_current_path(scratch.arena); - String8 current_path_with_slash = push_str8f(scratch.arena, "%S/", current_path); - rd_state->current_path_arena = arena_alloc(); - rd_state->current_path = push_str8_copy(rd_state->current_path_arena, current_path_with_slash); - scratch_end(scratch); - } - ProfEnd(); } @@ -11659,14 +11038,34 @@ rd_frame(void) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - local_persist S32 depth = 0; log_scope_begin(); + rd_state->frame_depth += 1; - //- TODO(rjf): @cfg debugging: stringify the current cfg tree + ////////////////////////////// + //- rjf: (DEBUG) take top-level cfg roots, stringize them, and store them to hash store + // +#if 0 { - // String8 string = rd_string_from_cfg_tree(scratch.arena, rd_state->root_cfg); - // int x = 0; + struct + { + U128 key; + String8 name; + } + table[] = + { + {rd_state->user_cfg_string_key, str8_lit("user")}, + {rd_state->project_cfg_string_key, str8_lit("project")}, + {rd_state->cmdln_cfg_string_key, str8_lit("command_line")}, + {rd_state->transient_cfg_string_key, str8_lit("transient")}, + }; + for EachElement(idx, table) + { + Arena *arena = arena_alloc(); + String8 data = rd_string_from_cfg_tree(arena, rd_cfg_child_from_string(rd_state->root_cfg, table[idx].name)); + hs_submit_data(table[idx].key, &arena, data); + } } +#endif ////////////////////////////// //- rjf: do per-frame resets @@ -11685,42 +11084,222 @@ rd_frame(void) rd_state->hover_regs = push_array(rd_frame_arena(), RD_Regs, 1); rd_state->hover_regs_slot = RD_RegSlot_Null; } - if(depth == 0) - { - rd_state->frame_di_scope = di_scope_open(); - } B32 allow_text_hotkeys = !rd_state->text_edit_mode; rd_state->text_edit_mode = 0; - rd_state->ctrl_entity_meval_cache_slots_count = 1024; - rd_state->ctrl_entity_meval_cache_slots = push_array(rd_frame_arena(), RD_CtrlEntityMetaEvalCacheSlot, rd_state->ctrl_entity_meval_cache_slots_count); + + ////////////////////////////// + //- rjf: iterate all tabs, touch their view-states + // + if(rd_state->frame_depth == 1) + { + Temp scratch = scratch_begin(0, 0); + RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + { + RD_Cfg *window = n->v; + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + { + for(RD_CfgNode *n = p->tabs.first; n != 0; n = n->next) + { + RD_Cfg *tab = n->v; + if(rd_cfg_is_project_filtered(tab)) + { + continue; + } + rd_view_state_from_cfg(tab); + } + } + } + scratch_end(scratch); + } + + ////////////////////////////// + //- rjf: garbage collect untouched immediate cfg trees + // + if(rd_state->frame_depth == 1) + { + RD_Cfg *transient = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); + for(RD_Cfg *tln = transient->first, *next = &rd_nil_cfg; tln != &rd_nil_cfg; tln = next) + { + next = tln->next; + if(str8_match(tln->string, str8_lit("immediate"), 0)) + { + if(rd_cfg_child_from_string(tln, str8_lit("hot")) == &rd_nil_cfg) + { + rd_cfg_release(tln); + } + } + } + for(RD_Cfg *tln = transient->first; tln != &rd_nil_cfg; tln = tln->next) + { + if(str8_match(tln->string, str8_lit("immediate"), 0)) + { + for(RD_Cfg *child = tln->first, *next = &rd_nil_cfg; child != &rd_nil_cfg; child = next) + { + next = child->next; + if(str8_match(child->string, str8_lit("hot"), 0)) + { + rd_cfg_release(child); + } + } + } + } + } + + ////////////////////////////// + //- rjf: garbage collect untouched view states + // + if(rd_state->frame_depth == 1) + { + for EachIndex(slot_idx, rd_state->view_state_slots_count) + { + for(RD_ViewState *vs = rd_state->view_state_slots[slot_idx].first, *next; vs != 0; vs = next) + { + next = vs->hash_next; + if(vs->last_frame_index_touched+2 < rd_state->frame_index) + { + ev_view_release(vs->ev_view); + for(RD_ArenaExt *ext = vs->first_arena_ext; ext != 0; ext = ext->next) + { + arena_release(ext->arena); + } + arena_release(vs->arena); + DLLRemove_NP(rd_state->view_state_slots[slot_idx].first, rd_state->view_state_slots[slot_idx].last, vs, hash_next, hash_prev); + SLLStackPush_N(rd_state->free_view_state, vs, hash_next); + } + } + } + } + + ////////////////////////////// + //- rjf: sync with di parsers + // + ProfScope("sync with di parsers") + { + DI_EventList events = di_p2u_pop_events(scratch.arena, 0); + for(DI_EventNode *n = events.first; n != 0; n = n->next) + { + DI_Event *event = &n->v; + switch(event->kind) + { + default:{}break; + case DI_EventKind_ConversionStarted: + { + RD_Cfg *root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); + RD_Cfg *task = rd_cfg_new(root, str8_lit("conversion_task")); + rd_cfg_new(task, event->string); + }break; + case DI_EventKind_ConversionEnded: + { + RD_Cfg *root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("transient")); + for(RD_Cfg *tln = root->first; tln != &rd_nil_cfg; tln = tln->next) + { + if(str8_match(tln->string, str8_lit("conversion_task"), 0) && str8_match(tln->first->string, event->string, 0)) + { + rd_cfg_release(tln); + break; + } + } + }break; + } + } + } + + ////////////////////////////// + //- rjf: animate all views + // + if(rd_state->frame_depth == 1) + { + F32 slow_rate = 1 - pow_f32(2, (-10.f * rd_state->frame_dt)); + F32 fast_rate = 1 - pow_f32(2, (-40.f * rd_state->frame_dt)); + for EachIndex(slot_idx, rd_state->view_state_slots_count) + { + for(RD_ViewState *vs = rd_state->view_state_slots[slot_idx].first; + vs != 0; + vs = vs->hash_next) + { + F32 scroll_x_diff = (-vs->scroll_pos.x.off); + F32 scroll_y_diff = (-vs->scroll_pos.y.off); + F32 loading_t_diff = (vs->loading_t_target - vs->loading_t); + vs->scroll_pos.x.off += scroll_x_diff*rd_state->scrolling_animation_rate; + vs->scroll_pos.y.off += scroll_y_diff*rd_state->scrolling_animation_rate; + vs->loading_t += loading_t_diff * slow_rate; + if(abs_f32(loading_t_diff) > 0.01f || + abs_f32(scroll_x_diff) > 0.01f || + abs_f32(scroll_y_diff) > 0.01f) + { + rd_request_frame(); + } + if(abs_f32(scroll_x_diff) <= 0.01f) + { + vs->scroll_pos.x.off = 0; + } + if(abs_f32(scroll_y_diff) <= 0.01f) + { + vs->scroll_pos.y.off = 0; + } + RD_Cfg *vcfg = rd_cfg_from_id(vs->cfg_id); + if(rd_cfg_child_from_string(vcfg, str8_lit("selected")) != &rd_nil_cfg) + { + if(vs->loading_t_target > 0.5f) + { + rd_request_frame(); + } + vs->loading_t_target = 0; + } + } + } + } ////////////////////////////// //- rjf: get events from the OS // OS_EventList events = {0}; - if(depth == 0) DeferLoop(depth += 1, depth -= 1) + if(rd_state->frame_depth == 1) { events = os_get_events(scratch.arena, rd_state->num_frames_requested == 0); } + ////////////////////////////// + //- rjf: open frame scopes + // + if(rd_state->frame_depth == 1) + { + if(rd_state->frame_di_scope) { di_scope_close(rd_state->frame_di_scope); } + if(rd_state->frame_ctrl_scope) { ctrl_scope_close(rd_state->frame_ctrl_scope); } + rd_state->frame_di_scope = di_scope_open(); + rd_state->frame_ctrl_scope = ctrl_scope_open(); + } + + ////////////////////////////// + //- rjf: calculate avg length in us of last many frames + // + U64 frame_time_history_avg_us = 0; + { + U64 num_frames_in_history = Min(ArrayCount(rd_state->frame_time_us_history), rd_state->frame_index); + U64 frame_time_history_sum_us = 0; + if(num_frames_in_history > 0) + { + for(U64 idx = 0; idx < num_frames_in_history; idx += 1) + { + frame_time_history_sum_us += rd_state->frame_time_us_history[idx]; + } + frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history; + } + } + ////////////////////////////// //- rjf: pick target hz // + // pick among a number of sensible targets to snap to, given how well + // we've been performing + // // TODO(rjf): maximize target, given all windows and their monitors + // F32 target_hz = os_get_gfx_info()->default_refresh_rate; if(rd_state->frame_index > 32) { - // rjf: calculate average frame time out of the last N - U64 num_frames_in_history = Min(ArrayCount(rd_state->frame_time_us_history), rd_state->frame_index); - U64 frame_time_history_sum_us = 0; - for(U64 idx = 0; idx < num_frames_in_history; idx += 1) - { - frame_time_history_sum_us += rd_state->frame_time_us_history[idx]; - } - U64 frame_time_history_avg_us = frame_time_history_sum_us/num_frames_in_history; - - // rjf: pick among a number of sensible targets to snap to, given how well - // we've been performing F32 possible_alternate_hz_targets[] = {target_hz, 60.f, 120.f, 144.f, 240.f}; F32 best_target_hz = target_hz; S64 best_target_hz_frame_time_us_diff = max_S64; @@ -11731,7 +11310,8 @@ rd_frame(void) { U64 candidate_frame_time_us = 1000000/(U64)candidate; S64 frame_time_us_diff = (S64)frame_time_history_avg_us - (S64)candidate_frame_time_us; - if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff) + if(abs_s64(frame_time_us_diff) < best_target_hz_frame_time_us_diff && + frame_time_history_avg_us < candidate_frame_time_us + candidate_frame_time_us/4) { best_target_hz = candidate; best_target_hz_frame_time_us_diff = frame_time_us_diff; @@ -11741,6 +11321,20 @@ rd_frame(void) target_hz = best_target_hz; } + ////////////////////////////// + //- rjf: given frame time history, decide on amount of time we're willing to wait for memory read results + // for evaluations + // + { + rd_state->frame_eval_memread_endt_us = 0; + U64 frame_time_target_cap_us = (U64)(1000000/target_hz); + if(frame_time_history_avg_us < frame_time_target_cap_us) + { + U64 spare_time = (frame_time_target_cap_us - frame_time_history_avg_us) + 4000; + rd_state->frame_eval_memread_endt_us = os_now_microseconds() + spare_time; + } + } + ////////////////////////////// //- rjf: target Hz -> delta time // @@ -11764,9 +11358,8 @@ rd_frame(void) if(os_key_press(&events, os_handle_zero(), 0, OS_Key_Delete)) { rd_request_frame(); - rd_unbind_name(rd_state->bind_change_cmd_name, rd_state->bind_change_binding); + rd_cfg_release(rd_cfg_from_id(rd_state->bind_change_binding_id)); rd_state->bind_change_active = 0; - rd_cmd(rd_cfg_src_write_cmd_kind_table[RD_CfgSrc_User]); } for(OS_Event *event = events.first, *next = 0; event != 0; event = next) { @@ -11783,23 +11376,121 @@ rd_frame(void) event->key != OS_Key_Shift) { rd_state->bind_change_active = 0; - RD_Binding binding = zero_struct; + RD_Cfg *binding = rd_cfg_from_id(rd_state->bind_change_binding_id); + if(binding == &rd_nil_cfg) { - binding.key = event->key; - binding.modifiers = event->modifiers; + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *keybindings = rd_cfg_child_from_string_or_alloc(user, str8_lit("keybindings")); + binding = rd_cfg_new(keybindings, str8_lit("")); } - rd_unbind_name(rd_state->bind_change_cmd_name, rd_state->bind_change_binding); - rd_bind_name(rd_state->bind_change_cmd_name, binding); + rd_cfg_release_all_children(binding); + rd_cfg_new(binding, rd_state->bind_change_cmd_name); + rd_cfg_new(binding, os_g_key_cfg_string_table[event->key]); + if(event->modifiers & OS_Modifier_Ctrl) { rd_cfg_new(binding, str8_lit("ctrl")); } + if(event->modifiers & OS_Modifier_Shift) { rd_cfg_new(binding, str8_lit("shift")); } + if(event->modifiers & OS_Modifier_Alt) { rd_cfg_new(binding, str8_lit("alt")); } U32 codepoint = os_codepoint_from_modifiers_and_key(event->modifiers, event->key); os_text(&events, event->window, codepoint); os_eat_event(&events, event); - rd_cmd(rd_cfg_src_write_cmd_kind_table[RD_CfgSrc_User]); rd_request_frame(); break; } } } + ////////////////////////////// + //- rjf: build key map from config + // + ProfScope("build key map from config") + { + //- rjf: set up table + rd_state->key_map = push_array(rd_frame_arena(), RD_KeyMap, 1); + RD_KeyMap *key_map = rd_state->key_map; + key_map->name_slots_count = 4096; + key_map->name_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->name_slots_count); + key_map->binding_slots_count = 4096; + key_map->binding_slots = push_array(rd_frame_arena(), RD_KeyMapSlot, key_map->binding_slots_count); + + //- rjf: gather & parse all explicitly stored keybinding sets + RD_CfgList keybindings_cfg_list = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("keybindings")); + for(RD_CfgNode *n = keybindings_cfg_list.first; n != 0; n = n->next) + { + RD_Cfg *keybindings_root = n->v; + for(RD_Cfg *keybinding = keybindings_root->first; keybinding != &rd_nil_cfg; keybinding = keybinding->next) + { + String8 name = {0}; + RD_Binding binding = {0}; + for(RD_Cfg *child = keybinding->first; child != &rd_nil_cfg; child = child->next) + { + if(0){} + else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; } + else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; } + else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; } + else + { + OS_Key key = OS_Key_Null; + for EachEnumVal(OS_Key, k) + { + if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive)) + { + key = k; + break; + } + } + if(key != OS_Key_Null) + { + binding.key = key; + } + else + { + name = child->string; + for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1) + { + if(str8_match(rd_binding_version_remap_old_name_table[idx], name, StringMatchFlag_CaseInsensitive)) + { + name = rd_binding_version_remap_new_name_table[idx]; + } + } + } + } + } + if(name.size != 0) + { + U64 name_hash = d_hash_from_string(name); + U64 binding_hash = d_hash_from_string(str8_struct(&binding)); + U64 name_slot_idx = name_hash%key_map->name_slots_count; + U64 binding_slot_idx = binding_hash%key_map->binding_slots_count; + RD_KeyMapNode *n = push_array(rd_frame_arena(), RD_KeyMapNode, 1); + n->cfg_id = keybinding->id; + n->name = push_str8_copy(rd_frame_arena(), name); + n->binding = binding; + SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next); + SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next); + } + } + } + } + + ////////////////////////////// + //- rjf: get fonts from config + // + ProfScope("get fonts from config") + { + String8 main_font_name = rd_setting_from_name(str8_lit("main_font")); + String8 code_font_name = rd_setting_from_name(str8_lit("code_font")); + rd_state->font_slot_table[RD_FontSlot_Main] = fnt_tag_from_path(main_font_name); + rd_state->font_slot_table[RD_FontSlot_Code] = fnt_tag_from_path(code_font_name); + if(fnt_tag_match(rd_state->font_slot_table[RD_FontSlot_Main], fnt_tag_zero())) + { + rd_state->font_slot_table[RD_FontSlot_Main] = fnt_tag_from_static_data_string(&rd_default_main_font_bytes); + } + if(fnt_tag_match(rd_state->font_slot_table[RD_FontSlot_Code], fnt_tag_zero())) + { + rd_state->font_slot_table[RD_FontSlot_Code] = fnt_tag_from_static_data_string(&rd_default_code_font_bytes); + } + rd_state->font_slot_table[RD_FontSlot_Icons] = fnt_tag_from_static_data_string(&rd_icon_font_bytes); + } + ////////////////////////////// //- rjf: consume events // @@ -11811,12 +11502,16 @@ rd_frame(void) RD_RegsScope() { next = event->next; - RD_Window *window = rd_window_from_os_handle(event->window); - if(window != 0 && window != rd_window_from_handle(rd_regs()->window)) + RD_WindowState *ws = rd_window_state_from_os_handle(event->window); + if(ws != 0 && ws != rd_window_state_from_cfg(rd_cfg_from_id(rd_regs()->window))) { - rd_regs()->window = rd_handle_from_window(window); - rd_regs()->panel = rd_handle_from_panel(window->focused_panel); - rd_regs()->view = window->focused_panel->selected_tab_view; + Temp scratch = scratch_begin(0, 0); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(ws->cfg_id)); + rd_regs()->window = ws->cfg_id; + rd_regs()->panel = panel_tree.focused->cfg->id; + rd_regs()->tab = panel_tree.focused->selected_tab->id; + rd_regs()->view = panel_tree.focused->selected_tab->id; + scratch_end(scratch); } B32 take = 0; @@ -11827,46 +11522,47 @@ rd_frame(void) } //- rjf: try window close - if(!take && event->kind == OS_EventKind_WindowClose && window != 0) + if(!take && event->kind == OS_EventKind_WindowClose && ws != 0) { take = 1; - rd_cmd(RD_CmdKind_CloseWindow, .window = rd_handle_from_window(window)); + rd_cmd(RD_CmdKind_Exit); } //- rjf: try menu bar operations + if(rd_state->alt_menu_bar_enabled) { if(!take && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->modifiers == 0 && event->is_repeat == 0) { take = 1; rd_request_frame(); - window->menu_bar_focused_on_press = window->menu_bar_focused; - window->menu_bar_key_held = 1; - window->menu_bar_focus_press_started = 1; + ws->menu_bar_focused_on_press = ws->menu_bar_focused; + ws->menu_bar_key_held = 1; + ws->menu_bar_focus_press_started = 1; } if(!take && event->kind == OS_EventKind_Release && event->key == OS_Key_Alt && event->modifiers == 0 && event->is_repeat == 0) { take = 1; rd_request_frame(); - window->menu_bar_key_held = 0; + ws->menu_bar_key_held = 0; } - if(window->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->modifiers == 0 && event->is_repeat == 0) + if(ws->menu_bar_focused && event->kind == OS_EventKind_Press && event->key == OS_Key_Alt && event->modifiers == 0 && event->is_repeat == 0) { take = 1; rd_request_frame(); - window->menu_bar_focused = 0; + ws->menu_bar_focused = 0; } - else if(window->menu_bar_focus_press_started && !window->menu_bar_focused && event->kind == OS_EventKind_Release && event->modifiers == 0 && event->key == OS_Key_Alt && event->is_repeat == 0) + else if(ws->menu_bar_focus_press_started && !ws->menu_bar_focused && event->kind == OS_EventKind_Release && event->modifiers == 0 && event->key == OS_Key_Alt && event->is_repeat == 0) { take = 1; rd_request_frame(); - window->menu_bar_focused = !window->menu_bar_focused_on_press; - window->menu_bar_focus_press_started = 0; + ws->menu_bar_focused = !ws->menu_bar_focused_on_press; + ws->menu_bar_focus_press_started = 0; } - else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && window->menu_bar_focused && !ui_any_ctx_menu_is_open()) + else if(event->kind == OS_EventKind_Press && event->key == OS_Key_Esc && ws->menu_bar_focused && !ui_any_ctx_menu_is_open()) { take = 1; rd_request_frame(); - window->menu_bar_focused = 0; + ws->menu_bar_focused = 0; } } @@ -11874,13 +11570,13 @@ rd_frame(void) if(!take && event->kind == OS_EventKind_Press) { RD_Binding binding = {event->key, event->modifiers}; - String8List spec_candidates = rd_cmd_name_list_from_binding(scratch.arena, binding); - if(spec_candidates.first != 0) + RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding); + if(key_map_nodes.first != 0) { U32 hit_char = os_codepoint_from_modifiers_and_key(event->modifiers, event->key); if(hit_char == 0 || allow_text_hotkeys) { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = spec_candidates.first->string); + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = key_map_nodes.first->v->name); if(allow_text_hotkeys) { os_text(&events, event->window, hit_char); @@ -11889,13 +11585,13 @@ rd_frame(void) take = 1; if(event->modifiers & OS_Modifier_Alt) { - window->menu_bar_focus_press_started = 0; + ws->menu_bar_focus_press_started = 0; } } } else if(OS_Key_F1 <= event->key && event->key <= OS_Key_F19) { - window->menu_bar_focus_press_started = 0; + ws->menu_bar_focus_press_started = 0; } rd_request_frame(); } @@ -11910,7 +11606,7 @@ rd_frame(void) take = 1; if(event->modifiers & OS_Modifier_Alt) { - window->menu_bar_focus_press_started = 0; + ws->menu_bar_focus_press_started = 0; } } @@ -11940,28 +11636,26 @@ rd_frame(void) //- rjf: unpack eval-dependent info // ProfBegin("unpack eval-dependent info"); - CTRL_Entity *process = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->process); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); Arch arch = thread->arch; U64 unwind_count = rd_regs()->unwind_count; U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(thread); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); - U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(d_state->ctrl_entity_store, thread->handle); - CTRL_EntityList all_modules = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Module); + U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); + CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); U64 eval_modules_count = Max(1, all_modules.count); E_Module *eval_modules = push_array(scratch.arena, E_Module, eval_modules_count); E_Module *eval_modules_primary = &eval_modules[0]; - eval_modules_primary->rdi = &di_rdi_parsed_nil; + eval_modules_primary->rdi = &rdi_parsed_nil; eval_modules_primary->vaddr_range = r1u64(0, max_U64); DI_Key primary_dbgi_key = {0}; ProfScope("produce all eval modules") { - U64 eval_module_idx = 0; - for(CTRL_EntityNode *n = all_modules.first; n != 0; n = n->next, eval_module_idx += 1) + for EachIndex(eval_module_idx, all_modules.count) { - CTRL_Entity *m = n->v; + CTRL_Entity *m = all_modules.v[eval_module_idx]; DI_Key dbgi_key = ctrl_dbgi_key_from_module(m); eval_modules[eval_module_idx].arch = m->arch; eval_modules[eval_module_idx].rdi = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_key, 0); @@ -11977,171 +11671,761 @@ rd_frame(void) ProfEnd(); //////////////////////////// - //- rjf: build eval type context + //- rjf: begin evaluation // - E_TypeCtx *type_ctx = push_array(scratch.arena, E_TypeCtx, 1); - ProfScope("build eval type context") - { - E_TypeCtx *ctx = type_ctx; - ctx->ip_vaddr = rip_vaddr; - ctx->ip_voff = rip_voff; - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - } - e_select_type_ctx(type_ctx); + e_select_cache(rd_state->eval_cache); //////////////////////////// - //- rjf: build eval parse context + //- rjf: build base evaluation context // - E_ParseCtx *parse_ctx = push_array(scratch.arena, E_ParseCtx, 1); - ProfScope("build eval parse context") + E_BaseCtx *eval_base_ctx = push_array(scratch.arena, E_BaseCtx, 1); { - E_ParseCtx *ctx = parse_ctx; - ctx->ip_vaddr = rip_vaddr; - ctx->ip_voff = rip_voff; - ctx->ip_thread_space = rd_eval_space_from_ctrl_entity(thread, RD_EvalSpaceKind_CtrlEntity); - ctx->modules = eval_modules; - ctx->modules_count = eval_modules_count; - ctx->primary_module = eval_modules_primary; - ctx->regs_map = ctrl_string2reg_from_arch(ctx->primary_module->arch); - ctx->reg_alias_map = ctrl_string2alias_from_arch(ctx->primary_module->arch); - ctx->locals_map = d_query_cached_locals_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); - ctx->member_map = d_query_cached_member_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); + E_BaseCtx *ctx = eval_base_ctx; + + //- rjf: fill instruction pointer info + ctx->thread_ip_vaddr = rip_vaddr; + ctx->thread_ip_voff = rip_voff; + ctx->thread_reg_space = rd_eval_space_from_ctrl_entity(thread, RD_EvalSpaceKind_CtrlEntity); + ctx->thread_arch = thread->arch; + ctx->thread_unwind_count = unwind_count; + + //- rjf: fill modules + ctx->modules = eval_modules; + ctx->modules_count = eval_modules_count; + ctx->primary_module = eval_modules_primary; + + //- rjf: fill space hooks + ctx->space_gen = rd_eval_space_gen; + ctx->space_read = rd_eval_space_read; + ctx->space_write = rd_eval_space_write; } - e_select_parse_ctx(parse_ctx); + e_select_base_ctx(eval_base_ctx); //////////////////////////// - //- rjf: create names/type-info for debugger collections + //- rjf: build extra types & maps // - E_TypeKey collection_type_keys[ArrayCount(rd_collection_name_table)] = {0}; - for EachElement(idx, rd_collection_name_table) + E_String2ExprMap *macro_map = push_array(scratch.arena, E_String2ExprMap, 1); + macro_map[0] = e_string2expr_map_make(scratch.arena, 512); + E_AutoHookMap *auto_hook_map = push_array(scratch.arena, E_AutoHookMap, 1); + auto_hook_map[0] = e_auto_hook_map_make(scratch.arena, 512); + rd_state->meta_name2type_map = push_array(rd_frame_arena(), E_String2TypeKeyMap, 1); + rd_state->meta_name2type_map[0] = e_string2typekey_map_make(rd_frame_arena(), 256); + EV_ExpandRuleTable *expand_rule_table = push_array(scratch.arena, EV_ExpandRuleTable, 1); + rd_state->view_ui_rule_map = rd_view_ui_rule_map_make(scratch.arena, 512); { - collection_type_keys[idx] = e_type_key_cons(.kind = E_TypeKind_Collection, .name = rd_collection_name_table[idx]); + //- rjf: add macros for command groups + { + String8 names[] = + { + str8_lit("commands"), + str8_lit("tab_commands"), + str8_lit("text_pt_commands"), + str8_lit("text_range_commands"), + }; + for EachElement(idx, names) + { + String8 name = names[idx]; + E_TypeKey type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_StubSingleLineExpansion, + .name = name, + .access = E_TYPE_ACCESS_FUNCTION_NAME(commands), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(commands), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(commands), + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, name, expr); + } + } + + //- rjf: add macro for themes + { + String8 names[] = + { + str8_lit("themes"), + }; + for EachElement(idx, names) + { + String8 name = names[idx]; + E_TypeKey type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_StubSingleLineExpansion, + .name = name, + .access = E_TYPE_ACCESS_FUNCTION_NAME(themes), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(themes), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(themes), + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, name, expr); + } + } + + //- rjf: build schema types & cache (name -> type) mapping + for EachElement(idx, rd_name_schema_info_table) + { + String8 name = rd_name_schema_info_table[idx].name; + E_TypeKey type_key = e_type_key_cons(.name = name, + .kind = E_TypeKind_Set, + .irext = E_TYPE_IREXT_FUNCTION_NAME(schema), + .access = E_TYPE_ACCESS_FUNCTION_NAME(schema), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(schema), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(schema), + }); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, name, type_key); + } + + //- rjf: add macro for top-level config root + { + String8 name = str8_lit("config"); + E_TypeKey type_key = e_type_key_cons(.name = name, + .kind = E_TypeKind_Set, + .access = E_TYPE_ACCESS_FUNCTION_NAME(cfgs)); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, name, type_key); + } + + //- rjf: add macro for top-level control root + { + String8 name = str8_lit("control"); + E_TypeKey type_key = e_type_key_cons(.name = name, + .kind = E_TypeKind_Set, + .access = E_TYPE_ACCESS_FUNCTION_NAME(control)); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, name, type_key); + } + + //- rjf: add macros for config "slice" collections (targets, breakpoints, etc.) + String8 evallable_cfg_names[] = + { + str8_lit("breakpoint"), + str8_lit("watch_pin"), + str8_lit("target"), + str8_lit("file_path_map"), + str8_lit("type_view"), + str8_lit("recent_project"), + str8_lit("recent_file"), + }; + for EachElement(cfg_name_idx, evallable_cfg_names) + { + String8 cfg_name = evallable_cfg_names[cfg_name_idx]; + String8 collection_name = rd_plural_from_code_name(cfg_name); + E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set, .name = collection_name, + .irext = E_TYPE_IREXT_FUNCTION_NAME(cfgs_slice), + .access = E_TYPE_ACCESS_FUNCTION_NAME(cfgs_slice), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(cfgs_slice), + .range= E_TYPE_EXPAND_RANGE_FUNCTION_NAME(cfgs_slice), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(cfgs_slice), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(cfgs_slice), + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = collection_type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); + } + + //- rjf: add macros for evallable top-level individual config entity trees - + // things with names either explicitly attached, or that we can infer + for EachElement(idx, rd_name_schema_info_table) + { + String8 name = rd_name_schema_info_table[idx].name; + MD_NodePtrList schemas = rd_schemas_from_name(name); + B32 is_individually_evallable = 0; + for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + if(md_node_has_child(n->v, str8_lit("label"), 0) || + md_node_has_child(n->v, str8_lit("executable"), 0)) + { + is_individually_evallable = 1; + break; + } + } + if(is_individually_evallable) + { + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, name); + RD_CfgList cfgs = rd_cfg_top_level_list_from_string(scratch.arena, name); + for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next) + { + RD_Cfg *cfg = n->v; + String8 label = rd_label_from_cfg(cfg); + if(label.size != 0) + { + E_Space space = rd_eval_space_from_cfg(cfg); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + e_string2expr_map_insert(scratch.arena, macro_map, label, expr); + } + } + } + } + + //- rjf: add macros for windows/tabs + RD_CfgList watch_tabs = {0}; + { + RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + { + RD_Cfg *window = n->v; + { + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, window->string); + E_Space space = rd_eval_space_from_cfg(window); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + e_string2expr_map_insert(scratch.arena, macro_map, push_str8f(scratch.arena, "query:config.$%I64x", window->id), expr); + } + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + for(RD_PanelNode *p = panel_tree.root; + p != &rd_nil_panel_node; + p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) + { + for(RD_CfgNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) + { + RD_Cfg *tab = tab_n->v; + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, tab->string); + E_Space space = rd_eval_space_from_cfg(tab); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + e_string2expr_map_insert(scratch.arena, macro_map, push_str8f(scratch.arena, "query:config.$%I64x", tab->id), expr); + if(str8_match(tab->string, str8_lit("watch"), 0)) + { + rd_cfg_list_push(scratch.arena, &watch_tabs, tab); + } + } + } + } + } + + //- rjf: add macros for all watches in all watch tabs which define identifiers + for(RD_CfgNode *n = watch_tabs.first; n != 0; n = n->next) + { + RD_Cfg *watch_tab = n->v; + for(RD_Cfg *child = watch_tab->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("watch"), 0)) + { + RD_Cfg *watch = child; + String8 expr = watch->first->string; + E_Parse parse = e_parse_from_string(expr); + if(parse.msgs.max_kind == E_MsgKind_Null) + { + for(E_Expr *expr = parse.expr; expr != &e_expr_nil; expr = expr->next) + { + typedef struct ExprWalkTask ExprWalkTask; + struct ExprWalkTask + { + ExprWalkTask *next; + E_Expr *expr; + }; + ExprWalkTask start_task = {0, expr}; + ExprWalkTask *first_task = &start_task; + ExprWalkTask *last_task = first_task; + for(ExprWalkTask *t = first_task; t != 0; t = t->next) + { + switch(t->expr->kind) + { + case E_ExprKind_Call:{}break; + case E_ExprKind_Define: + { + E_Expr *lhs = t->expr->first; + E_Expr *rhs = lhs->next; + if(lhs->kind == E_ExprKind_LeafIdentifier) + { + e_string2expr_map_insert(scratch.arena, macro_map, lhs->string, rhs); + } + }break; + default: + { + for(E_Expr *child = t->expr->first; child != &e_expr_nil; child = child->next) + { + ExprWalkTask *task = push_array(scratch.arena, ExprWalkTask, 1); + SLLQueuePush(first_task, last_task, task); + task->expr = child; + } + }break; + } + } + } + } + } + } + } + + //- rjf: add macros for user/project + { + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, str8_lit("user")); + E_Space space = rd_eval_space_from_cfg(rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user"))); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("user_settings"), expr); + } + { + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, str8_lit("project")); + E_Space space = rd_eval_space_from_cfg(rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project"))); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("project_settings"), expr); + } + + //- rjf: add macros for evallable control entities + String8 evallable_ctrl_names[] = + { + str8_lit("machine"), + str8_lit("process"), + str8_lit("thread"), + str8_lit("module"), + }; + for EachElement(idx, evallable_ctrl_names) + { + String8 name = evallable_ctrl_names[idx]; + CTRL_EntityKind kind = ctrl_entity_kind_from_string(name); + CTRL_EntityArray array = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, kind); + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, name); + for EachIndex(idx, array.count) + { + CTRL_Entity *entity = array.v[idx]; + E_Space space = rd_eval_space_from_ctrl_entity(entity, RD_EvalSpaceKind_MetaCtrlEntity); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = type_key; + if(entity->string.size != 0) + { + e_string2expr_map_insert(scratch.arena, macro_map, entity->string, expr); + } + if(kind == CTRL_EntityKind_Machine && entity->handle.machine_id == CTRL_MachineID_Local) + { + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("local_machine"), expr); + } + if(kind == CTRL_EntityKind_Thread && ctrl_handle_match(rd_base_regs()->thread, entity->handle)) + { + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_thread"), expr); + } + if(kind == CTRL_EntityKind_Process && ctrl_handle_match(rd_base_regs()->process, entity->handle)) + { + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_process"), expr); + } + if(kind == CTRL_EntityKind_Module && ctrl_handle_match(rd_base_regs()->module, entity->handle)) + { + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("current_module"), expr); + } + } + } + + //- rjf: add macros for all ctrl entity collections + for EachElement(ctrl_name_idx, evallable_ctrl_names) + { + String8 kind_name = evallable_ctrl_names[ctrl_name_idx]; + String8 collection_name = rd_plural_from_code_name(kind_name); + E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = collection_name, + .access = E_TYPE_ACCESS_FUNCTION_NAME(ctrl_entities), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(ctrl_entities), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(ctrl_entities) + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = collection_type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); + } + + //- rjf: add macro / lookup rules for unattached processes + { + String8 collection_name = str8_lit("unattached_processes"); + E_TypeKey collection_type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = collection_name, + .flags = E_TypeFlag_StubSingleLineExpansion, + .access = E_TYPE_ACCESS_FUNCTION_NAME(unattached_processes), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(unattached_processes), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(unattached_processes) + }); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = collection_type_key; + expr->space = e_space_make(RD_EvalSpaceKind_MetaCtrlEntity); + e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, collection_name, collection_type_key); + } + + //- rjf: add macro for 'call_stack' -> 'query:current_thread.callstack' + { + E_Expr *expr = e_parse_from_string(str8_lit("query:current_thread.call_stack")).expr; + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("call_stack"), expr); + } + + + //- rjf: add types for queries + { + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("environment"), + e_type_key_cons(.kind = E_TypeKind_Set, + .name = str8_lit("environment"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(environment), + .access = E_TYPE_ACCESS_FUNCTION_NAME(environment), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(environment), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(environment), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(environment), + })); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("watches"), + e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_EditableChildren|E_TypeFlag_StubSingleLineExpansion, + .name = str8_lit("watches"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(watches), + .access = E_TYPE_ACCESS_FUNCTION_NAME(watches), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(watches), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(watches), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(watches), + })); + e_string2typekey_map_insert(rd_frame_arena(), + rd_state->meta_name2type_map, + str8_lit("call_stack"), + e_type_key_cons(.kind = E_TypeKind_Set, + .name = str8_lit("call_stack"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(call_stack), + .access = E_TYPE_ACCESS_FUNCTION_NAME(call_stack), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(call_stack), + })); + e_string2typekey_map_insert(rd_frame_arena(), rd_state->meta_name2type_map, str8_lit("theme_colors"), + e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_StubSingleLineExpansion, + .name = str8_lit("theme_colors"), + .irext = E_TYPE_IREXT_FUNCTION_NAME(cfgs_slice), + .access = E_TYPE_ACCESS_FUNCTION_NAME(cfgs_slice), + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(cfgs_query), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(cfgs_slice), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(cfgs_slice), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(cfgs_slice), + })); + } + + //- rjf: add macro for collections with specific lookup rules (but no unique id rules) + { + struct + { + String8 name; + E_TypeExpandInfoFunctionType *info; + E_TypeExpandRangeFunctionType *range; + } + collection_infos[] = + { +#define Collection(name) {str8_lit_comp(#name), E_TYPE_EXPAND_INFO_FUNCTION_NAME(name), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(name)} + Collection(locals), + Collection(registers), +#undef Collection + }; + for EachElement(idx, collection_infos) + { + String8 collection_name = collection_infos[idx].name; + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .name = collection_name, + .expand = + { + .info = collection_infos[idx].info, + .range = collection_infos[idx].range, + }); + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + e_string2expr_map_insert(scratch.arena, macro_map, collection_name, expr); + } + } + + //- rjf: add macros for debug info table collections + String8 debug_info_table_collection_names[] = + { + str8_lit_comp("procedures"), + str8_lit_comp("thread_locals"), + str8_lit_comp("globals"), + str8_lit_comp("types"), + }; + for EachElement(idx, debug_info_table_collection_names) + { + String8 name = debug_info_table_collection_names[idx]; + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = e_space_make(RD_EvalSpaceKind_MetaQuery); + expr->type_key = e_type_key_cons(.kind = E_TypeKind_Set, + .flags = E_TypeFlag_StubSingleLineExpansion, + .name = name, + .expand = + { + .info = E_TYPE_EXPAND_INFO_FUNCTION_NAME(debug_info_table), + .range = E_TYPE_EXPAND_RANGE_FUNCTION_NAME(debug_info_table), + .id_from_num = E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(debug_info_table), + .num_from_id = E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_NAME(debug_info_table) + }); + e_string2expr_map_insert(scratch.arena, macro_map, name, expr); + } + + //- rjf: add macro for output log + { + HS_Scope *hs_scope = hs_scope_open(); + HS_Key key = d_state->output_log_key; + U128 hash = hs_hash_from_key(key, 0); + String8 data = hs_data_from_hash(hs_scope, hash); + E_Space space = e_space_make(E_SpaceKind_HashStoreKey); + space.u64_0 = key.root.u64[0]; + space.u128 = key.id.u128[0]; + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); + e_string2expr_map_insert(scratch.arena, macro_map, str8_lit("output"), expr); + hs_scope_close(hs_scope); + } + + //- rjf: (DEBUG) add macro for cfg strings +#if 0 + { + struct + { + U128 key; + String8 name; + } + table[] = + { + {rd_state->user_cfg_string_key, str8_lit("raddbg_user_data")}, + {rd_state->project_cfg_string_key, str8_lit("raddbg_project_data")}, + {rd_state->cmdln_cfg_string_key, str8_lit("raddbg_command_line_data")}, + {rd_state->transient_cfg_string_key, str8_lit("raddbg_transient_data")}, + }; + for EachElement(idx, table) + { + HS_Scope *hs_scope = hs_scope_open(); + U128 key = table[idx].key; + U128 hash = hs_hash_from_key(key, 0); + String8 data = hs_data_from_hash(hs_scope, hash); + E_Space space = e_space_make(E_SpaceKind_HashStoreKey); + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); + space.u128 = key; + expr->space = space; + expr->mode = E_Mode_Offset; + expr->type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), data.size, 0); + e_string2expr_map_insert(scratch.arena, macro_map, table[idx].name, expr); + hs_scope_close(hs_scope); + } + } +#endif + + //- rjf: choose set of lenses + // TODO(rjf): @lenses generate via metaprogram + struct + { + String8 name; + B32 inherited_by_members; + B32 inherited_by_elements; + B32 array_like; + E_TypeIRExtFunctionType *irext; + E_TypeAccessFunctionType *access; + E_TypeExpandRule expand; + RD_ViewUIFunctionType *ui; + EV_ExpandRuleInfoHookFunctionType *ev_expand; + } + lens_table[] = + { + {str8_lit("raw"), 0, 0, 0, 0, 0, {0}}, + {str8_lit("bin"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("oct"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("dec"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("hex"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("digits"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("no_string"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("no_char"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("no_addr"), 1, 1, 0, 0, 0, {0}}, + {str8_lit("sequence"), 0, 0, 1, 0, 0, {E_TYPE_EXPAND_INFO_FUNCTION_NAME(sequence), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(sequence)}}, + {str8_lit("rows"), 0, 0, 0, 0, 0, {E_TYPE_EXPAND_INFO_FUNCTION_NAME(rows), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(rows)}}, + {str8_lit("columns"), 0, 0, 0, 0, 0, {0}}, + {str8_lit("flatten"), 0, 0, 0, 0, 0, {0}}, + {str8_lit("omit"), 0, 0, 0, 0, 0, {E_TYPE_EXPAND_INFO_FUNCTION_NAME(omit), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(omit)}}, + {str8_lit("range1"), 0, 0, 0, 0, 0, {0}}, + {str8_lit("array"), 0, 0, 1, 0, 0, {E_TYPE_EXPAND_INFO_FUNCTION_NAME(array), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(array)}}, + {str8_lit("slice"), 0, 0, 1, E_TYPE_IREXT_FUNCTION_NAME(slice), E_TYPE_ACCESS_FUNCTION_NAME(slice), {E_TYPE_EXPAND_INFO_FUNCTION_NAME(slice), E_TYPE_EXPAND_RANGE_FUNCTION_NAME(slice)}}, + {str8_lit("text"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(text), EV_EXPAND_RULE_INFO_FUNCTION_NAME(text)}, + {str8_lit("disasm"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(disasm), EV_EXPAND_RULE_INFO_FUNCTION_NAME(disasm)}, + {str8_lit("memory"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(memory), EV_EXPAND_RULE_INFO_FUNCTION_NAME(memory)}, + {str8_lit("bitmap"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(bitmap), EV_EXPAND_RULE_INFO_FUNCTION_NAME(bitmap)}, + {str8_lit("color"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(color), EV_EXPAND_RULE_INFO_FUNCTION_NAME(color)}, + {str8_lit("geo3d"), 0, 0, 0, 0, 0, {0}, RD_VIEW_UI_FUNCTION_NAME(geo3d), EV_EXPAND_RULE_INFO_FUNCTION_NAME(geo3d)}, + }; + + //- rjf: fill lenses in ev expand rule map, rd view ui rule map + { + for EachElement(idx, lens_table) + { + if(lens_table[idx].ui != 0) + { + rd_view_ui_rule_map_insert(scratch.arena, rd_state->view_ui_rule_map, lens_table[idx].name, lens_table[idx].ui); + } + if(lens_table[idx].ev_expand != 0) + { + ev_expand_rule_table_push_new(scratch.arena, expand_rule_table, lens_table[idx].name, lens_table[idx].ev_expand); + } + } + } + + //- rjf: fill macros w/ types for lenses + for EachElement(idx, lens_table) + { + E_TypeFlags type_flags = 0; + if(lens_table[idx].inherited_by_members) + { + type_flags |= E_TypeFlag_InheritedByMembers; + } + if(lens_table[idx].inherited_by_elements) + { + type_flags |= E_TypeFlag_InheritedByElements; + } + if(lens_table[idx].array_like) + { + type_flags |= E_TypeFlag_ArrayLikeExpansion; + } + E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, r1u64(0, 0)); + expr->type_key = e_type_key_cons(.kind = E_TypeKind_LensSpec, + .flags = type_flags, + .name = lens_table[idx].name, + .irext = lens_table[idx].irext, + .access = lens_table[idx].access, + .expand = lens_table[idx].expand); + e_string2expr_map_insert(scratch.arena, macro_map, lens_table[idx].name, expr); + } + } + ev_select_expand_rule_table(expand_rule_table); + + //////////////////////////// + //- rjf: gather config from loaded modules + // + RD_CfgList immediate_type_views = {0}; + CTRL_EntityArray modules = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Module); + for EachIndex(idx, modules.count) + { + CTRL_Entity *module = modules.v[idx]; + String8 raddbg_data = ctrl_raddbg_data_from_module(scratch.arena, module->handle); + U8 split_char = 0; + String8List raddbg_data_text_parts = str8_split(scratch.arena, raddbg_data, &split_char, 1, 0); + U64 cfg_idx = 0; + for(String8Node *text_n = raddbg_data_text_parts.first; text_n != 0; text_n = text_n->next) + { + String8 text = text_n->string; + RD_CfgList cfgs = rd_cfg_tree_list_from_string(scratch.arena, str8_zero(), text); + String8 module_name = ctrl_string_from_handle(scratch.arena, module->handle); + for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next, cfg_idx += 1) + { + RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("module_%S_cfg_%I64x", module_name, cfg_idx); + rd_cfg_release_all_children(immediate_root); + rd_cfg_insert_child(immediate_root, immediate_root->last, n->v); + rd_cfg_list_push(scratch.arena, &immediate_type_views, n->v); + } + } } //////////////////////////// - //- rjf: build eval IR context + //- rjf: construct default immediate-mode configs based on loaded modules + // + { + local_persist read_only struct + { + B32 stl; + B32 ue; + String8 pattern; + String8 expr; + } + type_views[] = + { + { 1, 0, str8_lit_comp("std::vector"), str8_lit_comp("slice(_Mypair._Myval2)") }, + { 1, 0, str8_lit_comp("std::unique_ptr"), str8_lit_comp("_Mypair._Myval2") }, + { 1, 0, str8_lit_comp("std::basic_string"), str8_lit_comp("_Mypair._Myval2._Myres <= 15 ? _Mypair._Myval2._Bx._Buf : array(_Mypair._Myval2._Bx._Ptr, _Mypair._Myval2._Mysize)") }, + { 1, 0, str8_lit_comp("std::basic_string_view"), str8_lit_comp("array(_Mydata, _Mysize)") }, + }; + if(rd_state->use_default_stl_type_views) + { + for EachElement(idx, type_views) + { + if((type_views[idx].stl && rd_state->use_default_stl_type_views) || + (type_views[idx].ue && rd_state->use_default_ue_type_views)) + { + RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("default_stl_type_vis_%I64x", idx); + RD_Cfg *type_view = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("type_view")); + RD_Cfg *type = rd_cfg_child_from_string_or_alloc(type_view, str8_lit("type")); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(type_view, str8_lit("expr")); + rd_cfg_new_replace(type, type_views[idx].pattern); + rd_cfg_new_replace(expr, type_views[idx].expr); + rd_cfg_list_push(scratch.arena, &immediate_type_views, type_view); + } + } + } + } + + //////////////////////////// + //- rjf: add auto-hook rules for type views + // + { + RD_CfgList type_views = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("type_view")); + RD_CfgList rules_lists[] = + { + type_views, + immediate_type_views, + }; + for EachElement(list_idx, rules_lists) + { + RD_CfgList list = rules_lists[list_idx]; + for(RD_CfgNode *n = list.first; n != 0; n = n->next) + { + RD_Cfg *rule = n->v; + String8 type_string = rd_cfg_child_from_string(rule, str8_lit("type"))->first->string; + String8 expr_string = rd_cfg_child_from_string(rule, str8_lit("expr"))->first->string; + e_auto_hook_map_insert_new(scratch.arena, auto_hook_map, .type_pattern = type_string, .tag_expr_string = expr_string); + } + } + } + + //////////////////////////// + //- rjf: build IR evaluation context // - E_TypeKey meta_eval_type_key = e_type_key_cons_base(type(CTRL_MetaEval)); E_IRCtx *ir_ctx = push_array(scratch.arena, E_IRCtx, 1); { E_IRCtx *ctx = ir_ctx; - ctx->macro_map = push_array(scratch.arena, E_String2ExprMap, 1); - ctx->macro_map[0] = e_string2expr_map_make(scratch.arena, 512); - - //- rjf: add macros for collections - { - for EachElement(idx, rd_collection_name_table) - { - E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); - expr->space = e_space_make(RD_EvalSpaceKind_MetaCollection); - expr->mode = E_Mode_Null; - expr->type_key = collection_type_keys[idx]; - e_string2expr_map_insert(scratch.arena, ctx->macro_map, rd_collection_name_table[idx], expr); - } - } - - //- rjf: add macros for all evallable debugger frontend entities - { - RD_EntityKind evallable_kinds[] = - { - RD_EntityKind_Breakpoint, - RD_EntityKind_WatchPin, - RD_EntityKind_Target, - RD_EntityKind_FilePathMap, - RD_EntityKind_AutoViewRule, - }; - E_TypeKey evallable_kind_types[] = - { - e_type_key_cons_base(type(CTRL_BreakpointMetaEval)), - e_type_key_cons_base(type(CTRL_PinMetaEval)), - e_type_key_cons_base(type(CTRL_TargetMetaEval)), - e_type_key_cons_base(type(CTRL_FilePathMapMetaEval)), - e_type_key_cons_base(type(CTRL_AutoViewRuleMetaEval)), - }; - for EachElement(idx, evallable_kinds) - { - RD_EntityList list = rd_query_cached_entity_list_with_kind(evallable_kinds[idx]); - for(RD_EntityNode *n = list.first; n != 0; n = n->next) - { - RD_Entity *entity = n->entity; - E_Space space = rd_eval_space_from_entity(entity); - E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); - expr->space = space; - expr->mode = E_Mode_Offset; - expr->type_key = evallable_kind_types[idx]; - e_string2expr_map_insert(scratch.arena, ctx->macro_map, push_str8f(scratch.arena, "$%I64u", entity->id), expr); - if(entity->string.size != 0 && entity->kind != RD_EntityKind_WatchPin) - { - e_string2expr_map_insert(scratch.arena, ctx->macro_map, entity->string, expr); - } - } - } - } - - //- rjf: add macros for all evallable control entities - { - CTRL_EntityKind evallable_kinds[] = - { - CTRL_EntityKind_Machine, - CTRL_EntityKind_Process, - CTRL_EntityKind_Thread, - CTRL_EntityKind_Module, - }; - E_TypeKey evallable_kind_types[] = - { - e_type_key_cons_base(type(CTRL_MachineMetaEval)), - e_type_key_cons_base(type(CTRL_ProcessMetaEval)), - e_type_key_cons_base(type(CTRL_ThreadMetaEval)), - e_type_key_cons_base(type(CTRL_ModuleMetaEval)), - }; - for EachElement(idx, evallable_kinds) - { - CTRL_EntityKind kind = evallable_kinds[idx]; - CTRL_EntityList list = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, kind); - for(CTRL_EntityNode *n = list.first; n != 0; n = n->next) - { - CTRL_Entity *entity = n->v; - E_Space space = rd_eval_space_from_ctrl_entity(entity, RD_EvalSpaceKind_MetaCtrlEntity); - E_Expr *expr = e_push_expr(scratch.arena, E_ExprKind_LeafOffset, 0); - expr->space = space; - expr->mode = E_Mode_Offset; - expr->type_key = evallable_kind_types[idx]; - e_string2expr_map_insert(scratch.arena, ctx->macro_map, push_str8f(scratch.arena, "$_%I64x_%I64x", entity->handle.machine_id, entity->handle.dmn_handle.u64[0]), expr); - if(entity->string.size != 0) - { - e_string2expr_map_insert(scratch.arena, ctx->macro_map, entity->string, expr); - } - if(kind == CTRL_EntityKind_Thread && ctrl_handle_match(rd_base_regs()->thread, entity->handle)) - { - e_string2expr_map_insert(scratch.arena, ctx->macro_map, str8_lit("current_thread"), expr); - } - if(kind == CTRL_EntityKind_Process && ctrl_handle_match(rd_base_regs()->process, entity->handle)) - { - e_string2expr_map_insert(scratch.arena, ctx->macro_map, str8_lit("current_process"), expr); - } - if(kind == CTRL_EntityKind_Module && ctrl_handle_match(rd_base_regs()->module, entity->handle)) - { - e_string2expr_map_insert(scratch.arena, ctx->macro_map, str8_lit("current_module"), expr); - } - } - } - } - - //- rjf: add macros for all watches which define identifiers - RD_EntityList watches = rd_query_cached_entity_list_with_kind(RD_EntityKind_Watch); - for(RD_EntityNode *n = watches.first; n != 0; n = n->next) - { - RD_Entity *watch = n->entity; - String8 expr = watch->string; - E_TokenArray tokens = e_token_array_from_text(scratch.arena, expr); - E_Parse parse = e_parse_expr_from_text_tokens(scratch.arena, expr, &tokens); - if(parse.msgs.max_kind == E_MsgKind_Null) - { - e_push_leaf_ident_exprs_from_expr__in_place(scratch.arena, ctx->macro_map, parse.expr); - } - } + ctx->regs_map = ctrl_string2reg_from_arch(eval_base_ctx->primary_module->arch); + ctx->reg_alias_map = ctrl_string2alias_from_arch(eval_base_ctx->primary_module->arch); + ctx->locals_map = d_query_cached_locals_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); + ctx->member_map = d_query_cached_member_map_from_dbgi_key_voff(&primary_dbgi_key, rip_voff); + ctx->macro_map = macro_map; + ctx->auto_hook_map = auto_hook_map; } e_select_ir_ctx(ir_ctx); @@ -12162,80 +12446,15 @@ rd_frame(void) ctx->tls_base = push_array(scratch.arena, U64, 1); ctx->tls_base[0] = d_query_cached_tls_base_vaddr_from_process_root_rip(process, tls_root_vaddr, rip_vaddr); } - e_select_interpret_ctx(interpret_ctx); + e_select_interpret_ctx(interpret_ctx, eval_modules_primary->rdi, rip_voff); //////////////////////////// - //- rjf: build eval visualization view rule table + //- rjf: evaluate unpacked settings (must be used earlier than this point in the frame, + // but cannot evaluate before this point, so we need to prep for next frame // - EV_ViewRuleInfoTable *view_rule_info_table = push_array(scratch.arena, EV_ViewRuleInfoTable, 1); - { - ev_view_rule_info_table_push_builtins(scratch.arena, view_rule_info_table); - - // rjf: collection view rules - for EachElement(idx, rd_collection_name_table) - { - EV_ViewRuleInfo info = {0}; - info.string = rd_collection_name_table[idx]; - info.flags = EV_ViewRuleInfoFlag_Expandable; - info.expr_resolution = EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity); - info.expr_expand_info = rd_collection_expr_expand_info_hook_function_table[idx]; - info.expr_expand_range_info = rd_collection_expr_expand_range_info_hook_function_table[idx]; - info.expr_expand_id_from_num = rd_collection_expr_expand_id_from_num_hook_function_table[idx]; - info.expr_expand_num_from_id = rd_collection_expr_expand_num_from_id_hook_function_table[idx]; - ev_view_rule_info_table_push(scratch.arena, view_rule_info_table, &info); - } - - // rjf: visualizer view rules - for EachEnumVal(RD_ViewRuleKind, k) - { - RD_ViewRuleInfo *src_info = &rd_view_rule_kind_info_table[k]; - if(src_info->flags & RD_ViewRuleInfoFlag_CanUseInWatchTable) - { - EV_ViewRuleInfo dst_info = {0}; - dst_info.string = src_info->string; - dst_info.flags = src_info->flags & RD_ViewRuleInfoFlag_CanExpand ? EV_ViewRuleInfoFlag_Expandable : 0; - dst_info.expr_resolution = EV_VIEW_RULE_EXPR_RESOLUTION_FUNCTION_NAME(identity); - dst_info.expr_expand_info = src_info->expr_expand_info; - dst_info.expr_expand_range_info = EV_VIEW_RULE_EXPR_EXPAND_RANGE_INFO_FUNCTION_NAME(nil); - dst_info.expr_expand_id_from_num = EV_VIEW_RULE_EXPR_EXPAND_ID_FROM_NUM_FUNCTION_NAME(identity); - dst_info.expr_expand_num_from_id = EV_VIEW_RULE_EXPR_EXPAND_NUM_FROM_ID_FUNCTION_NAME(identity); - ev_view_rule_info_table_push(scratch.arena, view_rule_info_table, &dst_info); - } - } - } - ev_select_view_rule_info_table(view_rule_info_table); - - //////////////////////////// - //- rjf: build eval visualization auto-view-rule table - // - EV_AutoViewRuleTable *auto_view_rule_table = push_array(scratch.arena, EV_AutoViewRuleTable, 1); - { - // ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, e_type_key_cons_base(type(CTRL_CheckB32)), str8_lit("checkbox"), 1); - ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, e_type_key_cons_base(type(CTRL_MetaEvalFrameArray)), str8_lit("slice"), 1); - ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, e_type_key_cons_base(type(CTRL_MachineMetaEval)), str8_lit("scheduler_machine"), 1); - ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, e_type_key_cons_base(type(CTRL_ProcessMetaEval)), str8_lit("scheduler_process"), 1); - for EachElement(idx, rd_collection_name_table) - { - ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, collection_type_keys[idx], rd_collection_name_table[idx], 1); - } - RD_EntityList auto_view_rules = rd_query_cached_entity_list_with_kind(RD_EntityKind_AutoViewRule); - for(RD_EntityNode *n = auto_view_rules.first; n != 0; n = n->next) - { - RD_Entity *rule = n->entity; - RD_Entity *src = rd_entity_child_from_kind(rule, RD_EntityKind_Source); - RD_Entity *dst = rd_entity_child_from_kind(rule, RD_EntityKind_Dest); - String8 type_string = src->string; - String8 view_rule_string = dst->string; - E_TokenArray tokens = e_token_array_from_text(scratch.arena, type_string); - E_Parse type_parse = e_parse_type_from_text_tokens(scratch.arena, type_string, &tokens); - E_TypeKey type_key = e_type_from_expr(type_parse.expr); - if(!e_type_key_match(e_type_key_zero(), type_key)) - { - ev_auto_view_rule_table_push_new(scratch.arena, auto_view_rule_table, type_key, view_rule_string, 0); - } - } - } - ev_select_auto_view_rule_table(auto_view_rule_table); + rd_state->alt_menu_bar_enabled = rd_setting_b32_from_name(str8_lit("focus_menu_bar_with_alt")); + rd_state->use_default_stl_type_views = rd_setting_b32_from_name(str8_lit("use_default_stl_type_views")); + rd_state->use_default_ue_type_views = rd_setting_b32_from_name(str8_lit("use_default_ue_type_views")); //////////////////////////// //- rjf: autosave if needed @@ -12253,8 +12472,7 @@ rd_frame(void) //////////////////////////// //- rjf: process top-level graphical commands // - B32 panel_reset_done = 0; - if(depth == 0) + if(rd_state->frame_depth == 1) { for(;rd_next_cmd(&cmd);) RD_RegsScope() { @@ -12266,8 +12484,11 @@ rd_frame(void) rd_request_frame(); // rjf: process command + RD_Cfg *cfg = &rd_nil_cfg; + String8 dst_path = {0}; + String8 bucket_name = {0}; Dir2 split_dir = Dir2_Invalid; - RD_Panel *split_panel = &rd_nil_panel; + RD_Cfg *split_panel = &rd_nil_cfg; U64 panel_sib_off = 0; U64 panel_child_off = 0; Vec2S32 panel_change_dir = {0}; @@ -12276,27 +12497,79 @@ rd_frame(void) //- rjf: default cases case RD_CmdKind_Run: case RD_CmdKind_LaunchAndRun: - case RD_CmdKind_LaunchAndInit: + case RD_CmdKind_LaunchAndStepInto: case RD_CmdKind_StepInto: case RD_CmdKind_StepOver: case RD_CmdKind_Restart: { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + // rjf: reset hit counts + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(processes.count == 0 || kind == RD_CmdKind_Restart) { - RD_EntityList bps = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - for(RD_EntityNode *n = bps.first; n != 0; n = n->next) + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) { - n->entity->u64 = 0; + RD_Cfg *hit_count = rd_cfg_child_from_string_or_alloc(n->v, str8_lit("hit_count")); + rd_cfg_new_replace(hit_count, str8_lit("0")); } } + + // rjf: determine if we have active targets + RD_CfgList targets = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + B32 has_active_targets = 0; + for(RD_CfgNode *n = targets.first; n != 0; n = n->next) + { + RD_Cfg *target = n->v; + if(!rd_disabled_from_cfg(target)) + { + has_active_targets = 1; + break; + } + } + + // rjf: run -> no active targets, no processes, but we only have one target? -> just launch it, then select it + if((kind == RD_CmdKind_Run || + kind == RD_CmdKind_StepInto || + kind == RD_CmdKind_StepOver) && processes.count == 0 && targets.count == 1 && !has_active_targets) + { + rd_cmd(kind == RD_CmdKind_Run ? RD_CmdKind_LaunchAndRun : RD_CmdKind_LaunchAndStepInto, .cfg = targets.first->v->id); + rd_cmd(RD_CmdKind_SelectTarget, .cfg = targets.first->v->id); + break; + } + + // rjf: run -> no targets at all, no processes? -> do helper for add-target + if((kind == RD_CmdKind_Run || + kind == RD_CmdKind_StepInto || + kind == RD_CmdKind_StepOver) && targets.count == 0 && processes.count == 0) + { + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string); + break; + } + + // rjf: run -> no active targets, no processes? -> do helper for launch-and-run + if((kind == RD_CmdKind_Run || + kind == RD_CmdKind_StepInto || + kind == RD_CmdKind_StepOver) && processes.count == 0 && !has_active_targets) + { + rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[kind == RD_CmdKind_Run ? RD_CmdKind_LaunchAndRun : RD_CmdKind_LaunchAndStepInto].string); + break; + } + + // rjf: if this is a low-level operation, e.g. launch-and-run or launch-and-step-into, + // and we do not have any active targets, then let's just select the ones that we are + // launching. + if(!has_active_targets && + (kind == RD_CmdKind_LaunchAndRun || + kind == RD_CmdKind_LaunchAndStepInto)) + { + rd_cmd(RD_CmdKind_SelectTarget, .cfg = rd_regs()->cfg); + } } // fallthrough default: { // rjf: try to run engine command if(D_CmdKind_Null < (D_CmdKind)kind && (D_CmdKind)kind < D_CmdKind_COUNT) { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); D_CmdParams params = {0}; params.machine = rd_regs()->machine; params.process = rd_regs()->process; @@ -12308,25 +12581,61 @@ rd_frame(void) params.vaddr = rd_regs()->vaddr; params.prefer_disasm = rd_regs()->prefer_disasm; params.pid = rd_regs()->pid; - if(entity->kind == RD_EntityKind_Target) - { - params.targets.count = 1; - params.targets.v = push_array(scratch.arena, D_Target, params.targets.count); - params.targets.v[0] = rd_d_target_from_entity(entity); - } + params.targets.count = 1; + params.targets.v = push_array(scratch.arena, D_Target, params.targets.count); + params.targets.v[0] = rd_target_from_cfg(scratch.arena, rd_cfg_from_id(rd_regs()->cfg)); d_push_cmd((D_CmdKind)kind, ¶ms); } - // rjf: try to open tabs for "view driver" commands - RD_ViewRuleInfo *view_rule_info = rd_view_rule_info_from_string(cmd->name); - if(view_rule_info != &rd_nil_view_rule_info) + // rjf: try to open tabs, if this is a tab-fastpath-opener + if(kind >= RD_CmdKind_FirstTabFastPathCmd) { - rd_cmd(RD_CmdKind_OpenTab, .string = str8_zero(), .params_tree = md_tree_from_string(scratch.arena, cmd->name)->first); + U64 fast_path_idx = (kind - RD_CmdKind_FirstTabFastPathCmd); + String8 view_name = rd_tab_fast_path_view_name_table[fast_path_idx]; + String8 query_name = rd_tab_fast_path_query_name_table[fast_path_idx]; + rd_cmd(RD_CmdKind_BuildTab, .string = view_name, .expr = query_name); } }break; - //- rjf: command fast path + //- rjf: open palette + case RD_CmdKind_OpenPalette: + { + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_Cfg *tab = panel_tree.focused->selected_tab; + String8List exprs = {0}; + { + str8_list_pushf(scratch.arena, &exprs, "query:commands"); + if(tab != &rd_nil_cfg) + { + str8_list_pushf(scratch.arena, &exprs, "query:config.$%I64x", tab->id); + } + if(window != &rd_nil_cfg) + { + str8_list_pushf(scratch.arena, &exprs, "query:config.$%I64x", window->id); + } + str8_list_pushf(scratch.arena, &exprs, "query:targets"); + str8_list_pushf(scratch.arena, &exprs, "query:breakpoints"); + str8_list_pushf(scratch.arena, &exprs, "query:recent_files"); + str8_list_pushf(scratch.arena, &exprs, "query:recent_projects"); + str8_list_pushf(scratch.arena, &exprs, "query:machines"); + str8_list_pushf(scratch.arena, &exprs, "query:processes"); + str8_list_pushf(scratch.arena, &exprs, "query:threads"); + str8_list_pushf(scratch.arena, &exprs, "query:modules"); + str8_list_pushf(scratch.arena, &exprs, "query:user_settings"); + str8_list_pushf(scratch.arena, &exprs, "query:project_settings"); + str8_list_pushf(scratch.arena, &exprs, "query:procedures"); + str8_list_pushf(scratch.arena, &exprs, "query:types"); + str8_list_pushf(scratch.arena, &exprs, "query:globals"); + str8_list_pushf(scratch.arena, &exprs, "query:thread_locals"); + } + String8 expr = str8_list_join(scratch.arena, &exprs, &(StringJoin){.sep = str8_lit(", ")}); + rd_cmd(RD_CmdKind_PushQuery, .expr = expr, .do_implicit_root = 1, .do_lister = 1, .do_big_rows = 1, .view = tab->id, .tab = tab->id); + }break; + + //- rjf: command fast paths case RD_CmdKind_RunCommand: + case RD_CmdKind_OpenTab: { RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(cmd->regs->cmd_name); @@ -12336,18 +12645,31 @@ rd_frame(void) RD_RegsScope(.cmd_name = str8_zero()) rd_push_cmd(cmd->regs->cmd_name, rd_regs()); } + // rjf: command has filesystem query, user wants native filesystem UI -> get the path then run the command + else if(info->query.slot == RD_RegSlot_FilePath && rd_setting_b32_from_name(str8_lit("use_native_file_system_dialog"))) + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *current_path = rd_cfg_child_from_string(user, str8_lit("current_path")); + String8 current_path_string = current_path->first->string; + if(current_path_string.size == 0) + { + current_path_string = path_normalized_from_string(scratch.arena, os_get_current_path(scratch.arena)); + } + String8 file_path = os_graphical_pick_file(scratch.arena, current_path_string); + file_path = path_normalized_from_string(scratch.arena, file_path); + if(file_path.size != 0) + { + RD_RegsScope(.cmd_name = str8_zero(), .file_path = file_path) rd_push_cmd(cmd->regs->cmd_name, rd_regs()); + rd_cmd(RD_CmdKind_SetCurrentPath, .file_path = str8_chop_last_slash(file_path)); + } + } + // rjf: command has required query -> prep query else { - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - arena_clear(window->query_cmd_arena); - window->query_cmd_name = push_str8_copy(window->query_cmd_arena, cmd->regs->cmd_name); - window->query_cmd_regs = rd_regs_copy(window->query_cmd_arena, rd_regs()); - MemoryZeroArray(window->query_cmd_regs_mask); - window->query_view_selected = 1; - } + rd_cmd(RD_CmdKind_PushQuery, + .do_implicit_root = 1, + .do_lister = info->query.expr.size != 0); } }break; @@ -12356,7 +12678,7 @@ rd_frame(void) { // rjf: if control processes are live, but this is not force-confirmed, then // get confirmation from user - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); UI_Key key = ui_key_from_string(ui_key_zero(), str8_lit("lossy_exit_confirmation")); if(processes.count != 0 && !rd_regs()->force_confirm && !ui_key_match(rd_state->popup_key, key)) { @@ -12385,76 +12707,71 @@ rd_frame(void) //- rjf: windows case RD_CmdKind_OpenWindow: { - RD_Window *originating_window = rd_window_from_handle(rd_regs()->window); - if(originating_window == 0) + RD_Cfg *old_window = rd_cfg_from_id(rd_regs()->window); + RD_Cfg *bucket = old_window->parent; + if(bucket == &rd_nil_cfg) { - originating_window = rd_state->first_window; + bucket = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); } - OS_Handle preferred_monitor = {0}; - DeferLoop(depth += 1, depth -= 1) + RD_Cfg *new_window = rd_cfg_new(bucket, str8_lit("window")); + RD_Cfg *size = rd_cfg_new(new_window, str8_lit("size")); + rd_cfg_newf(size, "1280"); + rd_cfg_newf(size, "720"); + for(RD_Cfg *old_child = old_window->first; old_child != &rd_nil_cfg; old_child = old_child->next) { - RD_Window *new_ws = rd_window_open(v2f32(1280, 720), preferred_monitor, RD_CfgSrc_User); - if(originating_window) + if(!str8_match(old_child->string, str8_lit("panels"), 0) && + !str8_match(old_child->string, str8_lit("size"), 0) && + !str8_match(old_child->string, str8_lit("pos"), 0) && + !str8_match(old_child->string, str8_lit("monitor"), 0) && + !str8_match(old_child->string, str8_lit("fullscreen"), 0) && + !str8_match(old_child->string, str8_lit("maximized"), 0)) { - MemoryCopy(new_ws->setting_vals, originating_window->setting_vals, sizeof(RD_SettingVal)*RD_SettingCode_COUNT); + RD_Cfg *new_child = rd_cfg_deep_copy(old_child); + rd_cfg_insert_child(new_window, new_window->last, new_child); } } + RD_Cfg *panels = rd_cfg_new(new_window, str8_lit("panels")); + rd_cfg_child_from_string_or_alloc(panels, str8_lit("selected")); + }break; + case RD_CmdKind_WindowSettings: + { + String8 expr = push_str8f(scratch.arena, "query:config.$%I64x", rd_regs()->window); + rd_cmd(RD_CmdKind_PushQuery, .expr = expr, .do_implicit_root = 1, .do_big_rows = 1, .do_lister = 1); }break; case RD_CmdKind_CloseWindow: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - if(ws != 0) + RD_CfgList all_windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + RD_Cfg *wcfg = rd_cfg_from_id(rd_regs()->window); + if(all_windows.count == 1 && all_windows.first->v == wcfg) { - // rjf: is this the last window? -> exit - if(rd_state->first_window == rd_state->last_window && rd_state->first_window == ws) - { - rd_cmd(RD_CmdKind_Exit); - } - - // rjf: not the last window? -> just release this window - else - { - // NOTE(rjf): we need to explicitly release all panel views, because views - // are a global concept and otherwise would leak. - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) - { - rd_panel_release_all_views(panel); - } - - ui_state_release(ws->ui); - DLLRemove(rd_state->first_window, rd_state->last_window, ws); - r_window_unequip(ws->os, ws->r); - os_window_close(ws->os); - arena_release(ws->query_cmd_arena); - arena_release(ws->ctx_menu_arena); - arena_release(ws->drop_completion_arena); - arena_release(ws->hover_eval_arena); - arena_release(ws->autocomp_lister_params_arena); - arena_release(ws->arena); - SLLStackPush(rd_state->free_window, ws); - ws->gen += 1; - } + rd_cmd(RD_CmdKind_Exit); + } + else + { + rd_cfg_release(wcfg); } }break; case RD_CmdKind_ToggleFullscreen: { - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) + RD_Cfg *wcfg = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(wcfg); + if(ws != &rd_nil_window_state) { - os_window_set_fullscreen(window->os, !os_window_is_fullscreen(window->os)); + os_window_set_fullscreen(ws->os, !os_window_is_fullscreen(ws->os)); } }break; case RD_CmdKind_BringToFront: { - RD_Window *last_focused_window = rd_window_from_handle(rd_state->last_focused_window); - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + RD_Cfg *last_focused_wcfg = rd_cfg_from_id(rd_state->last_focused_window); + RD_WindowState *last_focused_ws = rd_window_state_from_cfg(last_focused_wcfg); + if(last_focused_ws == &rd_nil_window_state) { - os_window_set_minimized(w->os, 0); - os_window_focus(last_focused_window->os); + last_focused_ws = rd_state->first_window_state; } - if(last_focused_window != 0) + if(last_focused_ws != &rd_nil_window_state) { - os_window_focus(last_focused_window->os); + os_window_set_minimized(last_focused_ws->os, 0); + os_window_focus(last_focused_ws->os); } }break; @@ -12474,1184 +12791,391 @@ rd_frame(void) rd_state->popup_key = ui_key_zero(); }break; + //- rjf: keybindings + case RD_CmdKind_ResetToDefaultBindings: + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_CfgList all_keybindings = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("keybindings")); + for(RD_CfgNode *n = all_keybindings.first; n != 0; n = n->next) + { + rd_cfg_release(n->v); + } + RD_Cfg *keybindings = rd_cfg_new(user, str8_lit("keybindings")); + for EachElement(idx, rd_default_binding_table) + { + String8 name = rd_default_binding_table[idx].string; + RD_Binding binding = rd_default_binding_table[idx].binding; + RD_Cfg *binding_root = rd_cfg_new(keybindings, str8_zero()); + rd_cfg_new(binding_root, name); + rd_cfg_new(binding_root, os_g_key_cfg_string_table[binding.key]); + if(binding.modifiers & OS_Modifier_Ctrl) {rd_cfg_newf(binding_root, "ctrl");} + if(binding.modifiers & OS_Modifier_Shift) {rd_cfg_newf(binding_root, "shift");} + if(binding.modifiers & OS_Modifier_Alt) {rd_cfg_newf(binding_root, "alt");} + } + }break; + //- rjf: config path saving/loading/applying case RD_CmdKind_OpenRecentProject: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - if(entity->kind == RD_EntityKind_RecentProject) + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *path = rd_cfg_child_from_string(cfg, str8_lit("path")); + if(str8_match(cfg->string, str8_lit("recent_project"), 0) && + path->first->string.size != 0) { - rd_cmd(RD_CmdKind_OpenProject, .file_path = entity->string); + rd_cmd(RD_CmdKind_OpenProject, .file_path = path->first->string); } }break; case RD_CmdKind_OpenUser: case RD_CmdKind_OpenProject: { - //- TODO(rjf): @cfg load & apply user/project data to the cfg data structure -#if 0 - { - String8 file_root_key = (kind == RD_CmdKind_OpenUser ? str8_lit("user") : str8_lit("project")); - RD_Cfg *file_root = rd_cfg_child_from_string(rd_state->root_cfg, file_root_key); - - //- rjf: eliminate all old state under this file tree - for(RD_Cfg *tln = file_root->first, *next = &rd_nil_cfg; - tln != &rd_nil_cfg; - tln = next) - { - next = tln->next; - rd_cfg_release(tln); - } - - //- rjf: load & parse the new file, generate cfg entities for it - String8 file_path = rd_regs()->file_path; - String8 file_data = os_data_from_file_path(scratch.arena, file_path); - RD_CfgList file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, file_data); - - //- rjf: insert the new cfg entities into this file tree - for(RD_CfgNode *n = file_cfg_list.first; n != 0; n = n->next) - { - rd_cfg_insert_child(file_root, file_root->last, n->v); - } - } -#endif + String8 file_root_key = (kind == RD_CmdKind_OpenUser ? str8_lit("user") : + kind == RD_CmdKind_OpenProject ? str8_lit("project") : + str8_lit("other")); + RD_Cfg *file_root = rd_cfg_child_from_string(rd_state->root_cfg, file_root_key); - // TODO(rjf): dear lord this is so overcomplicated, this needs to be collapsed down & simplified ASAP + //- rjf: load the new file's data + String8 file_path = rd_regs()->file_path; + String8 file_data = os_data_from_file_path(scratch.arena, file_path); + FileProperties file_props = os_properties_from_file_path(file_path); - B32 load_cfg[RD_CfgSrc_COUNT] = {0}; - RD_CfgSrc cfg_src = (RD_CfgSrc)0; - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) + //- rjf: determine if the file is good + B32 file_is_okay = 0; { - load_cfg[src] = (kind == rd_cfg_src_load_cmd_kind_table[src]); - if(load_cfg[src]) - { - cfg_src = src; - } + file_is_okay = ((file_props.size == 0 && file_props.created == 0) || + str8_match(str8_prefix(file_data, 9), str8_lit("// raddbg"), 0)); } - //- rjf: normalize path - String8 new_path = path_normalized_from_string(scratch.arena, rd_regs()->file_path); - - //- rjf: path -> data - FileProperties props = {0}; - String8 data = {0}; + //- rjf: determine file's version + String8 file_version = {0}; + if(file_is_okay && file_props.size != 0) { - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, new_path); - props = os_properties_from_file(file); - data = os_string_from_file_range(scratch.arena, file, r1u64(0, props.size)); - os_file_close(file); - } - - //- rjf: investigate file path/data - B32 file_is_okay = 1; - if(props.modified != 0 && data.size != 0 && !str8_match(str8_prefix(data, 9), str8_lit("// raddbg"), 0) && rd_state->cfg_cached_timestamp[cfg_src] != 0) - { - file_is_okay = 0; - } - - //- rjf: set new config paths - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - if(load_cfg[src]) - { - arena_clear(rd_state->cfg_path_arenas[src]); - rd_state->cfg_paths[src] = push_str8_copy(rd_state->cfg_path_arenas[src], new_path); - } - } - } - - //- rjf: get config file properties - FileProperties cfg_props[RD_CfgSrc_COUNT] = {0}; - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - String8 path = rd_cfg_path_from_src(src); - cfg_props[src] = os_properties_from_file_path(path); - } - } - - //- rjf: load files - String8 cfg_data[RD_CfgSrc_COUNT] = {0}; - U64 cfg_timestamps[RD_CfgSrc_COUNT] = {0}; - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - String8 path = rd_cfg_path_from_src(src); - OS_Handle file = os_file_open(OS_AccessFlag_ShareRead|OS_AccessFlag_Read, path); - FileProperties props = os_properties_from_file(file); - String8 data = os_string_from_file_range(scratch.arena, file, r1u64(0, props.size)); - if(props.modified != 0) - { - cfg_data[src] = data; - cfg_timestamps[src] = props.modified; - } - os_file_close(file); - } - } - - //- rjf: determine if we need to save config - B32 cfg_save[RD_CfgSrc_COUNT] = {0}; - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - cfg_save[src] = (load_cfg[src] && cfg_props[src].created == 0); - } - } - - //- rjf: determine if we need to reload config - B32 cfg_load[RD_CfgSrc_COUNT] = {0}; - B32 cfg_load_any = 0; - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - cfg_load[src] = (load_cfg[src] && ((cfg_save[src] == 0 && rd_state->cfg_cached_timestamp[src] != cfg_timestamps[src]) || cfg_props[src].created == 0)); - cfg_load_any = cfg_load_any || cfg_load[src]; - } - } - - //- rjf: load => build new config table - if(cfg_load_any) - { - arena_clear(rd_state->cfg_arena); - MemoryZeroStruct(&rd_state->cfg_table); - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - rd_cfg_table_push_unparsed_string(rd_state->cfg_arena, &rd_state->cfg_table, cfg_data[src], src); - } - } - - //- rjf: load => dispatch apply - // - // NOTE(rjf): must happen before `save`. we need to create a default before saving, which - // occurs in the 'apply' path. - // - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - if(cfg_load[src]) - { - RD_CmdKind cmd_kind = rd_cfg_src_apply_cmd_kind_table[src]; - rd_cmd(cmd_kind); - rd_state->cfg_cached_timestamp[src] = cfg_timestamps[src]; - } - } - } - - //- rjf: save => dispatch write - if(file_is_okay) - { - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) - { - if(cfg_save[src]) - { - RD_CmdKind cmd_kind = rd_cfg_src_write_cmd_kind_table[src]; - rd_cmd(cmd_kind); - } - } + file_version = str8_skip(file_data, 10); + U64 line_end = str8_find_needle(file_version, 0, str8_lit("\n"), 0); + file_version = str8_prefix(file_version, line_end); + U64 first_space = str8_find_needle(file_version, 0, str8_lit(" "), 0); + file_version = str8_prefix(file_version, first_space); + file_version = str8_skip_chop_whitespace(file_version); } //- rjf: bad file -> alert user if(!file_is_okay) { - log_user_errorf("\"%S\" appears to refer to an existing file which is not a RADDBG config file. This would overwrite the file.", new_path); - } - }break; - - //- rjf: loading/applying stateful config changes - case RD_CmdKind_ApplyUserData: - case RD_CmdKind_ApplyProjectData: - { - RD_CfgTable *table = rd_cfg_table(); - OS_HandleArray monitors = os_push_monitors_array(scratch.arena); - - //- rjf: get config source - RD_CfgSrc src = RD_CfgSrc_User; - for(RD_CfgSrc s = (RD_CfgSrc)0; s < RD_CfgSrc_COUNT; s = (RD_CfgSrc)(s+1)) - { - if(kind == rd_cfg_src_apply_cmd_kind_table[s]) - { - src = s; - break; - } + log_user_errorf("\"%S\" appears to refer to an existing file which is not a RADDBG config file. This would overwrite the file.", file_path); } - //- rjf: get paths - String8 cfg_path = rd_cfg_path_from_src(src); - String8 cfg_folder = str8_chop_last_slash(cfg_path); - - //- rjf: keep track of recent projects - if(src == RD_CfgSrc_Project) + //- rjf: eliminate all old state under this file tree + if(file_is_okay) { - //- TODO(rjf): @cfg keep track of recent projects - { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_CfgList recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); - RD_Cfg *recent_project = &rd_nil_cfg; - for(RD_CfgNode *n = recent_projects.first; n != 0; n = n->next) - { - if(path_match_normalized(n->v->string, cfg_path)) - { - recent_project = n->v; - break; - } - } - if(recent_project == &rd_nil_cfg) - { - recent_project = rd_cfg_new(user, str8_lit("recent_project")); - rd_cfg_new(recent_project, path_normalized_from_string(scratch.arena, cfg_path)); - } - rd_cfg_unhook(user, recent_project); - rd_cfg_insert_child(user, &rd_nil_cfg, recent_project); - recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); - if(recent_projects.count > 32) - { - rd_cfg_release(recent_projects.last->v); - } - } - RD_EntityList recent_projects = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentProject); - RD_Entity *recent_project = &rd_nil_entity; - for(RD_EntityNode *n = recent_projects.first; n != 0; n = n->next) - { - if(path_match_normalized(cfg_path, n->entity->string)) - { - recent_project = n->entity; - break; - } - } - if(rd_entity_is_nil(recent_project)) - { - recent_project = rd_entity_alloc(rd_entity_root(), RD_EntityKind_RecentProject); - rd_entity_equip_name(recent_project, path_normalized_from_string(scratch.arena, cfg_path)); - rd_entity_equip_cfg_src(recent_project, RD_CfgSrc_User); - } + rd_cfg_release_all_children(file_root); } - //- rjf: eliminate all existing entities which are derived from config + //- rjf: parse the new file, generate cfg entities for it + RD_CfgList file_cfg_list = {0}; + if(file_is_okay) { - for EachEnumVal(RD_EntityKind, k) + U64 file_version_code = version_from_str8(file_version); + if(file_version_code < Version(0, 9, 16)) { - RD_EntityKindFlags k_flags = rd_entity_kind_flags_table[k]; - if(k_flags & RD_EntityKindFlag_IsSerializedToConfig) - { - RD_EntityList entities = rd_query_cached_entity_list_with_kind(k); - for(RD_EntityNode *n = entities.first; n != 0; n = n->next) - { - if(n->entity->cfg_src == src) - { - rd_entity_mark_for_deletion(n->entity); - } - } - } - } - } - - //- rjf: apply all entities - { - for EachEnumVal(RD_EntityKind, k) - { - RD_EntityKindFlags k_flags = rd_entity_kind_flags_table[k]; - if(k_flags & RD_EntityKindFlag_IsSerializedToConfig) - { - RD_CfgVal *k_val = rd_cfg_val_from_string(table, d_entity_kind_name_lower_table[k]); - for(RD_CfgTree *k_tree = k_val->first; - k_tree != &d_nil_cfg_tree; - k_tree = k_tree->next) - { - if(k_tree->source != src) - { - continue; - } - RD_Entity *entity = rd_entity_alloc(rd_entity_root(), k); - rd_entity_equip_cfg_src(entity, k_tree->source); - - // rjf: iterate config tree - typedef struct Task Task; - struct Task - { - Task *next; - RD_Entity *entity; - MD_Node *n; - }; - Task start_task = {0, entity, k_tree->root}; - Task *first_task = &start_task; - Task *last_task = first_task; - for(Task *t = first_task; t != 0; t = t->next) - { - MD_Node *node = t->n; - for MD_EachNode(child, node->first) - { - // rjf: standalone string literals under an entity -> name - if(child->flags & MD_NodeFlag_StringLiteral && child->first == &md_nil_node) - { - String8 string = raw_from_escaped_str8(scratch.arena, child->string); - // TODO(rjf): @hack - hardcoding in the "EntityKind_Location" here - this is because - // i am assuming an entity *kind* can 'know' about the 'pathness' of a string. this is - // not the case. post-0.9.12 i need to fix this. - if(rd_entity_kind_flags_table[t->entity->kind] & RD_EntityKindFlag_NameIsPath && - t->entity->kind != RD_EntityKind_Location) - { - string = path_absolute_dst_from_relative_dst_src(scratch.arena, string, cfg_folder); - } - rd_entity_equip_name(t->entity, string); - } - - // rjf: standalone string literals under an entity, with a numeric child -> name & text location - if(child->flags & MD_NodeFlag_StringLiteral && child->first->flags & MD_NodeFlag_Numeric && child->first->first == &md_nil_node) - { - String8 string = raw_from_escaped_str8(scratch.arena, child->string); - if(rd_entity_kind_flags_table[t->entity->kind] & RD_EntityKindFlag_NameIsPath) - { - string = path_absolute_dst_from_relative_dst_src(scratch.arena, string, cfg_folder); - } - rd_entity_equip_name(t->entity, string); - S64 line = 0; - try_s64_from_str8_c_rules(child->first->string, &line); - TxtPt pt = txt_pt(line, 1); - rd_entity_equip_txt_pt(t->entity, pt); - } - - // rjf: standalone hex literals under an entity -> vaddr - if(child->flags & MD_NodeFlag_Numeric && child->first == &md_nil_node && str8_match(str8_substr(child->string, r1u64(0, 2)), str8_lit("0x"), 0)) - { - U64 vaddr = 0; - try_u64_from_str8_c_rules(child->string, &vaddr); - rd_entity_equip_vaddr(t->entity, vaddr); - } - - // rjf: specifically named entity equipment - if((str8_match(child->string, str8_lit("name"), StringMatchFlag_CaseInsensitive) || - str8_match(child->string, str8_lit("label"), StringMatchFlag_CaseInsensitive)) && - child->first != &md_nil_node) - { - String8 string = raw_from_escaped_str8(scratch.arena, child->first->string); - // TODO(rjf): @hack - hardcoding in the "EntityKind_Location" here - this is because - // i am assuming an entity *kind* can 'know' about the 'pathness' of a string. this is - // not the case. post-0.9.12 i need to fix this. - if(rd_entity_kind_flags_table[t->entity->kind] & RD_EntityKindFlag_NameIsPath && - (t->entity->kind != RD_EntityKind_Location || !md_node_is_nil(md_child_from_string(node, str8_lit("line"), 0)))) - { - string = path_absolute_dst_from_relative_dst_src(scratch.arena, string, cfg_folder); - } - rd_entity_equip_name(t->entity, string); - } - if((str8_match(child->string, str8_lit("active"), StringMatchFlag_CaseInsensitive) || - str8_match(child->string, str8_lit("enabled"), StringMatchFlag_CaseInsensitive)) && - child->first != &md_nil_node) - { - rd_entity_equip_disabled(t->entity, !str8_match(child->first->string, str8_lit("1"), 0)); - } - if(str8_match(child->string, str8_lit("disabled"), StringMatchFlag_CaseInsensitive) && child->first != &md_nil_node) - { - rd_entity_equip_disabled(t->entity, str8_match(child->first->string, str8_lit("1"), 0)); - } - if(str8_match(child->string, str8_lit("debug_subprocesses"), StringMatchFlag_CaseInsensitive) && child->first != &md_nil_node) - { - t->entity->debug_subprocesses = str8_match(child->first->string, str8_lit("1"), 0); - } - if(str8_match(child->string, str8_lit("hsva"), StringMatchFlag_CaseInsensitive) && child->first != &md_nil_node) - { - Vec4F32 hsva = {0}; - hsva.x = (F32)f64_from_str8(child->first->string); - hsva.y = (F32)f64_from_str8(child->first->next->string); - hsva.z = (F32)f64_from_str8(child->first->next->next->string); - hsva.w = (F32)f64_from_str8(child->first->next->next->next->string); - rd_entity_equip_color_hsva(t->entity, hsva); - } - if(str8_match(child->string, str8_lit("color"), StringMatchFlag_CaseInsensitive) && child->first != &md_nil_node) - { - Vec4F32 rgba = rgba_from_hex_string_4f32(child->first->string); - Vec4F32 hsva = hsva_from_rgba(rgba); - rd_entity_equip_color_hsva(t->entity, hsva); - } - if(str8_match(child->string, str8_lit("line"), StringMatchFlag_CaseInsensitive) && child->first != &md_nil_node) - { - S64 line = 0; - try_s64_from_str8_c_rules(child->first->string, &line); - TxtPt pt = txt_pt(line, 1); - rd_entity_equip_txt_pt(t->entity, pt); - } - if((str8_match(child->string, str8_lit("vaddr"), StringMatchFlag_CaseInsensitive) || - str8_match(child->string, str8_lit("addr"), StringMatchFlag_CaseInsensitive)) && - child->first != &md_nil_node) - { - U64 vaddr = 0; - try_u64_from_str8_c_rules(child->first->string, &vaddr); - rd_entity_equip_vaddr(t->entity, vaddr); - } - - // rjf: sub-entity -> create new task - RD_EntityKind sub_entity_kind = RD_EntityKind_Nil; - for EachEnumVal(RD_EntityKind, k2) - { - if(child->flags & MD_NodeFlag_Identifier && child->first != &md_nil_node && - (str8_match(child->string, d_entity_kind_name_lower_table[k2], StringMatchFlag_CaseInsensitive) || - (k2 == RD_EntityKind_Executable && str8_match(child->string, str8_lit("exe"), StringMatchFlag_CaseInsensitive)))) - { - Task *task = push_array(scratch.arena, Task, 1); - task->next = t->next; - task->entity = rd_entity_alloc(t->entity, k2); - task->n = child; - t->next = task; - break; - } - } - } - } - } - } - } - } - - //- rjf: apply exception code filters - RD_CfgVal *filter_tables = rd_cfg_val_from_string(table, str8_lit("exception_code_filters")); - for(RD_CfgTree *table = filter_tables->first; - table != &d_nil_cfg_tree; - table = table->next) - { - for MD_EachNode(rule, table->root->first) - { - String8 name = rule->string; - String8 val_string = rule->first->string; - U64 val = 0; - if(try_u64_from_str8_c_rules(val_string, &val)) - { - CTRL_ExceptionCodeKind kind = CTRL_ExceptionCodeKind_Null; - for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); - k < CTRL_ExceptionCodeKind_COUNT; - k = (CTRL_ExceptionCodeKind)(k+1)) - { - if(str8_match(name, ctrl_exception_code_kind_lowercase_code_string_table[k], 0)) - { - kind = k; - break; - } - } - if(kind != CTRL_ExceptionCodeKind_Null) - { - if(val) - { - rd_state->ctrl_exception_code_filters[kind/64] |= (1ull<<(kind%64)); - } - else - { - rd_state->ctrl_exception_code_filters[kind/64] &= ~(1ull<<(kind%64)); - } - } - } - } - } - - //- rjf: eliminate all windows - for(RD_Window *window = rd_state->first_window; window != 0; window = window->next) - { - if(window->cfg_src != src) - { - continue; - } - rd_cmd(RD_CmdKind_CloseWindow, .window = rd_handle_from_window(window)); - } - - //- rjf: apply fonts - { - FNT_Tag defaults[RD_FontSlot_COUNT] = - { - fnt_tag_from_static_data_string(&rd_default_main_font_bytes), - fnt_tag_from_static_data_string(&rd_default_code_font_bytes), - fnt_tag_from_static_data_string(&rd_icon_font_bytes), - }; - MemoryZeroArray(rd_state->cfg_font_tags); - { - RD_CfgVal *code_font_val = rd_cfg_val_from_string(table, str8_lit("code_font")); - RD_CfgVal *main_font_val = rd_cfg_val_from_string(table, str8_lit("main_font")); - MD_Node *code_font_node = code_font_val->last->root; - MD_Node *main_font_node = main_font_val->last->root; - String8 code_font_relative_path = code_font_node->first->string; - String8 main_font_relative_path = main_font_node->first->string; - if(!md_node_is_nil(code_font_node)) - { - arena_clear(rd_state->cfg_code_font_path_arena); - rd_state->cfg_code_font_path = raw_from_escaped_str8(rd_state->cfg_code_font_path_arena, code_font_relative_path); - } - if(!md_node_is_nil(main_font_node)) - { - arena_clear(rd_state->cfg_main_font_path_arena); - rd_state->cfg_main_font_path = raw_from_escaped_str8(rd_state->cfg_main_font_path_arena, main_font_relative_path); - } - String8 code_font_path = path_absolute_dst_from_relative_dst_src(scratch.arena, code_font_relative_path, cfg_folder); - String8 main_font_path = path_absolute_dst_from_relative_dst_src(scratch.arena, main_font_relative_path, cfg_folder); - if(os_file_path_exists(code_font_path) && !md_node_is_nil(code_font_node) && code_font_relative_path.size != 0) - { - rd_state->cfg_font_tags[RD_FontSlot_Code] = fnt_tag_from_path(code_font_path); - } - if(os_file_path_exists(main_font_path) && !md_node_is_nil(main_font_node) && main_font_relative_path.size != 0) - { - rd_state->cfg_font_tags[RD_FontSlot_Main] = fnt_tag_from_path(main_font_path); - } - } - for(RD_FontSlot slot = (RD_FontSlot)0; slot < RD_FontSlot_COUNT; slot = (RD_FontSlot)(slot+1)) - { - if(fnt_tag_match(fnt_tag_zero(), rd_state->cfg_font_tags[slot])) - { - rd_state->cfg_font_tags[slot] = defaults[slot]; - } - } - } - - //- rjf: build windows & panel layouts - RD_CfgVal *windows = rd_cfg_val_from_string(table, str8_lit("window")); - for(RD_CfgTree *window_tree = windows->first; - window_tree != &d_nil_cfg_tree; - window_tree = window_tree->next) - { - // rjf: skip wrong source - if(window_tree->source != src) - { - continue; - } - - // rjf: grab metadata - B32 is_fullscreen = 0; - B32 is_maximized = 0; - Axis2 top_level_split_axis = Axis2_X; - OS_Handle preferred_monitor = os_primary_monitor(); - Vec2F32 size = {0}; - F32 dpi = 0.f; - RD_SettingVal setting_vals[RD_SettingCode_COUNT] = {0}; - { - for MD_EachNode(n, window_tree->root->first) - { - if(n->flags & MD_NodeFlag_Identifier && - md_node_is_nil(n->first) && - str8_match(n->string, str8_lit("split_x"), StringMatchFlag_CaseInsensitive)) - { - top_level_split_axis = Axis2_X; - } - if(n->flags & MD_NodeFlag_Identifier && - md_node_is_nil(n->first) && - str8_match(n->string, str8_lit("split_y"), StringMatchFlag_CaseInsensitive)) - { - top_level_split_axis = Axis2_Y; - } - if(n->flags & MD_NodeFlag_Identifier && - md_node_is_nil(n->first) && - str8_match(n->string, str8_lit("fullscreen"), StringMatchFlag_CaseInsensitive)) - { - is_fullscreen = 1; - } - if(n->flags & MD_NodeFlag_Identifier && - md_node_is_nil(n->first) && - str8_match(n->string, str8_lit("maximized"), StringMatchFlag_CaseInsensitive)) - { - is_maximized = 1; - } - } - MD_Node *monitor_node = md_child_from_string(window_tree->root, str8_lit("monitor"), 0); - String8 preferred_monitor_name = monitor_node->first->string; - for(U64 idx = 0; idx < monitors.count; idx += 1) - { - String8 monitor_name = os_name_from_monitor(scratch.arena, monitors.v[idx]); - if(str8_match(monitor_name, preferred_monitor_name, StringMatchFlag_CaseInsensitive)) - { - preferred_monitor = monitors.v[idx]; - break; - } - } - Vec2F32 preferred_monitor_size = os_dim_from_monitor(preferred_monitor); - MD_Node *size_node = md_child_from_string(window_tree->root, str8_lit("size"), 0); - { - String8 x_string = size_node->first->string; - String8 y_string = size_node->first->next->string; - U64 x_u64 = 0; - U64 y_u64 = 0; - if(!try_u64_from_str8_c_rules(x_string, &x_u64)) - { - x_u64 = (U64)(preferred_monitor_size.x*2/3); - } - if(!try_u64_from_str8_c_rules(y_string, &y_u64)) - { - y_u64 = (U64)(preferred_monitor_size.y*2/3); - } - size.x = (F32)x_u64; - size.y = (F32)y_u64; - } - MD_Node *dpi_node = md_child_from_string(window_tree->root, str8_lit("dpi"), 0); - String8 dpi_string = md_string_from_children(scratch.arena, dpi_node); - dpi = f64_from_str8(dpi_string); - for EachEnumVal(RD_SettingCode, code) - { - MD_Node *code_node = md_child_from_string(window_tree->root, rd_setting_code_lower_string_table[code], 0); - if(!md_node_is_nil(code_node)) - { - S64 val_s64 = 0; - try_s64_from_str8_c_rules(code_node->first->string, &val_s64); - setting_vals[code].set = 1; - setting_vals[code].s32 = (S32)val_s64; - setting_vals[code].s32 = clamp_1s32(rd_setting_code_s32_range_table[code], setting_vals[code].s32); - } - } - } - - // rjf: open window - RD_Window *ws = rd_window_open(size, preferred_monitor, window_tree->source); - if(dpi != 0.f) { ws->last_dpi = dpi; } - for EachEnumVal(RD_SettingCode, code) - { - if(setting_vals[code].set == 0 && rd_setting_code_default_is_per_window_table[code]) - { - setting_vals[code] = rd_setting_code_default_val_table[code]; - } - } - MemoryCopy(ws->setting_vals, setting_vals, sizeof(setting_vals[0])*ArrayCount(setting_vals)); - - // rjf: build panel tree - MD_Node *panel_tree = md_child_from_string(window_tree->root, str8_lit("panels"), 0); - RD_Panel *panel_parent = ws->root_panel; - panel_parent->split_axis = top_level_split_axis; - MD_NodeRec rec = {0}; - for(MD_Node *n = panel_tree, *next = &md_nil_node; - !md_node_is_nil(n); - n = next) - { - // rjf: assume we're just moving to the next one initially... - next = n->next; - - // rjf: grab root panel - RD_Panel *panel = &rd_nil_panel; - if(n == panel_tree) - { - panel = ws->root_panel; - panel->pct_of_parent = 1.f; - } - - // rjf: allocate & insert non-root panels - these will have a numeric string, determining - // pct of parent - if(n->flags & MD_NodeFlag_Numeric) - { - panel = rd_panel_alloc(ws); - rd_panel_insert(panel_parent, panel_parent->last, panel); - panel->split_axis = axis2_flip(panel_parent->split_axis); - panel->pct_of_parent = (F32)f64_from_str8(n->string); - } - - // rjf: do general per-panel work - if(!rd_panel_is_nil(panel)) - { - // rjf: determine if this panel has panel children - B32 has_panel_children = 0; - for MD_EachNode(child, n->first) - { - if(child->flags & MD_NodeFlag_Numeric) - { - has_panel_children = 1; - break; - } - } - - // rjf: apply panel options - for MD_EachNode(op, n->first) - { - if(md_node_is_nil(op->first) && str8_match(op->string, str8_lit("tabs_on_bottom"), 0)) - { - panel->tab_side = Side_Max; - } - } - - // rjf: apply panel views/tabs/commands - RD_View *selected_view = &rd_nil_view; - for MD_EachNode(op, n->first) - { - RD_ViewRuleInfo *view_rule_info = rd_view_rule_info_from_string(op->string); - if(view_rule_info == &rd_nil_view_rule_info || has_panel_children != 0) - { - continue; - } - - // rjf: allocate view & apply view-specific parameterizations - RD_View *view = &rd_nil_view; - B32 view_is_selected = 0; - RD_ViewRuleInfoFlags view_rule_info_flags = view_rule_info->flags; - { - // rjf: allocate view - view = rd_view_alloc(); - - // rjf: check if this view is selected - view_is_selected = !md_node_is_nil(md_child_from_string(op, str8_lit("selected"), 0)); - - // rjf: read project path - String8 project_path = str8_lit(""); - { - MD_Node *project_node = md_child_from_string(op, str8_lit("project"), 0); - if(!md_node_is_nil(project_node)) - { - project_path = path_absolute_dst_from_relative_dst_src(scratch.arena, project_node->first->string, cfg_folder); - } - } - - // rjf: read view query string - String8 view_query = str8_lit(""); - { - String8 escaped_query = md_child_from_string(op, str8_lit("query"), 0)->first->string; - view_query = raw_from_escaped_str8(scratch.arena, escaped_query); - } - - // rjf: convert file queries from relative to absolute - { - String8 query_file_path = rd_file_path_from_eval_string(scratch.arena, view_query); - if(query_file_path.size != 0) - { - query_file_path = path_absolute_dst_from_relative_dst_src(scratch.arena, query_file_path, cfg_folder); - view_query = push_str8f(scratch.arena, "file:\"%S\"", query_file_path); - } - } - - // rjf: set up view - rd_view_equip_spec(view, view_rule_info, view_query, op); - if(project_path.size != 0) - { - arena_clear(view->project_path_arena); - view->project_path = push_str8_copy(view->project_path_arena, project_path); - } - } - - // rjf: insert - if(!rd_view_is_nil(view)) - { - rd_panel_insert_tab_view(panel, panel->last_tab_view, view); - if(view_is_selected) - { - selected_view = view; - } - } - } - - // rjf: select selected view - if(!rd_view_is_nil(selected_view)) - { - panel->selected_tab_view = rd_handle_from_view(selected_view); - } - - // rjf: recurse from this panel - if(has_panel_children) - { - next = n->first; - panel_parent = panel; - } - else for(MD_Node *p = n; - p != &md_nil_node && p != panel_tree; - p = p->parent, panel_parent = panel_parent->parent) - { - if(p->next != &md_nil_node) - { - next = p->next; - break; - } - } - } - } - - // rjf: initiate fullscreen - if(is_fullscreen) - { - os_window_set_fullscreen(ws->os, 1); - } - - // rjf: initiate maximize - if(is_maximized) - { - os_window_set_maximized(ws->os, 1); - } - - // rjf: focus the biggest panel - { - RD_Panel *best_leaf_panel = &rd_nil_panel; - F32 best_leaf_panel_area = 0; - Rng2F32 root_rect = r2f32p(0, 0, 1000, 1000); // NOTE(rjf): we can assume any size - just need proportions. - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) - { - if(rd_panel_is_nil(panel->first)) - { - Rng2F32 rect = rd_target_rect_from_panel(root_rect, ws->root_panel, panel); - Vec2F32 dim = dim_2f32(rect); - F32 area = dim.x*dim.y; - if(best_leaf_panel_area == 0 || area > best_leaf_panel_area) - { - best_leaf_panel_area = area; - best_leaf_panel = panel; - } - } - } - ws->focused_panel = best_leaf_panel; - } - } - - //- rjf: apply keybindings - if(src == RD_CfgSrc_User) - { - rd_clear_bindings(); - } - RD_CfgVal *keybindings = rd_cfg_val_from_string(table, str8_lit("keybindings")); - for(RD_CfgTree *keybinding_set = keybindings->first; - keybinding_set != &d_nil_cfg_tree; - keybinding_set = keybinding_set->next) - { - for MD_EachNode(keybind, keybinding_set->root->first) - { - String8 cmd_name = {0}; - OS_Key key = OS_Key_Null; - MD_Node *ctrl_node = &md_nil_node; - MD_Node *shift_node = &md_nil_node; - MD_Node *alt_node = &md_nil_node; - for MD_EachNode(child, keybind->first) - { - if(str8_match(child->string, str8_lit("ctrl"), 0)) - { - ctrl_node = child; - } - else if(str8_match(child->string, str8_lit("shift"), 0)) - { - shift_node = child; - } - else if(str8_match(child->string, str8_lit("alt"), 0)) - { - alt_node = child; - } - else - { - OS_Key k = rd_os_key_from_cfg_string(child->string); - if(k != OS_Key_Null) - { - key = k; - } - else - { - cmd_name = child->string; - for(U64 idx = 0; idx < ArrayCount(rd_binding_version_remap_old_name_table); idx += 1) - { - if(str8_match(rd_binding_version_remap_old_name_table[idx], child->string, StringMatchFlag_CaseInsensitive)) - { - String8 new_name = rd_binding_version_remap_new_name_table[idx]; - cmd_name = new_name; - } - } - } - } - } - if(cmd_name.size != 0 && key != OS_Key_Null) - { - OS_Modifiers flags = 0; - if(!md_node_is_nil(ctrl_node)) { flags |= OS_Modifier_Ctrl; } - if(!md_node_is_nil(shift_node)) { flags |= OS_Modifier_Shift; } - if(!md_node_is_nil(alt_node)) { flags |= OS_Modifier_Alt; } - RD_Binding binding = {key, flags}; - rd_bind_name(cmd_name, binding); - } - } - } - - //- rjf: reset theme to default - MemoryCopy(rd_state->cfg_theme_target.colors, rd_theme_preset_colors__default_dark, sizeof(rd_theme_preset_colors__default_dark)); - MemoryCopy(rd_state->cfg_theme.colors, rd_theme_preset_colors__default_dark, sizeof(rd_theme_preset_colors__default_dark)); - - //- rjf: apply theme presets - RD_CfgVal *color_preset = rd_cfg_val_from_string(table, str8_lit("color_preset")); - B32 preset_applied = 0; - if(color_preset != &d_nil_cfg_val) - { - String8 color_preset_name = color_preset->last->root->first->string; - RD_ThemePreset preset = (RD_ThemePreset)0; - B32 found_preset = 0; - for(RD_ThemePreset p = (RD_ThemePreset)0; p < RD_ThemePreset_COUNT; p = (RD_ThemePreset)(p+1)) - { - if(str8_match(color_preset_name, rd_theme_preset_code_string_table[p], StringMatchFlag_CaseInsensitive)) - { - found_preset = 1; - preset = p; - break; - } - } - if(found_preset) - { - preset_applied = 1; - MemoryCopy(rd_state->cfg_theme_target.colors, rd_theme_preset_colors_table[preset], sizeof(rd_theme_preset_colors__default_dark)); - MemoryCopy(rd_state->cfg_theme.colors, rd_theme_preset_colors_table[preset], sizeof(rd_theme_preset_colors__default_dark)); - } - } - - //- rjf: apply individual theme colors - B8 theme_color_hit[RD_ThemeColor_COUNT] = {0}; - RD_CfgVal *colors = rd_cfg_val_from_string(table, str8_lit("colors")); - for(RD_CfgTree *colors_set = colors->first; - colors_set != &d_nil_cfg_tree; - colors_set = colors_set->next) - { - for MD_EachNode(color, colors_set->root->first) - { - String8 saved_color_name = color->string; - String8List candidate_color_names = {0}; - str8_list_push(scratch.arena, &candidate_color_names, saved_color_name); - for(U64 idx = 0; idx < ArrayCount(rd_theme_color_version_remap_old_name_table); idx += 1) - { - if(str8_match(rd_theme_color_version_remap_old_name_table[idx], saved_color_name, StringMatchFlag_CaseInsensitive)) - { - str8_list_push(scratch.arena, &candidate_color_names, rd_theme_color_version_remap_new_name_table[idx]); - } - } - for(String8Node *name_n = candidate_color_names.first; name_n != 0; name_n = name_n->next) - { - String8 name = name_n->string; - RD_ThemeColor color_code = RD_ThemeColor_Null; - for(RD_ThemeColor c = RD_ThemeColor_Null; c < RD_ThemeColor_COUNT; c = (RD_ThemeColor)(c+1)) - { - if(str8_match(rd_theme_color_cfg_string_table[c], name, StringMatchFlag_CaseInsensitive)) - { - color_code = c; - break; - } - } - if(color_code != RD_ThemeColor_Null) - { - theme_color_hit[color_code] = 1; - MD_Node *hex_cfg = color->first; - String8 hex_string = hex_cfg->string; - U64 hex_val = 0; - try_u64_from_str8_c_rules(hex_string, &hex_val); - Vec4F32 color_rgba = rgba_from_u32((U32)hex_val); - rd_state->cfg_theme_target.colors[color_code] = color_rgba; - if(rd_state->frame_index <= 2) - { - rd_state->cfg_theme.colors[color_code] = color_rgba; - } - } - } - } - } - - //- rjf: no preset -> autofill all missing colors from the preset with the most similar background - if(!preset_applied) - { - RD_ThemePreset closest_preset = RD_ThemePreset_DefaultDark; - F32 closest_preset_bg_distance = 100000000; - for(RD_ThemePreset p = (RD_ThemePreset)0; p < RD_ThemePreset_COUNT; p = (RD_ThemePreset)(p+1)) - { - Vec4F32 cfg_bg = rd_state->cfg_theme_target.colors[RD_ThemeColor_BaseBackground]; - Vec4F32 pre_bg = rd_theme_preset_colors_table[p][RD_ThemeColor_BaseBackground]; - Vec4F32 diff = sub_4f32(cfg_bg, pre_bg); - Vec3F32 diff3 = diff.xyz; - F32 distance = length_3f32(diff3); - if(distance < closest_preset_bg_distance) - { - closest_preset = p; - closest_preset_bg_distance = distance; - } - } - for(RD_ThemeColor c = (RD_ThemeColor)(RD_ThemeColor_Null+1); - c < RD_ThemeColor_COUNT; - c = (RD_ThemeColor)(c+1)) - { - if(!theme_color_hit[c]) - { - rd_state->cfg_theme_target.colors[c] = rd_state->cfg_theme.colors[c] = rd_theme_preset_colors_table[closest_preset][c]; - } - } - } - - //- rjf: if theme colors are all zeroes, then set to default - config appears busted - { - B32 all_colors_are_zero = 1; - Vec4F32 zero_color = {0}; - for(RD_ThemeColor c = (RD_ThemeColor)(RD_ThemeColor_Null+1); c < RD_ThemeColor_COUNT; c = (RD_ThemeColor)(c+1)) - { - if(!MemoryMatchStruct(&rd_state->cfg_theme_target.colors[c], &zero_color)) - { - all_colors_are_zero = 0; - break; - } - } - if(all_colors_are_zero) - { - MemoryCopy(rd_state->cfg_theme_target.colors, rd_theme_preset_colors__default_dark, sizeof(rd_theme_preset_colors__default_dark)); - MemoryCopy(rd_state->cfg_theme.colors, rd_theme_preset_colors__default_dark, sizeof(rd_theme_preset_colors__default_dark)); - } - } - - //- rjf: apply settings - B8 setting_codes_hit[RD_SettingCode_COUNT] = {0}; - MemoryZero(&rd_state->cfg_setting_vals[src][0], sizeof(RD_SettingVal)*RD_SettingCode_COUNT); - for EachEnumVal(RD_SettingCode, code) - { - String8 name = rd_setting_code_lower_string_table[code]; - RD_CfgVal *code_cfg_val = rd_cfg_val_from_string(table, name); - RD_CfgTree *code_tree = code_cfg_val->last; - if(code_tree->source == src) - { - MD_Node *val_node = code_tree->root->first; - S64 val = 0; - if(try_s64_from_str8_c_rules(val_node->string, &val)) - { - rd_state->cfg_setting_vals[src][code].set = 1; - rd_state->cfg_setting_vals[src][code].s32 = (S32)val; - } - setting_codes_hit[code] = !md_node_is_nil(val_node); - } - } - - //- rjf: if config applied 0 settings, we need to do some sensible default - if(src == RD_CfgSrc_User) - { - for EachEnumVal(RD_SettingCode, code) - { - if(!setting_codes_hit[code]) - { - rd_state->cfg_setting_vals[src][code] = rd_setting_code_default_val_table[code]; - } - } - } - - //- rjf: if config opened 0 windows, we need to do some sensible default - if(src == RD_CfgSrc_User && windows->first == &d_nil_cfg_tree) - { - OS_Handle preferred_monitor = os_primary_monitor(); - Vec2F32 monitor_dim = os_dim_from_monitor(preferred_monitor); - Vec2F32 window_dim = v2f32(monitor_dim.x*4/5, monitor_dim.y*4/5); - RD_Window *ws = rd_window_open(window_dim, preferred_monitor, RD_CfgSrc_User); - F32 font_size = (F32)ws->setting_vals[RD_SettingCode_MainFontSize].s32; - F32 num_lines_in_monitor_height = monitor_dim.y / font_size; - if(num_lines_in_monitor_height < 100) - { - rd_cmd(RD_CmdKind_ResetToCompactPanels, .window = rd_handle_from_window(ws)); + RD_CfgList (*legacy_parse_function)(Arena *arena, String8 file_path, String8 data) = rd_cfg_tree_list_from_string__pre_0_9_16; + file_cfg_list = legacy_parse_function(scratch.arena, file_path, file_data); } else { - rd_cmd(RD_CmdKind_ResetToDefaultPanels, .window = rd_handle_from_window(ws)); + file_cfg_list = rd_cfg_tree_list_from_string(scratch.arena, str8_chop_last_slash(file_path), file_data); } } - //- rjf: if config bound 0 keys, we need to do some sensible default - if(src == RD_CfgSrc_User && rd_state->key_map_total_count == 0) + //- rjf: store path + if(file_is_okay) { - for(U64 idx = 0; idx < ArrayCount(rd_default_binding_table); idx += 1) + switch(kind) { - RD_StringBindingPair *pair = &rd_default_binding_table[idx]; - rd_bind_name(pair->string, pair->binding); - } - } - - //- rjf: always ensure that the meta controls have bindings - if(src == RD_CfgSrc_User) - { - struct - { - String8 name; - OS_Key fallback_key; - } - meta_ctrls[] = - { - { rd_cmd_kind_info_table[RD_CmdKind_Edit].string, OS_Key_F2 }, - { rd_cmd_kind_info_table[RD_CmdKind_Accept].string, OS_Key_Return }, - { rd_cmd_kind_info_table[RD_CmdKind_Cancel].string, OS_Key_Esc }, - }; - for(U64 idx = 0; idx < ArrayCount(meta_ctrls); idx += 1) - { - RD_BindingList bindings = rd_bindings_from_name(scratch.arena, meta_ctrls[idx].name); - if(bindings.count == 0) + default:{}break; + case RD_CmdKind_OpenUser: { - RD_Binding binding = {meta_ctrls[idx].fallback_key, 0}; - rd_bind_name(meta_ctrls[idx].name, binding); + arena_clear(rd_state->user_path_arena); + rd_state->user_path = push_str8_copy(rd_state->user_path_arena, file_path); + }break; + case RD_CmdKind_OpenProject: + { + arena_clear(rd_state->project_path_arena); + rd_state->project_path = push_str8_copy(rd_state->project_path_arena, file_path); + }break; + } + } + + //- rjf: insert the new cfg entities into this file tree + if(file_is_okay) + { + for(RD_CfgNode *n = file_cfg_list.first; n != 0; n = n->next) + { + rd_cfg_insert_child(file_root, file_root->last, n->v); + } + } + + //- rjf: if config did not open any windows for the user, then we need to open a sensible default + if(file_is_okay && kind == RD_CmdKind_OpenUser) + { + RD_CfgList all_user_windows = rd_cfg_child_list_from_string(scratch.arena, file_root, str8_lit("window")); + if(all_user_windows.count == 0) + { + OS_Handle monitor = os_primary_monitor(); + String8 monitor_name = os_name_from_monitor(scratch.arena, monitor); + Vec2F32 monitor_dim = os_dim_from_monitor(monitor); + F32 monitor_dpi = os_dpi_from_monitor(monitor); + Vec2F32 window_dim = v2f32(monitor_dim.x*4/5, monitor_dim.y*4/5); + if(window_dim.x == 0 || window_dim.y == 0) + { + window_dim = v2f32(1280, 720); + } + RD_Cfg *new_window = rd_cfg_new(file_root, str8_lit("window")); + RD_Cfg *size = rd_cfg_new(new_window, str8_lit("size")); + rd_cfg_newf(size, "%f", window_dim.x); + rd_cfg_newf(size, "%f", window_dim.y); + F32 line_height_guess = 11.f * (monitor_dpi / 96.f); + F32 num_lines_in_monitor_height = monitor_dim.y / line_height_guess; + if(num_lines_in_monitor_height < 100) + { + rd_cmd(RD_CmdKind_ResetToCompactPanels, .window = new_window->id); + } + else + { + rd_cmd(RD_CmdKind_ResetToDefaultPanels, .window = new_window->id); } } } + + //- rjf: if config did not define any keybindings for the user, then we need to build a sensible default + if(file_is_okay && kind == RD_CmdKind_OpenUser) + { + RD_CfgList all_keybindings = rd_cfg_child_list_from_string(scratch.arena, file_root, str8_lit("keybindings")); + if(all_keybindings.count == 0) + { + rd_cmd(RD_CmdKind_ResetToDefaultBindings); + } + } + + //- rjf: record last-opened user in config directory + if(file_is_okay && kind == RD_CmdKind_OpenUser) + { + String8 last_user_path = push_str8f(scratch.arena, "%S/raddbg/last_user", os_get_process_info()->user_program_data_path); + os_write_data_to_file_path(last_user_path, file_path); + } + + //- rjf: record recently-opened projects in the user + if(file_is_okay && kind == RD_CmdKind_OpenProject) + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_CfgList recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + RD_Cfg *recent_project = &rd_nil_cfg; + for(RD_CfgNode *n = recent_projects.first; n != 0; n = n->next) + { + if(path_match_normalized(rd_path_from_cfg(n->v), file_path)) + { + recent_project = n->v; + break; + } + } + if(recent_project == &rd_nil_cfg) + { + recent_project = rd_cfg_new(user, str8_lit("recent_project")); + RD_Cfg *path_root = rd_cfg_new(recent_project, str8_lit("path")); + rd_cfg_new(path_root, path_absolute_dst_from_relative_dst_src(scratch.arena, file_path, str8_chop_last_slash(rd_state->user_path))); + } + rd_cfg_unhook(user, recent_project); + rd_cfg_insert_child(user, &rd_nil_cfg, recent_project); + recent_projects = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("recent_project")); + if(recent_projects.count > 32) + { + rd_cfg_release(recent_projects.last->v); + } + } + + //- rjf: eliminate all project-filtered tab focuses + if(file_is_okay && kind == RD_CmdKind_OpenProject) + { + RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + { + RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, n->v); + for(RD_PanelNode *panel = panels.root; panel != &rd_nil_panel_node; panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) + { + if(rd_cfg_is_project_filtered(panel->selected_tab)) + { + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + { + RD_Cfg *tab = tab_n->v; + if(!rd_cfg_is_project_filtered(tab)) + { + rd_cmd(RD_CmdKind_FocusTab, .tab = tab->id); + break; + } + } + } + } + } + } + + //- rjf: if we've just loaded the user, and we do not have a project path, + // then we should try to look at the user's data for recent projects and + // load one of those, *or* just the default. + if(file_is_okay && kind == RD_CmdKind_OpenUser && rd_state->project_path.size == 0) + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *recent_project = rd_cfg_child_from_string(user, str8_lit("recent_project")); + String8 project_path = rd_path_from_cfg(recent_project); + if(project_path.size == 0) + { + String8 user_program_data_path = os_get_process_info()->user_program_data_path; + String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg")); + os_make_directory(user_data_folder); + project_path = push_str8f(scratch.arena, "%S/default.raddbg_project", user_data_folder); + } + rd_cmd(RD_CmdKind_OpenProject, .file_path = project_path); + } + + //- rjf: update all window titles + if(file_is_okay) + { + String8 window_title = rd_push_window_title(scratch.arena); + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) + { + os_window_set_title(ws->os, window_title); + } + } + }break; + case RD_CmdKind_NewUser: + case RD_CmdKind_NewProject: + { + String8 new_path = rd_regs()->file_path; + B32 file_will_be_overwritten = (os_properties_from_file_path(new_path).created != 0); + UI_Key key = ui_key_from_string(ui_key_zero(), str8_lit("new_config_overwrite_confirm")); + if(file_will_be_overwritten && !rd_regs()->force_confirm && !ui_key_match(rd_state->popup_key, key)) + { + rd_state->popup_key = key; + rd_state->popup_active = 1; + arena_clear(rd_state->popup_arena); + MemoryZeroStruct(&rd_state->popup_cmds); + rd_state->popup_title = push_str8f(rd_state->popup_arena, "Are you sure you want to save to this path?"); + rd_state->popup_desc = push_str8f(rd_state->popup_arena, "The existing file at '%S' will be overwritten.", new_path); + RD_Regs *regs = rd_regs_copy(rd_frame_arena(), rd_regs()); + regs->force_confirm = 1; + rd_cmd_list_push_new(rd_state->popup_arena, &rd_state->popup_cmds, rd_cmd_kind_info_table[kind].string, regs); + } + else switch(kind) + { + default:{}break; + case RD_CmdKind_NewUser: + { + os_delete_file_at_path(new_path); + rd_cmd(RD_CmdKind_OpenUser, .file_path = new_path); + }break; + case RD_CmdKind_NewProject: + { + os_delete_file_at_path(new_path); + rd_cmd(RD_CmdKind_OpenProject, .file_path = new_path); + }break; + } + }break; + case RD_CmdKind_SaveUser: + case RD_CmdKind_SaveProject: + { + String8 new_path = rd_regs()->file_path; + B32 file_will_be_overwritten = (os_properties_from_file_path(new_path).created != 0); + UI_Key key = ui_key_from_string(ui_key_zero(), str8_lit("save_config_overwrite_confirm")); + if(file_will_be_overwritten && !rd_regs()->force_confirm && !ui_key_match(rd_state->popup_key, key)) + { + rd_state->popup_key = key; + rd_state->popup_active = 1; + arena_clear(rd_state->popup_arena); + MemoryZeroStruct(&rd_state->popup_cmds); + rd_state->popup_title = push_str8f(rd_state->popup_arena, "Are you sure you want to save to this path?"); + rd_state->popup_desc = push_str8f(rd_state->popup_arena, "The existing file at '%S' will be overwritten.", new_path); + RD_Regs *regs = rd_regs_copy(rd_frame_arena(), rd_regs()); + regs->force_confirm = 1; + rd_cmd_list_push_new(rd_state->popup_arena, &rd_state->popup_cmds, rd_cmd_kind_info_table[kind].string, regs); + } + else switch(kind) + { + default:{}break; + case RD_CmdKind_SaveUser: + { + arena_clear(rd_state->user_path_arena); + rd_state->user_path = push_str8_copy(rd_state->user_path_arena, new_path); + rd_cmd(RD_CmdKind_WriteUserData); + }break; + case RD_CmdKind_SaveProject: + { + arena_clear(rd_state->project_path_arena); + rd_state->project_path = push_str8_copy(rd_state->project_path_arena, new_path); + rd_cmd(RD_CmdKind_WriteProjectData); + }break; + } }break; //- rjf: writing config changes - case RD_CmdKind_WriteUserData: - case RD_CmdKind_WriteProjectData: + case RD_CmdKind_WriteUserData: dst_path = rd_state->user_path; bucket_name = str8_lit("user"); goto write; + case RD_CmdKind_WriteProjectData: dst_path = rd_state->project_path; bucket_name = str8_lit("project"); goto write; + write:; { - RD_CfgSrc src = RD_CfgSrc_User; - for(RD_CfgSrc s = (RD_CfgSrc)0; s < RD_CfgSrc_COUNT; s = (RD_CfgSrc)(s+1)) + B32 dst_exists = (os_properties_from_file_path(dst_path).created != 0); + String8 temp_path = push_str8f(scratch.arena, "%S.temp", dst_path); + String8 overwritten_path = push_str8f(scratch.arena, "%S.old", dst_path); + RD_Cfg *tree_root = rd_cfg_child_from_string(rd_state->root_cfg, bucket_name); + String8List strings = {0}; + str8_list_pushf(scratch.arena, &strings, "// raddbg %s %S file\n\n", BUILD_VERSION_STRING_LITERAL, bucket_name); + for(RD_Cfg *child = tree_root->first; child != &rd_nil_cfg; child = child->next) { - if(kind == rd_cfg_src_write_cmd_kind_table[s]) - { - src = s; - break; - } + str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, str8_chop_last_slash(dst_path), child)); + } + String8 data = str8_list_join(scratch.arena, &strings, 0); + B32 temp_write_good = os_write_data_to_file_path(temp_path, data); + B32 old_move_good = (temp_write_good && (!dst_exists || os_move_file_path(overwritten_path, dst_path))); + B32 new_move_good = (old_move_good && os_move_file_path(dst_path, temp_path)); + if(new_move_good && dst_exists) + { + os_delete_file_at_path(overwritten_path); + } + else if(!new_move_good && old_move_good && dst_exists) + { + os_move_file_path(dst_path, overwritten_path); } - String8 path = rd_cfg_path_from_src(src); - String8List rd_strs = rd_cfg_strings_from_gfx(scratch.arena, path, src); - String8 header = push_str8f(scratch.arena, "// raddbg %s file\n\n", rd_cfg_src_string_table[src].str); - String8List strs = {0}; - str8_list_push(scratch.arena, &strs, header); - str8_list_concat_in_place(&strs, &rd_strs); - String8 data = str8_list_join(scratch.arena, &strs, 0); - String8 data_indented = indented_from_string(scratch.arena, data); - os_write_data_to_file_path(path, data_indented); }break; - //- rjf: code navigation - case RD_CmdKind_FindTextForward: - case RD_CmdKind_FindTextBackward: + //- rjf: opening user/project settings + case RD_CmdKind_UserSettings: { - rd_set_search_string(rd_regs()->string); + rd_cmd(RD_CmdKind_PushQuery, .expr = str8_lit("query:user_settings"), .do_implicit_root = 1, .do_big_rows = 1, .do_lister = 1); }break; - - //- rjf: find next and find prev - case RD_CmdKind_FindNext: + case RD_CmdKind_ProjectSettings: { - rd_cmd(RD_CmdKind_FindTextForward, .string = rd_push_search_string(scratch.arena)); - }break; - case RD_CmdKind_FindPrev: - { - rd_cmd(RD_CmdKind_FindTextBackward, .string = rd_push_search_string(scratch.arena)); + rd_cmd(RD_CmdKind_PushQuery, .expr = str8_lit("query:project_settings"), .do_implicit_root = 1, .do_big_rows = 1, .do_lister = 1); }break; //- rjf: font sizes - case RD_CmdKind_IncUIFontScale: + case RD_CmdKind_IncWindowFontSize: cfg = rd_cfg_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto inc_font_size; + case RD_CmdKind_IncViewFontSize: cfg = rd_cfg_from_id(rd_regs()->view); goto inc_font_size; + inc_font_size:; + if(cfg != &rd_nil_cfg) { fnt_reset(); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - window->setting_vals[RD_SettingCode_MainFontSize].set = 1; - window->setting_vals[RD_SettingCode_MainFontSize].s32 += 1; - window->setting_vals[RD_SettingCode_MainFontSize].s32 = clamp_1s32(rd_setting_code_s32_range_table[RD_SettingCode_MainFontSize], window->setting_vals[RD_SettingCode_MainFontSize].s32); - } + F32 current_font_size = rd_font_size(); + F32 new_font_size = current_font_size+1; + new_font_size = Clamp(6.f, new_font_size, 72.f); + RD_Cfg *font_size_cfg = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("font_size")); + rd_cfg_new_replacef(font_size_cfg, "%I64u", (U64)new_font_size); }break; - case RD_CmdKind_DecUIFontScale: + case RD_CmdKind_DecWindowFontSize: cfg = rd_cfg_from_id(rd_regs()->window); rd_regs()->view = 0; rd_regs()->tab = 0; goto dec_font_size; + case RD_CmdKind_DecViewFontSize: cfg = rd_cfg_from_id(rd_regs()->view); goto dec_font_size; + dec_font_size:; + if(cfg != &rd_nil_cfg) { fnt_reset(); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - window->setting_vals[RD_SettingCode_MainFontSize].set = 1; - window->setting_vals[RD_SettingCode_MainFontSize].s32 -= 1; - window->setting_vals[RD_SettingCode_MainFontSize].s32 = clamp_1s32(rd_setting_code_s32_range_table[RD_SettingCode_MainFontSize], window->setting_vals[RD_SettingCode_MainFontSize].s32); - } - }break; - case RD_CmdKind_IncCodeFontScale: - { - fnt_reset(); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - window->setting_vals[RD_SettingCode_CodeFontSize].set = 1; - window->setting_vals[RD_SettingCode_CodeFontSize].s32 += 1; - window->setting_vals[RD_SettingCode_CodeFontSize].s32 = clamp_1s32(rd_setting_code_s32_range_table[RD_SettingCode_CodeFontSize], window->setting_vals[RD_SettingCode_CodeFontSize].s32); - } - }break; - case RD_CmdKind_DecCodeFontScale: - { - fnt_reset(); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - if(window != 0) - { - window->setting_vals[RD_SettingCode_CodeFontSize].set = 1; - window->setting_vals[RD_SettingCode_CodeFontSize].s32 -= 1; - window->setting_vals[RD_SettingCode_CodeFontSize].s32 = clamp_1s32(rd_setting_code_s32_range_table[RD_SettingCode_CodeFontSize], window->setting_vals[RD_SettingCode_CodeFontSize].s32); - } + F32 current_font_size = rd_font_size(); + F32 new_font_size = current_font_size-1; + new_font_size = Clamp(6.f, new_font_size, 72.f); + RD_Cfg *font_size_cfg = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("font_size")); + rd_cfg_new_replacef(font_size_cfg, "%I64u", (U64)new_font_size); }break; //- rjf: panel creation @@ -13662,109 +13186,181 @@ rd_frame(void) case RD_CmdKind_SplitPanel: { split_dir = rd_regs()->dir2; - split_panel = rd_panel_from_handle(rd_regs()->dst_panel); + split_panel = rd_cfg_from_id(rd_regs()->dst_panel); }goto split; split:; if(split_dir != Dir2_Invalid) { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - if(rd_panel_is_nil(split_panel)) - { - split_panel = ws->focused_panel; - } - RD_Panel *new_panel = &rd_nil_panel; + // rjf: unpack Axis2 split_axis = axis2_from_dir2(split_dir); Side split_side = side_from_dir2(split_dir); - RD_Panel *panel = split_panel; - RD_Panel *parent = panel->parent; - if(!rd_panel_is_nil(parent) && parent->split_axis == split_axis) + if(split_panel == &rd_nil_cfg) { - RD_Panel *next = rd_panel_alloc(ws); - rd_panel_insert(parent, split_side == Side_Max ? panel : panel->prev, next); - next->pct_of_parent = 1.f/parent->child_count; - for(RD_Panel *child = parent->first; !rd_panel_is_nil(child); child = child->next) - { - if(child != next) - { - child->pct_of_parent *= (F32)(parent->child_count-1) / (parent->child_count); - } - } - ws->focused_panel = next; - new_panel = next; + split_panel = rd_cfg_from_id(rd_regs()->panel); } + RD_Cfg *new_panel_cfg = &rd_nil_cfg; + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, split_panel); + RD_PanelNode *panel_root = panel_tree.root; + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_root, split_panel); + RD_PanelNode *parent = panel->parent; + + // rjf: splitting on same axis as parent -> insert new sibling on same axis, adjust sizes + if(parent != &rd_nil_panel_node && parent->split_axis == split_axis) + { + RD_Cfg *parent_cfg = parent->cfg; + RD_Cfg *panel_cfg = panel->cfg; + RD_Cfg *new_cfg = rd_cfg_alloc(); + rd_cfg_insert_child(parent_cfg, split_side == Side_Max ? panel_cfg : panel_cfg->prev, new_cfg); + rd_cfg_equip_stringf(new_cfg, "%f", 1.f/(parent->child_count+1)); + for(RD_PanelNode *child = parent->first; child != &rd_nil_panel_node; child = child->next) + { + F32 old_pct = child->pct_of_parent; + F32 new_pct = old_pct * ((F32)(parent->child_count) / (parent->child_count+1)); + rd_cfg_equip_stringf(child->cfg, "%f", new_pct); + } + new_panel_cfg = new_cfg; + } + + // rjf: splitting on opposite axis as parent - need to create new replacement node, + new sibling else { - RD_Panel *pre_prev = panel->prev; - RD_Panel *pre_parent = parent; - RD_Panel *new_parent = rd_panel_alloc(ws); - new_parent->pct_of_parent = panel->pct_of_parent; - if(!rd_panel_is_nil(pre_parent)) + RD_Cfg *split_panel_prev = panel->prev->cfg; + RD_Cfg *new_parent = rd_cfg_alloc(); + RD_Cfg *new_sibling = rd_cfg_alloc(); + rd_cfg_equip_string(new_parent, split_panel->string); + rd_cfg_equip_string(split_panel, str8_lit("0.5")); + rd_cfg_equip_string(new_sibling, str8_lit("0.5")); + if(parent->cfg != &rd_nil_cfg) { - rd_panel_remove(pre_parent, panel); - rd_panel_insert(pre_parent, pre_prev, new_parent); + rd_cfg_unhook(parent->cfg, split_panel); + rd_cfg_insert_child(parent->cfg, split_panel_prev, new_parent); } else { - ws->root_panel = new_parent; - } - RD_Panel *left = panel; - RD_Panel *right = rd_panel_alloc(ws); - new_panel = right; - if(split_side == Side_Min) - { - Swap(RD_Panel *, left, right); - } - rd_panel_insert(new_parent, &rd_nil_panel, left); - rd_panel_insert(new_parent, left, right); - new_parent->split_axis = split_axis; - left->pct_of_parent = 0.5f; - right->pct_of_parent = 0.5f; - ws->focused_panel = new_panel; - } - if(!rd_panel_is_nil(new_panel->prev)) - { - Rng2F32 prev_rect_pct = new_panel->prev->animated_rect_pct; - new_panel->animated_rect_pct = prev_rect_pct; - new_panel->animated_rect_pct.p0.v[split_axis] = new_panel->animated_rect_pct.p1.v[split_axis]; - } - if(!rd_panel_is_nil(new_panel->next)) - { - Rng2F32 next_rect_pct = new_panel->next->animated_rect_pct; - new_panel->animated_rect_pct = next_rect_pct; - new_panel->animated_rect_pct.p1.v[split_axis] = new_panel->animated_rect_pct.p0.v[split_axis]; - } - RD_Panel *move_tab_panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *move_tab = rd_view_from_handle(rd_regs()->view); - if(!rd_panel_is_nil(new_panel) && !rd_view_is_nil(move_tab) && !rd_panel_is_nil(move_tab_panel) && - kind == RD_CmdKind_SplitPanel) - { - rd_panel_remove_tab_view(move_tab_panel, move_tab); - rd_panel_insert_tab_view(new_panel, new_panel->last_tab_view, move_tab); - new_panel->selected_tab_view = rd_handle_from_view(move_tab); - B32 move_tab_panel_is_empty = 1; - for(RD_View *v = move_tab_panel->first_tab_view; !rd_view_is_nil(v); v = v->order_next) - { - if(!rd_view_is_project_filtered(v)) + rd_cfg_equip_string(new_parent, str8_lit("panels")); + RD_Cfg *window_cfg = rd_window_from_cfg(split_panel); + rd_cfg_insert_child(window_cfg, window_cfg->last, new_parent); + if(split_axis == Axis2_X) { - move_tab_panel_is_empty = 0; - break; + rd_cfg_child_from_string_or_alloc(window_cfg, str8_lit("split_x")); + } + else + { + rd_cfg_release(rd_cfg_child_from_string(window_cfg, str8_lit("split_x"))); } } - if(move_tab_panel_is_empty && move_tab_panel != ws->root_panel && - move_tab_panel != new_panel->prev && move_tab_panel != new_panel->next) + RD_Cfg *min = split_panel; + RD_Cfg *max = new_sibling; + if(split_side == Side_Min) { - rd_cmd(RD_CmdKind_ClosePanel, .panel = rd_handle_from_panel(move_tab_panel)); + Swap(RD_Cfg *, min, max); } + rd_cfg_insert_child(new_parent, new_parent->last, min); + rd_cfg_insert_child(new_parent, new_parent->last, max); + new_panel_cfg = new_sibling; + } + + // rjf: pre-emptively set up the animation rectangle, depending on where + // the new panel was inserted + { + RD_WindowState *ws = rd_window_state_from_cfg(new_panel_cfg); + if(ws != &rd_nil_window_state) + { + ui_select_state(ws->ui); + RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, new_panel_cfg); + RD_PanelNode *new_panel = rd_panel_node_from_tree_cfg(new_panel_tree.root, new_panel_cfg); + Rng2F32 stub_content_rect = r2f32p(0, 0, 1000, 1000); + Vec2F32 stub_content_rect_dim = dim_2f32(stub_content_rect); + Rng2F32 new_rect_px = rd_target_rect_from_panel_node(stub_content_rect, new_panel_tree.root, new_panel); + Rng2F32 new_rect_pct = r2f32p(new_rect_px.x0/stub_content_rect_dim.x, + new_rect_px.y0/stub_content_rect_dim.y, + new_rect_px.x1/stub_content_rect_dim.x, + new_rect_px.y1/stub_content_rect_dim.y); + if(new_panel->prev != &rd_nil_panel_node) + { + Rng2F32 target_prev_rect_px = rd_target_rect_from_panel_node(stub_content_rect, panel_tree.root, rd_panel_node_from_tree_cfg(panel_tree.root, new_panel->prev->cfg)); + Rng2F32 target_prev_rect_pct = r2f32p(target_prev_rect_px.x0/stub_content_rect_dim.x, + target_prev_rect_px.y0/stub_content_rect_dim.y, + target_prev_rect_px.x1/stub_content_rect_dim.x, + target_prev_rect_px.y1/stub_content_rect_dim.y); + Rng2F32 prev_rect_pct = r2f32p(ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x0", new_panel->prev->cfg), target_prev_rect_pct.x0, .initial = target_prev_rect_pct.x0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y0", new_panel->prev->cfg), target_prev_rect_pct.y0, .initial = target_prev_rect_pct.y0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x1", new_panel->prev->cfg), target_prev_rect_pct.x1, .initial = target_prev_rect_pct.x1, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y1", new_panel->prev->cfg), target_prev_rect_pct.y1, .initial = target_prev_rect_pct.y1, .rate = rd_state->menu_animation_rate)); + new_rect_pct = prev_rect_pct; + new_rect_pct.p0.v[split_axis] = new_rect_pct.p1.v[split_axis]; + } + if(new_panel->next != &rd_nil_panel_node) + { + Rng2F32 target_next_rect_px = rd_target_rect_from_panel_node(stub_content_rect, panel_tree.root, rd_panel_node_from_tree_cfg(panel_tree.root, new_panel->next->cfg)); + Rng2F32 target_next_rect_pct = r2f32p(target_next_rect_px.x0/stub_content_rect_dim.x, + target_next_rect_px.y0/stub_content_rect_dim.y, + target_next_rect_px.x1/stub_content_rect_dim.x, + target_next_rect_px.y1/stub_content_rect_dim.y); + Rng2F32 next_rect_pct = r2f32p(ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x0", new_panel->next->cfg), target_next_rect_pct.x0, .initial = target_next_rect_pct.x0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y0", new_panel->next->cfg), target_next_rect_pct.y0, .initial = target_next_rect_pct.y0, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x1", new_panel->next->cfg), target_next_rect_pct.x1, .initial = target_next_rect_pct.x1, .rate = rd_state->menu_animation_rate), + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y1", new_panel->next->cfg), target_next_rect_pct.y1, .initial = target_next_rect_pct.y1, .rate = rd_state->menu_animation_rate)); + new_rect_pct = next_rect_pct; + new_rect_pct.p1.v[split_axis] = new_rect_pct.p0.v[split_axis]; + } + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x0", new_panel->cfg), new_rect_pct.x0, .initial = new_rect_pct.x0, .reset = 1, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_x1", new_panel->cfg), new_rect_pct.x1, .initial = new_rect_pct.x1, .reset = 1, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y0", new_panel->cfg), new_rect_pct.y0, .initial = new_rect_pct.y0, .reset = 1, .rate = rd_state->menu_animation_rate); + ui_anim(ui_key_from_stringf(ui_key_zero(), "panel_%p_y1", new_panel->cfg), new_rect_pct.y1, .initial = new_rect_pct.y1, .reset = 1, .rate = rd_state->menu_animation_rate); + } + } + + // rjf: if this split was caused by drag/dropping a tab, and the originating panel + // has no further tabs, then close the originating panel + RD_Cfg *dragdrop_origin_panel_cfg = rd_cfg_from_id(rd_regs()->panel); + RD_Cfg *dragdrop_tab = rd_cfg_from_id(rd_regs()->view); + if(kind == RD_CmdKind_SplitPanel && + new_panel_cfg != &rd_nil_cfg && dragdrop_tab != &rd_nil_cfg && dragdrop_origin_panel_cfg != &rd_nil_cfg) + { + rd_cfg_unhook(dragdrop_origin_panel_cfg, dragdrop_tab); + rd_cfg_insert_child(new_panel_cfg, new_panel_cfg->last, dragdrop_tab); + RD_PanelTree origin_panel_tree = rd_panel_tree_from_cfg(scratch.arena, dragdrop_origin_panel_cfg); + RD_PanelNode *origin_panel = rd_panel_node_from_tree_cfg(origin_panel_tree.root, dragdrop_origin_panel_cfg); + if(origin_panel->selected_tab == &rd_nil_cfg) + { + for(RD_CfgNode *n = origin_panel->tabs.first; n != 0; n = n->next) + { + if(!rd_cfg_is_project_filtered(n->v)) + { + rd_cmd(RD_CmdKind_FocusTab, .panel = origin_panel->cfg->id, .tab = n->v->id); + break; + } + } + } + if(origin_panel->cfg != split_panel && origin_panel->tabs.count == 0) + { + rd_cmd(RD_CmdKind_ClosePanel); + } + rd_cmd(RD_CmdKind_FocusTab, .panel = new_panel_cfg->id, .tab = dragdrop_tab->id); + } + + // rjf: focus new panel + if(new_panel_cfg != &rd_nil_cfg) + { + rd_cmd(RD_CmdKind_FocusPanel, .panel = new_panel_cfg->id); + } + + // rjf: tabs on bottom on split panel? -> tabs on bottom on new panel + if(panel->tab_side == Side_Max && split_axis == Axis2_X) + { + rd_cmd(RD_CmdKind_TabBarBottom, .panel = new_panel_cfg->id); } }break; //- rjf: panel rotation case RD_CmdKind_RotatePanelColumns: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *panel = ws->focused_panel; - RD_Panel *parent = &rd_nil_panel; - for(RD_Panel *p = panel->parent; !rd_panel_is_nil(p); p = p->parent) + RD_Cfg *panel_cfg = rd_cfg_from_id(rd_regs()->panel); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel_cfg); + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, panel_cfg); + RD_PanelNode *parent = &rd_nil_panel_node; + for(RD_PanelNode *p = panel->parent; p != &rd_nil_panel_node; p = p->parent) { if(p->split_axis == Axis2_X) { @@ -13772,49 +13368,77 @@ rd_frame(void) break; } } - if(!rd_panel_is_nil(parent) && parent->child_count > 1) + if(parent != &rd_nil_panel_node && parent->child_count > 1) { - RD_Panel *old_first = parent->first; - RD_Panel *new_first = parent->first->next; - old_first->next = &rd_nil_panel; - old_first->prev = parent->last; - parent->last->next = old_first; - new_first->prev = &rd_nil_panel; - parent->first = new_first; - parent->last = old_first; + RD_Cfg *rotated = parent->first->cfg; + rd_cfg_unhook(parent->cfg, parent->first->cfg); + rd_cfg_insert_child(parent->cfg, parent->last->cfg, rotated); } }break; //- rjf: panel focusing - case RD_CmdKind_NextPanel: panel_sib_off = OffsetOf(RD_Panel, next); panel_child_off = OffsetOf(RD_Panel, first); goto cycle; - case RD_CmdKind_PrevPanel: panel_sib_off = OffsetOf(RD_Panel, prev); panel_child_off = OffsetOf(RD_Panel, last); goto cycle; + case RD_CmdKind_NextPanel: panel_sib_off = OffsetOf(RD_PanelNode, next); panel_child_off = OffsetOf(RD_PanelNode, first); goto cycle; + case RD_CmdKind_PrevPanel: panel_sib_off = OffsetOf(RD_PanelNode, prev); panel_child_off = OffsetOf(RD_PanelNode, last); goto cycle; cycle:; { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - for(RD_Panel *panel = ws->focused_panel; !rd_panel_is_nil(panel);) + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(rd_regs()->window)); + RD_PanelNode *next_focused = &rd_nil_panel_node; + for(RD_PanelNode *p = panel_tree.focused; + p != &rd_nil_panel_node; + p = rd_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) { - RD_PanelRec rec = rd_panel_rec_depth_first(panel, panel_sib_off, panel_child_off); - panel = rec.next; - if(rd_panel_is_nil(panel)) + if(p != panel_tree.focused && p->first == &rd_nil_panel_node) { - panel = ws->root_panel; - } - if(rd_panel_is_nil(panel->first)) - { - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(panel)); + next_focused = p; break; } } + if(next_focused == &rd_nil_panel_node) + { + for(RD_PanelNode *p = panel_tree.root; + p != &rd_nil_panel_node; + p = rd_panel_node_rec__depth_first(panel_tree.root, p, panel_sib_off, panel_child_off).next) + { + if(p != panel_tree.focused && p->first == &rd_nil_panel_node) + { + next_focused = p; + break; + } + } + } + rd_cmd(RD_CmdKind_FocusPanel, .panel = next_focused->cfg->id); }break; case RD_CmdKind_FocusPanel: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - if(!rd_panel_is_nil(panel)) + RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); + RD_Cfg *selection_cfg = &rd_nil_cfg; + for(RD_PanelNode *p = panel_tree.root; + p != &rd_nil_panel_node; + p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - ws->focused_panel = panel; + RD_Cfg *p_cfg = p->cfg; + RD_Cfg *p_selection = rd_cfg_child_from_string(p_cfg, str8_lit("selected")); + if(selection_cfg == &rd_nil_cfg) + { + selection_cfg = p_selection; + } + else for(RD_Cfg *s = p_selection; s != &rd_nil_cfg; s = rd_cfg_child_from_string(p_cfg, str8_lit("selected"))) + { + rd_cfg_release(s); + } + } + if(selection_cfg == &rd_nil_cfg) + { + selection_cfg = rd_cfg_alloc(); + rd_cfg_equip_string(selection_cfg, str8_lit("selected")); + } + if(panel != &rd_nil_cfg) + { + rd_cfg_insert_child(panel, &rd_nil_cfg, selection_cfg); + RD_Cfg *window = rd_window_from_cfg(panel); + RD_WindowState *ws = rd_window_state_from_cfg(window); ws->menu_bar_focused = 0; - ws->query_view_selected = 0; } }break; @@ -13825,39 +13449,40 @@ rd_frame(void) case RD_CmdKind_FocusPanelDown: panel_change_dir = v2s32(+0, +1); goto focus_panel_dir; focus_panel_dir:; { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *src_panel = ws->focused_panel; - Rng2F32 src_panel_rect = rd_target_rect_from_panel(r2f32(v2f32(0, 0), v2f32(1000, 1000)), ws->root_panel, src_panel); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *src_panel = panel_tree.focused; + Rng2F32 src_panel_rect = rd_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, src_panel); Vec2F32 src_panel_center = center_2f32(src_panel_rect); Vec2F32 src_panel_half_dim = scale_2f32(dim_2f32(src_panel_rect), 0.5f); Vec2F32 travel_dim = add_2f32(src_panel_half_dim, v2f32(10.f, 10.f)); Vec2F32 travel_dst = add_2f32(src_panel_center, mul_2f32(travel_dim, v2f32((F32)panel_change_dir.x, (F32)panel_change_dir.y))); - RD_Panel *dst_root = &rd_nil_panel; - for(RD_Panel *p = ws->root_panel; !rd_panel_is_nil(p); p = rd_panel_rec_depth_first_pre(p).next) + RD_PanelNode *dst_root = &rd_nil_panel_node; + for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - if(p == src_panel || !rd_panel_is_nil(p->first)) + if(p == src_panel || p->first != &rd_nil_panel_node) { continue; } - Rng2F32 p_rect = rd_target_rect_from_panel(r2f32(v2f32(0, 0), v2f32(1000, 1000)), ws->root_panel, p); + Rng2F32 p_rect = rd_target_rect_from_panel_node(r2f32(v2f32(0, 0), v2f32(1000, 1000)), panel_tree.root, p); if(contains_2f32(p_rect, travel_dst)) { dst_root = p; break; } } - if(!rd_panel_is_nil(dst_root)) + if(dst_root != &rd_nil_panel_node) { - RD_Panel *dst_panel = &rd_nil_panel; - for(RD_Panel *p = dst_root; !rd_panel_is_nil(p); p = rd_panel_rec_depth_first_pre(p).next) + RD_PanelNode *dst_panel = &rd_nil_panel_node; + for(RD_PanelNode *p = dst_root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(dst_root, p).next) { - if(rd_panel_is_nil(p->first) && p != src_panel) + if(p->first == &rd_nil_panel_node && p != src_panel) { dst_panel = p; break; } } - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(dst_panel)); + rd_cmd(RD_CmdKind_FocusPanel, .panel = dst_panel->cfg->id); } }break; @@ -13872,13 +13497,18 @@ rd_frame(void) //- rjf: files case RD_CmdKind_SetCurrentPath: { - arena_clear(rd_state->current_path_arena); - rd_state->current_path = push_str8_copy(rd_state->current_path_arena, rd_regs()->file_path); + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *current_path = rd_cfg_child_from_string_or_alloc(user, str8_lit("current_path")); + rd_cfg_new_replace(current_path, rd_regs()->file_path); }break; case RD_CmdKind_SetFileReplacementPath: { // NOTE(rjf): // + // foo.c + // C:/test/bar/baz/foo.c + // -> override foo.c -> C:/test/bar/baz/foo.c + // // C:/foo/bar/baz.c // D:/foo/bar/baz.c // -> override C: -> D: @@ -13894,10 +13524,8 @@ rd_frame(void) //- rjf: unpack String8 src_path = rd_regs()->string; String8 dst_path = rd_regs()->file_path; - String8 src_path__normalized = path_normalized_from_string(scratch.arena, src_path); - String8 dst_path__normalized = path_normalized_from_string(scratch.arena, dst_path); - String8List src_path_parts = str8_split_path(scratch.arena, src_path__normalized); - String8List dst_path_parts = str8_split_path(scratch.arena, dst_path__normalized); + String8List src_path_parts = str8_split_path(scratch.arena, src_path); + String8List dst_path_parts = str8_split_path(scratch.arena, dst_path); //- rjf: reverse path parts String8List src_path_parts__reversed = {0}; @@ -13917,7 +13545,9 @@ rd_frame(void) String8Node *first_diff_dst = dst_path_parts__reversed.first; for(;first_diff_src != 0 && first_diff_dst != 0;) { - if(!str8_match(first_diff_src->string, first_diff_dst->string, StringMatchFlag_CaseInsensitive)) + if(!str8_match(first_diff_src->string, first_diff_dst->string, StringMatchFlag_CaseInsensitive) || + first_diff_src->next == 0 || + first_diff_dst->next == 0) { break; } @@ -13940,30 +13570,39 @@ rd_frame(void) String8 map_src = str8_list_join(scratch.arena, &map_src_parts, &map_join); String8 map_dst = str8_list_join(scratch.arena, &map_dst_parts, &map_join); - //- rjf: store as file path map entity - //- TODO(rjf): @cfg store as file path map entity + //- rjf: store as file path map cfg + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); { - RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); - RD_Cfg *map = rd_cfg_new(user, str8_lit("file_path_map")); - RD_Cfg *src = rd_cfg_new(map, str8_lit("source")); - RD_Cfg *dst = rd_cfg_new(map, str8_lit("dest")); - rd_cfg_new(src, map_src); - rd_cfg_new(dst, map_dst); + RD_CfgList cfgs = rd_cfg_child_list_from_string(scratch.arena, user, str8_lit("file_path_map")); + RD_Cfg *map = &rd_nil_cfg; + for(RD_CfgNode *n = cfgs.first; n != 0; n = n->next) + { + RD_Cfg *src = rd_cfg_child_from_string(n->v, str8_lit("source")); + if(path_match_normalized(src->first->string, map_src)) + { + map = n->v; + break; + } + } + if(map == &rd_nil_cfg) + { + map = rd_cfg_new(user, str8_lit("file_path_map")); + } + RD_Cfg *src = rd_cfg_child_from_string_or_alloc(map, str8_lit("source")); + RD_Cfg *dst = rd_cfg_child_from_string_or_alloc(map, str8_lit("dest")); + rd_cfg_new_replace(src, map_src); + rd_cfg_new_replace(dst, map_dst); } - RD_Entity *map = rd_entity_alloc(rd_entity_root(), RD_EntityKind_FilePathMap); - RD_Entity *src = rd_entity_alloc(map, RD_EntityKind_Source); - RD_Entity *dst = rd_entity_alloc(map, RD_EntityKind_Dest); - rd_entity_equip_name(src, map_src); - rd_entity_equip_name(dst, map_dst); }break; //- rjf: panel removal case RD_CmdKind_ClosePanel: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_Panel *parent = panel->parent; - if(!rd_panel_is_nil(parent)) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, rd_cfg_from_id(rd_regs()->panel)); + RD_PanelNode *parent = panel->parent; + if(parent != &rd_nil_panel_node) { Axis2 split_axis = parent->split_axis; @@ -13971,217 +13610,364 @@ rd_frame(void) // we should just remove both children. if(parent->child_count == 2) { - RD_Panel *discard_child = panel; - RD_Panel *keep_child = panel == parent->first ? parent->last : parent->first; - RD_Panel *grandparent = parent->parent; - RD_Panel *parent_prev = parent->prev; + RD_PanelNode *discard_child = panel; + RD_PanelNode *keep_child = (panel == parent->first ? parent->last : parent->first); + RD_PanelNode *grandparent = parent->parent; + RD_PanelNode *parent_prev = parent->prev; F32 pct_of_parent = parent->pct_of_parent; // rjf: unhook kept child - rd_panel_remove(parent, keep_child); + rd_cfg_unhook(parent->cfg, keep_child->cfg); // rjf: unhook this subtree - if(!rd_panel_is_nil(grandparent)) + if(grandparent != &rd_nil_panel_node) { - rd_panel_remove(grandparent, parent); + rd_cfg_unhook(grandparent->cfg, parent->cfg); } - // rjf: release the things we should discard + // rjf: release the containing tree { - rd_panel_release(ws, parent); - rd_panel_release(ws, discard_child); + rd_cfg_release(parent->cfg); } // rjf: re-hook our kept child into the overall tree - if(rd_panel_is_nil(grandparent)) + if(grandparent == &rd_nil_panel_node) { - ws->root_panel = keep_child; + if(keep_child->split_axis == Axis2_X) + { + rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); + } + else + { + rd_cfg_release(rd_cfg_child_from_string(window, str8_lit("split_x"))); + } + rd_cfg_equip_string(keep_child->cfg, str8_lit("panels")); + rd_cfg_insert_child(window, window->last, keep_child->cfg); } else { - rd_panel_insert(grandparent, parent_prev, keep_child); - } - keep_child->pct_of_parent = pct_of_parent; - - // rjf: reset focus, if needed - if(ws->focused_panel == discard_child) - { - ws->focused_panel = keep_child; - for(RD_Panel *grandchild = ws->focused_panel; !rd_panel_is_nil(grandchild); grandchild = grandchild->first) - { - ws->focused_panel = grandchild; - } + rd_cfg_insert_child(grandparent->cfg, parent_prev->cfg, keep_child->cfg); + rd_cfg_equip_stringf(keep_child->cfg, "%f", pct_of_parent); } // rjf: keep-child split-axis == grandparent split-axis? bubble keep-child up into grandparent's children - if(!rd_panel_is_nil(grandparent) && grandparent->split_axis == keep_child->split_axis && !rd_panel_is_nil(keep_child->first)) + if(grandparent != &rd_nil_panel_node && grandparent->split_axis == keep_child->split_axis && keep_child->first != &rd_nil_panel_node) { - rd_panel_remove(grandparent, keep_child); - RD_Panel *prev = parent_prev; - for(RD_Panel *child = keep_child->first, *next = 0; !rd_panel_is_nil(child); child = next) + rd_cfg_unhook(grandparent->cfg, keep_child->cfg); + RD_Cfg *prev = parent_prev->cfg; + for(RD_PanelNode *child = keep_child->first, *next = &rd_nil_panel_node; child != &rd_nil_panel_node; child = next) { next = child->next; - rd_panel_remove(keep_child, child); - rd_panel_insert(grandparent, prev, child); - prev = child; - child->pct_of_parent *= keep_child->pct_of_parent; + rd_cfg_unhook(keep_child->cfg, child->cfg); + rd_cfg_insert_child(grandparent->cfg, prev, child->cfg); + prev = child->cfg; + F32 old_pct = child->pct_of_parent; + F32 new_pct = old_pct * pct_of_parent; + rd_cfg_equip_stringf(child->cfg, "%f", new_pct); } - rd_panel_release(ws, keep_child); + rd_cfg_release(keep_child->cfg); + } + + // rjf: reset focus, if needed + if(panel_tree.focused == discard_child) + { + RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *new_focused = rd_panel_node_from_tree_cfg(panel_tree.root, keep_child->cfg); + for(RD_PanelNode *grandchild = new_focused; grandchild != &rd_nil_panel_node; grandchild = grandchild->first) + { + new_focused = grandchild; + } + rd_cmd(RD_CmdKind_FocusPanel, .panel = new_focused->cfg->id); } } // NOTE(rjf): Otherwise we can just remove this child. else { - RD_Panel *next = &rd_nil_panel; + // rjf: remove + RD_PanelNode *next = &rd_nil_panel_node; F32 removed_size_pct = panel->pct_of_parent; - if(rd_panel_is_nil(next)) { next = panel->prev; } - if(rd_panel_is_nil(next)) { next = panel->next; } - rd_panel_remove(parent, panel); - rd_panel_release(ws, panel); - if(ws->focused_panel == panel) + if(next == &rd_nil_panel_node) { next = panel->prev; } + if(next == &rd_nil_panel_node) { next = panel->next; } + rd_cfg_unhook(parent->cfg, panel->cfg); + rd_cfg_release(panel->cfg); + + // rjf: resize siblings to this node { - ws->focused_panel = next; - for(RD_Panel *grandchild = ws->focused_panel; !rd_panel_is_nil(grandchild); grandchild = grandchild->first) + RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *new_parent = rd_panel_node_from_tree_cfg(new_panel_tree.root, parent->cfg); + for(RD_PanelNode *child = new_parent->first; child != &rd_nil_panel_node; child = child->next) { - ws->focused_panel = grandchild; + RD_Cfg *cfg = child->cfg; + F32 old_pct = child->pct_of_parent; + F32 new_pct = old_pct / (1.f-removed_size_pct); + rd_cfg_equip_stringf(cfg, "%f", new_pct); } } - for(RD_Panel *child = parent->first; !rd_panel_is_nil(child); child = child->next) + + // rjf: reset focus, if needed + if(panel_tree.focused == panel) { - child->pct_of_parent /= 1.f-removed_size_pct; + RD_PanelTree new_panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *new_focused = rd_panel_node_from_tree_cfg(panel_tree.root, next->cfg); + for(RD_PanelNode *grandchild = new_focused; grandchild != &rd_nil_panel_node; grandchild = grandchild->first) + { + new_focused = grandchild; + } + rd_cmd(RD_CmdKind_FocusPanel, .panel = new_focused->cfg->id); } } } }break; //- rjf: panel tab controls + case RD_CmdKind_FocusTab: + { + RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + RD_Cfg *panel = tab->parent; + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, panel); + RD_PanelNode *panel_node = rd_panel_node_from_tree_cfg(panel_tree.root, panel); + RD_Cfg *selection_cfg = &rd_nil_cfg; + for(RD_CfgNode *n = panel_node->tabs.first; n != 0; n = n->next) + { + RD_Cfg *tab_selection_cfg = rd_cfg_child_from_string(n->v, str8_lit("selected")); + if(selection_cfg == &rd_nil_cfg) + { + selection_cfg = tab_selection_cfg; + } + else for(RD_Cfg *s = tab_selection_cfg; s != &rd_nil_cfg; s = rd_cfg_child_from_string(n->v, str8_lit("selected"))) + { + rd_cfg_release(s); + } + } + if(selection_cfg == &rd_nil_cfg) + { + selection_cfg = rd_cfg_alloc(); + rd_cfg_equip_string(selection_cfg, str8_lit("selected")); + } + rd_cfg_insert_child(tab, &rd_nil_cfg, selection_cfg); + }break; case RD_CmdKind_NextTab: { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *start_view = rd_selected_tab_from_panel(panel); - RD_View *next_view = start_view; - U64 idx = 0; - for(RD_View *v = start_view; !rd_view_is_nil(v); v = (rd_view_is_nil(v->order_next) ? panel->first_tab_view : v->order_next), idx += 1) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *focused = panel_tree.focused; + RD_CfgNode *selected_tab_n = 0; + for(RD_CfgNode *n = focused->tabs.first; n != 0; n = n->next) { - if(v == start_view && idx != 0) + if(n->v == focused->selected_tab) { - break; - } - if(!rd_view_is_project_filtered(v) && v != start_view) - { - next_view = v; + selected_tab_n = n; break; } } - panel->selected_tab_view = rd_handle_from_view(next_view); + RD_Cfg *next_selected_tab = &rd_nil_cfg; + U64 idx = 0; + for(RD_CfgNode *tab_n = selected_tab_n; + tab_n != 0 && (tab_n != selected_tab_n || idx == 0); + ((tab_n->next == 0) ? (tab_n = focused->tabs.first) : (tab_n = tab_n->next)), idx += 1) + { + if(!rd_cfg_is_project_filtered(tab_n->v) && tab_n != selected_tab_n) + { + next_selected_tab = tab_n->v; + break; + } + } + if(next_selected_tab != &rd_nil_cfg) + { + rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); + } }break; case RD_CmdKind_PrevTab: { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *start_view = rd_selected_tab_from_panel(panel); - RD_View *next_view = start_view; - U64 idx = 0; - for(RD_View *v = start_view; !rd_view_is_nil(v); v = (rd_view_is_nil(v->order_prev) ? panel->last_tab_view : v->order_prev), idx += 1) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *focused = panel_tree.focused; + RD_CfgNode *selected_tab_n = 0; + for(RD_CfgNode *n = focused->tabs.last; n != 0; n = n->prev) { - if(v == start_view && idx != 0) + if(n->v == focused->selected_tab) { - break; - } - if(!rd_view_is_project_filtered(v) && v != start_view) - { - next_view = v; + selected_tab_n = n; break; } } - panel->selected_tab_view = rd_handle_from_view(next_view); + RD_Cfg *next_selected_tab = &rd_nil_cfg; + U64 idx = 0; + for(RD_CfgNode *tab_n = selected_tab_n; + tab_n != 0 && (tab_n != selected_tab_n || idx == 0); + ((tab_n->prev == 0) ? (tab_n = focused->tabs.last) : (tab_n = tab_n->prev)), idx += 1) + { + if(!rd_cfg_is_project_filtered(tab_n->v) && tab_n != selected_tab_n) + { + next_selected_tab = tab_n->v; + break; + } + } + if(next_selected_tab != &rd_nil_cfg) + { + rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); + } }break; case RD_CmdKind_MoveTabRight: case RD_CmdKind_MoveTabLeft: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *panel = ws->focused_panel; - RD_View *view = rd_selected_tab_from_panel(panel); - RD_View *prev_view = (kind == RD_CmdKind_MoveTabRight ? view->order_next : view->order_prev->order_prev); - if(!rd_view_is_nil(prev_view) || kind == RD_CmdKind_MoveTabLeft) + RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + RD_Cfg *window = rd_window_from_cfg(tab); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); + RD_CfgList filtered_tabs = {0}; + for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) { - rd_cmd(RD_CmdKind_MoveTab, - .panel = rd_handle_from_panel(panel), - .dst_panel = rd_handle_from_panel(panel), - .view = rd_handle_from_view(view), - .prev_view = rd_handle_from_view(prev_view)); - } - }break; - case RD_CmdKind_OpenTab: - { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *view = rd_view_alloc(); - String8 query = rd_regs()->string; - RD_ViewRuleInfo *spec = rd_view_rule_info_from_string(rd_regs()->params_tree->string); - rd_view_equip_spec(view, spec, query, rd_regs()->params_tree); - rd_panel_insert_tab_view(panel, panel->last_tab_view, view); - }break; - case RD_CmdKind_CloseTab: - { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *view = rd_view_from_handle(rd_regs()->view); - if(!rd_view_is_nil(view)) - { - rd_panel_remove_tab_view(panel, view); - rd_view_release(view); - } - }break; - case RD_CmdKind_MoveTab: - { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *src_panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *view = rd_view_from_handle(rd_regs()->view); - RD_Panel *dst_panel = rd_panel_from_handle(rd_regs()->dst_panel); - RD_View *prev_view = rd_view_from_handle(rd_regs()->prev_view); - if(!rd_panel_is_nil(src_panel) && - !rd_panel_is_nil(dst_panel) && - prev_view != view) - { - rd_panel_remove_tab_view(src_panel, view); - rd_panel_insert_tab_view(dst_panel, prev_view, view); - ws->focused_panel = dst_panel; - B32 src_panel_is_empty = 1; - for(RD_View *v = src_panel->first_tab_view; !rd_view_is_nil(v); v = v->order_next) + if(rd_cfg_is_project_filtered(n->v)) { - if(!rd_view_is_project_filtered(v)) + continue; + } + rd_cfg_list_push(scratch.arena, &filtered_tabs, n->v); + } + RD_Cfg *tab_prev2 = &rd_nil_cfg; + RD_Cfg *tab_prev = &rd_nil_cfg; + RD_Cfg *tab_next = &rd_nil_cfg; + { + RD_Cfg *prev2 = &rd_nil_cfg; + RD_Cfg *prev = &rd_nil_cfg; + RD_Cfg *next = &rd_nil_cfg; + for(RD_CfgNode *n = filtered_tabs.first; n != 0; (prev2 = prev, prev = n->v, n = n->next)) + { + next = n->next ? n->next->v : &rd_nil_cfg; + if(n->v == tab) { - src_panel_is_empty = 0; + tab_prev2 = prev2; + tab_prev = prev; + tab_next = next; break; } } - if(src_panel_is_empty && src_panel != ws->root_panel) + } + RD_Cfg *new_prev = (kind == RD_CmdKind_MoveTabRight ? tab_next : tab_prev2); + if(new_prev == tab_prev && filtered_tabs.last) + { + new_prev = filtered_tabs.last->v; + } + rd_cmd(RD_CmdKind_MoveView, + .dst_panel = panel->cfg->id, + .view = tab->id, + .prev_tab = new_prev->id); + }break; + case RD_CmdKind_BuildTab: + { + String8 expr_file_path = rd_file_path_from_eval_string(scratch.arena, rd_regs()->expr); + RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); + RD_Cfg *tab = rd_cfg_new(panel, rd_regs()->string); + RD_Cfg *expr = rd_cfg_new(tab, str8_lit("expression")); + rd_cfg_new(expr, rd_regs()->expr); + if(expr_file_path.size != 0) + { + RD_Cfg *project = rd_cfg_new(tab, str8_lit("project")); + rd_cfg_new(project, rd_state->project_path); + } + rd_cmd(RD_CmdKind_FocusTab, .tab = tab->id); + }break; + case RD_CmdKind_DuplicateTab: + { + RD_Cfg *src = rd_cfg_from_id(rd_regs()->tab); + RD_Cfg *dst = rd_cfg_deep_copy(src); + rd_cfg_insert_child(src->parent, src, dst); + rd_cmd(RD_CmdKind_FocusTab, .tab = dst->id); + }break; + case RD_CmdKind_CopyTabFullPath: + { + RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + String8 expr = rd_expr_from_cfg(tab); + String8 full_path = rd_file_path_from_eval_string(scratch.arena, expr); + os_set_clipboard_text(full_path); + }break; + case RD_CmdKind_CloseTab: + { + RD_Cfg *tab = rd_cfg_from_id(rd_regs()->tab); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, tab); + RD_PanelNode *panel = rd_panel_node_from_tree_cfg(panel_tree.root, tab->parent); + if(panel->selected_tab == tab) + { + B32 found_selected = 0; + RD_Cfg *next_selected_tab = &rd_nil_cfg; + for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) { - rd_cmd(RD_CmdKind_ClosePanel, .panel = rd_handle_from_panel(src_panel)); + if(n->v == panel->selected_tab) + { + found_selected = 1; + } + else if(!rd_cfg_is_project_filtered(n->v)) + { + next_selected_tab = n->v; + if(found_selected) + { + break; + } + } + } + rd_cmd(RD_CmdKind_FocusTab, .tab = next_selected_tab->id); + } + rd_cfg_release(tab); + }break; + case RD_CmdKind_MoveView: + { + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *prev_tab = rd_cfg_from_id(rd_regs()->prev_tab); + RD_Cfg *src_panel = view->parent; + RD_Cfg *dst_panel = rd_cfg_from_id(rd_regs()->dst_panel); + if(dst_panel != &rd_nil_cfg && prev_tab != view) + { + rd_cfg_unhook(src_panel, view); + rd_cfg_insert_child(dst_panel, prev_tab, view); + rd_cmd(RD_CmdKind_FocusTab, .panel = dst_panel->id, .tab = view->id); + rd_cmd(RD_CmdKind_FocusPanel, .panel = dst_panel->id); + RD_PanelTree src_panel_tree = rd_panel_tree_from_cfg(scratch.arena, src_panel); + RD_PanelNode *src_panel_node = rd_panel_node_from_tree_cfg(src_panel_tree.root, src_panel); + B32 src_panel_is_empty = 0; + if(src_panel != dst_panel) + { + src_panel_is_empty = 1; + for(RD_CfgNode *n = src_panel_node->tabs.first; n != 0; n = n->next) + { + if(!rd_cfg_is_project_filtered(n->v)) + { + rd_cmd(RD_CmdKind_FocusTab, .panel = src_panel->id, .tab = n->v->id); + src_panel_is_empty = 0; + break; + } + } + } + if(src_panel_is_empty) + { + rd_cmd(RD_CmdKind_ClosePanel, .panel = src_panel->id); } } }break; case RD_CmdKind_TabBarTop: { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - panel->tab_side = Side_Min; + RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); + rd_cfg_release(rd_cfg_child_from_string(panel, str8_lit("tabs_on_bottom"))); }break; case RD_CmdKind_TabBarBottom: { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - panel->tab_side = Side_Max; + RD_Cfg *panel = rd_cfg_from_id(rd_regs()->panel); + rd_cfg_child_from_string_or_alloc(panel, str8_lit("tabs_on_bottom")); + }break; + case RD_CmdKind_TabSettings: + { + String8 expr = push_str8f(scratch.arena, "query:config.$%I64x", rd_regs()->tab); + rd_cmd(RD_CmdKind_PushQuery, .expr = expr, .do_implicit_root = 1, .do_big_rows = 1, .do_lister = 1); }break; //- rjf: files case RD_CmdKind_Open: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - String8 path = rd_regs()->file_path; + String8 path = path_absolute_dst_from_relative_dst_src(scratch.arena, rd_regs()->file_path, os_get_current_path(scratch.arena)); FileProperties props = os_properties_from_file_path(path); if(props.created != 0) { rd_cmd(RD_CmdKind_RecordFileInProject); - rd_cmd(RD_CmdKind_OpenTab, - .string = rd_eval_string_from_file_path(scratch.arena, path), - .params_tree = md_tree_from_string(scratch.arena, rd_view_rule_kind_info_table[RD_ViewRuleKind_PendingFile].string)->first); + rd_cmd(RD_CmdKind_BuildTab, .string = str8_lit("pending"), .expr = rd_eval_string_from_file_path(scratch.arena, path)); } else { @@ -14190,90 +13976,38 @@ rd_frame(void) }break; case RD_CmdKind_Switch: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - RD_Panel *src_panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *src_view = rd_view_from_handle(rd_regs()->view); - RD_ViewRuleKind src_view_kind = rd_view_rule_kind_from_string(src_view->spec->string); - RD_Entity *recent_file = rd_entity_from_handle(rd_regs()->entity); - if(!rd_entity_is_nil(recent_file)) - { - String8 recent_file_path = recent_file->string; - RD_Panel *existing_panel = &rd_nil_panel; - RD_View *existing_view = &rd_nil_view; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) - { - if(!rd_panel_is_nil(panel->first)) - { - continue; - } - for(RD_View *v = panel->first_tab_view; !rd_view_is_nil(v); v = v->order_next) - { - if(rd_view_is_project_filtered(v)) { continue; } - String8 v_path = rd_file_path_from_eval_string(scratch.arena, str8(v->query_buffer, v->query_string_size)); - RD_ViewRuleKind v_kind = rd_view_rule_kind_from_string(v->spec->string); - if(str8_match(v_path, recent_file_path, StringMatchFlag_CaseInsensitive) && v_kind == src_view_kind) - { - existing_panel = panel; - existing_view = v; - goto done_existing_view_search__switch; - } - } - } - done_existing_view_search__switch:; - if(rd_view_is_nil(existing_view)) - { - rd_cmd(RD_CmdKind_OpenTab, - .string = rd_eval_string_from_file_path(scratch.arena, recent_file_path), - .params_tree = md_tree_from_string(scratch.arena, rd_view_rule_kind_info_table[RD_ViewRuleKind_PendingFile].string)->first); - } - else - { - rd_cmd(RD_CmdKind_FocusPanel, .panel = rd_handle_from_panel(existing_panel)); - existing_panel->selected_tab_view = rd_handle_from_view(existing_view); - } - } + RD_Cfg *recent_file = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *path_root = rd_cfg_child_from_string(recent_file, str8_lit("path")); + String8 path = path_root->first->string; + rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = path, .cursor = txt_pt(0, 0), .vaddr = 0, .force_focus = 1); }break; case RD_CmdKind_SwitchToPartnerFile: { - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - RD_View *view = rd_selected_tab_from_panel(panel); + String8 file_path = rd_regs()->file_path; + String8 file_folder = str8_chop_last_slash(file_path); + String8 file_name = str8_skip_last_slash(str8_chop_last_dot(file_path)); + String8 file_ext = str8_skip_last_dot(file_path); + String8 partner_ext_candidates[] = { - String8 file_path = rd_file_path_from_eval_string(scratch.arena, str8(view->query_buffer, view->query_string_size)); - String8 file_full_path = path_normalized_from_string(scratch.arena, file_path); - String8 file_folder = str8_chop_last_slash(file_full_path); - String8 file_name = str8_skip_last_slash(str8_chop_last_dot(file_full_path)); - String8 file_ext = str8_skip_last_dot(file_full_path); - String8 partner_ext_candidates[] = + str8_lit_comp("h"), + str8_lit_comp("hpp"), + str8_lit_comp("hxx"), + str8_lit_comp("c"), + str8_lit_comp("cc"), + str8_lit_comp("cxx"), + str8_lit_comp("cpp"), + }; + for(U64 idx = 0; idx < ArrayCount(partner_ext_candidates); idx += 1) + { + if(!str8_match(partner_ext_candidates[idx], file_ext, StringMatchFlag_CaseInsensitive)) { - str8_lit_comp("h"), - str8_lit_comp("hpp"), - str8_lit_comp("hxx"), - str8_lit_comp("c"), - str8_lit_comp("cc"), - str8_lit_comp("cxx"), - str8_lit_comp("cpp"), - }; - for(U64 idx = 0; idx < ArrayCount(partner_ext_candidates); idx += 1) - { - if(!str8_match(partner_ext_candidates[idx], file_ext, StringMatchFlag_CaseInsensitive)) + String8 candidate = push_str8f(scratch.arena, "%S.%S", file_name, partner_ext_candidates[idx]); + String8 candidate_path = push_str8f(scratch.arena, "%S/%S", file_folder, candidate); + FileProperties candidate_props = os_properties_from_file_path(candidate_path); + if(candidate_props.modified != 0) { - String8 candidate = push_str8f(scratch.arena, "%S.%S", file_name, partner_ext_candidates[idx]); - String8 candidate_path = push_str8f(scratch.arena, "%S/%S", file_folder, candidate); - FileProperties candidate_props = os_properties_from_file_path(candidate_path); - if(candidate_props.modified != 0) - { - RD_Entity *recent_file = rd_entity_from_name_and_kind(candidate_path, RD_EntityKind_RecentFile); - if(!rd_entity_is_nil(recent_file)) - { - rd_cmd(RD_CmdKind_Switch, .entity = rd_handle_from_entity(recent_file)); - } - else - { - rd_cmd(RD_CmdKind_RecordFileInProject, .file_path = candidate_path); - rd_cmd(RD_CmdKind_OpenTab, .string = rd_eval_string_from_file_path(scratch.arena, candidate_path), .params_tree = md_tree_from_string(scratch.arena, view->spec->string)->first); - } - break; - } + rd_cmd(RD_CmdKind_FindCodeLocation, .file_path = candidate_path, .cursor = txt_pt(0, 0), .vaddr = 0); + break; } } } @@ -14281,70 +14015,48 @@ rd_frame(void) case RD_CmdKind_RecordFileInProject: if(rd_regs()->file_path.size != 0) { - String8 path = path_normalized_from_string(scratch.arena, rd_regs()->file_path); - - //- TODO(rjf): @cfg record file in project + String8 path = rd_regs()->file_path; + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_CfgList recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); + RD_Cfg *recent_file = &rd_nil_cfg; + for(RD_CfgNode *n = recent_files.first; n != 0; n = n->next) { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_CfgList recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files")); - RD_Cfg *recent_file = &rd_nil_cfg; - for(RD_CfgNode *n = recent_files.first; n != 0; n = n->next) + if(path_match_normalized(rd_path_from_cfg(n->v), path)) { - if(path_match_normalized(n->v->string, path)) - { - recent_file = n->v; - break; - } - } - if(recent_file == &rd_nil_cfg) - { - recent_file = rd_cfg_new(project, str8_lit("recent_file")); - rd_cfg_new(recent_file, path); - } - rd_cfg_unhook(project, recent_file); - rd_cfg_insert_child(project, &rd_nil_cfg, recent_file); - recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_files")); - if(recent_files.count > 256) - { - rd_cfg_release(recent_files.last->v); - } - } - - RD_EntityList recent_files = rd_query_cached_entity_list_with_kind(RD_EntityKind_RecentFile); - if(recent_files.count >= 256) - { - rd_entity_mark_for_deletion(recent_files.first->entity); - } - RD_Entity *existing_recent_file = &rd_nil_entity; - for(RD_EntityNode *n = recent_files.first; n != 0; n = n->next) - { - if(str8_match(n->entity->string, path, StringMatchFlag_CaseInsensitive)) - { - existing_recent_file = n->entity; + recent_file = n->v; break; } } - if(rd_entity_is_nil(existing_recent_file)) + if(recent_file == &rd_nil_cfg) { - RD_Entity *recent_file = rd_entity_alloc(rd_entity_root(), RD_EntityKind_RecentFile); - rd_entity_equip_name(recent_file, path); - rd_entity_equip_cfg_src(recent_file, RD_CfgSrc_Project); + recent_file = rd_cfg_new(project, str8_lit("recent_file")); + RD_Cfg *path_root = rd_cfg_new(recent_file, str8_lit("path")); + rd_cfg_new(path_root, path); } - else + rd_cfg_unhook(project, recent_file); + rd_cfg_insert_child(project, &rd_nil_cfg, recent_file); + recent_files = rd_cfg_child_list_from_string(scratch.arena, project, str8_lit("recent_file")); + if(recent_files.count > 256) { - rd_entity_change_parent(existing_recent_file, rd_entity_root(), rd_entity_root(), rd_entity_root()->last); + rd_cfg_release(recent_files.last->v); } }break; + case RD_CmdKind_ShowFileInExplorer: + if(rd_regs()->file_path.size != 0) + { + String8 full_path = rd_regs()->file_path; + os_show_in_filesystem_ui(full_path); + }break; //- rjf: source <-> disasm case RD_CmdKind_GoToDisassembly: { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); U64 vaddr = 0; for(D_LineNode *n = rd_regs()->lines.first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &n->v.dbgi_key); - CTRL_Entity *module = ctrl_module_from_thread_candidates(d_state->ctrl_entity_store, thread, &modules); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); @@ -14369,375 +14081,265 @@ rd_frame(void) //- rjf: panel built-in layout builds case RD_CmdKind_ResetToDefaultPanels: case RD_CmdKind_ResetToCompactPanels: + case RD_CmdKind_ResetToSimplePanels: { - panel_reset_done = 1; - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_Cfg *panels = rd_cfg_child_from_string(window, str8_lit("panels")); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); - typedef enum Layout + //- rjf: define all of the "fixed" tabs we care about +#define X(name) RD_Cfg *name = &rd_nil_cfg; +#define Y(name, rule, expr) RD_Cfg *name = &rd_nil_cfg; +#define Z(name) RD_Cfg *name = &rd_nil_cfg; + RD_FixedTabXList +#undef X +#undef Y +#undef Z + + //- rjf: find all the fixed tabs, and all text viewers + B32 any_fixed_tabs_found = 0; + RD_CfgList texts = {0}; + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - Layout_Default, - Layout_Compact, + for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) + { + RD_Cfg *tab = n->v; + B32 need_unhook = 1; + if(0){} +#define X(name) else if(str8_match(tab->string, str8_lit("watch"), 0) && str8_match(rd_expr_from_cfg(tab), str8_lit("query:" #name), 0)) {name = tab;} +#define Y(name, rule, expr) else if(str8_match(tab->string, str8_lit(#rule), 0) && str8_match(rd_expr_from_cfg(tab), str8_lit(expr), 0)) {name = tab;} +#define Z(name) else if(str8_match(tab->string, str8_lit(#name), 0)) {name = tab;} + RD_FixedTabXList +#undef X +#undef Y +#undef Z + else if(str8_match(tab->string, str8_lit("text"), 0)) {rd_cfg_list_push(scratch.arena, &texts, tab);} + else + { + need_unhook = 0; + } + if(need_unhook) + { + rd_cfg_unhook(panel->cfg, tab); + any_fixed_tabs_found = 1; + } + } } - Layout; - Layout layout = Layout_Default; + + //- rjf: release the old panel tree + rd_cfg_release(panels); + + //- rjf: allocate any missing tabs +#define X(name) if(name == &rd_nil_cfg) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit("watch")); RD_Cfg *expr_cfg = rd_cfg_new(name, str8_lit("expression")); rd_cfg_new(expr_cfg, str8_lit("query:" #name));} +#define Y(name, rule, expr) if(name == &rd_nil_cfg) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit(#rule)); RD_Cfg *expr_cfg = rd_cfg_new(name, str8_lit("expression")); rd_cfg_new(expr_cfg, str8_lit(expr));} +#define Z(name) if(name == &rd_nil_cfg && !any_fixed_tabs_found) {name = rd_cfg_alloc(); rd_cfg_equip_string(name, str8_lit(#name));} + RD_FixedTabXList +#undef X +#undef Y +#undef Z + + //- rjf: eliminate all tab selections +#define X(name) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} +#define Y(name, rule, expr) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} +#define Z(name) if(name != &rd_nil_cfg) {rd_cfg_release(rd_cfg_child_from_string(name, str8_lit("selected")));} + RD_FixedTabXList +#undef X +#undef Y +#undef Z + for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + { + rd_cfg_release(rd_cfg_child_from_string(n->v, str8_lit("selected"))); + } + + //- rjf: create the panel root + panels = rd_cfg_new(window, str8_lit("panels")); + + //- rjf: rebuild the new panel tree switch(kind) { default:{}break; - case RD_CmdKind_ResetToDefaultPanels:{layout = Layout_Default;}break; - case RD_CmdKind_ResetToCompactPanels:{layout = Layout_Compact;}break; - } - - //- rjf: gather all panels in the panel tree - remove & gather views - // we'd like to keep in the next layout - RD_HandleList panels_to_close = {0}; - RD_HandleList views_to_close = {0}; - RD_View *watch = &rd_nil_view; - RD_View *locals = &rd_nil_view; - RD_View *regs = &rd_nil_view; - RD_View *globals = &rd_nil_view; - RD_View *tlocals = &rd_nil_view; - RD_View *types = &rd_nil_view; - RD_View *procs = &rd_nil_view; - RD_View *callstack = &rd_nil_view; - RD_View *breakpoints = &rd_nil_view; - RD_View *watch_pins = &rd_nil_view; - RD_View *output = &rd_nil_view; - RD_View *targets = &rd_nil_view; - RD_View *scheduler = &rd_nil_view; - RD_View *modules = &rd_nil_view; - RD_View *disasm = &rd_nil_view; - RD_View *memory = &rd_nil_view; - RD_View *getting_started = &rd_nil_view; - RD_HandleList code_views = {0}; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) - { - RD_Handle handle = rd_handle_from_panel(panel); - rd_handle_list_push(scratch.arena, &panels_to_close, handle); - for(RD_View *view = panel->first_tab_view, *next = 0; !rd_view_is_nil(view); view = next) - { - next = view->order_next; - RD_ViewRuleKind view_rule_kind = rd_view_rule_kind_from_string(view->spec->string); - B32 needs_delete = 1; - switch(view_rule_kind) - { - default:{}break; - case RD_ViewRuleKind_Watch: {if(rd_view_is_nil(watch)) { needs_delete = 0; watch = view;} }break; - case RD_ViewRuleKind_Locals: {if(rd_view_is_nil(locals)) { needs_delete = 0; locals = view;} }break; - case RD_ViewRuleKind_Registers: {if(rd_view_is_nil(regs)) { needs_delete = 0; regs = view;} }break; - case RD_ViewRuleKind_Globals: {if(rd_view_is_nil(globals)) { needs_delete = 0; globals = view;} }break; - case RD_ViewRuleKind_ThreadLocals: {if(rd_view_is_nil(tlocals)) { needs_delete = 0; tlocals = view;} }break; - case RD_ViewRuleKind_Types: {if(rd_view_is_nil(types)) { needs_delete = 0; types = view;} }break; - case RD_ViewRuleKind_Procedures: {if(rd_view_is_nil(procs)) { needs_delete = 0; procs = view;} }break; - case RD_ViewRuleKind_CallStack: {if(rd_view_is_nil(callstack)) { needs_delete = 0; callstack = view;} }break; - case RD_ViewRuleKind_Breakpoints: {if(rd_view_is_nil(breakpoints)) { needs_delete = 0; breakpoints = view;} }break; - case RD_ViewRuleKind_WatchPins: {if(rd_view_is_nil(watch_pins)) { needs_delete = 0; watch_pins = view;} }break; - case RD_ViewRuleKind_Output: {if(rd_view_is_nil(output)) { needs_delete = 0; output = view;} }break; - case RD_ViewRuleKind_Targets: {if(rd_view_is_nil(targets)) { needs_delete = 0; targets = view;} }break; - case RD_ViewRuleKind_Scheduler: {if(rd_view_is_nil(scheduler)) { needs_delete = 0; scheduler = view;} }break; - case RD_ViewRuleKind_Modules: {if(rd_view_is_nil(modules)) { needs_delete = 0; modules = view;} }break; - case RD_ViewRuleKind_Disasm: {if(rd_view_is_nil(disasm)) { needs_delete = 0; disasm = view;} }break; - case RD_ViewRuleKind_Memory: {if(rd_view_is_nil(memory)) { needs_delete = 0; memory = view;} }break; - case RD_ViewRuleKind_GettingStarted:{if(rd_view_is_nil(getting_started)) { needs_delete = 0; getting_started = view;} }break; - case RD_ViewRuleKind_Text: - { - needs_delete = 0; - rd_handle_list_push(scratch.arena, &code_views, rd_handle_from_view(view)); - }break; - } - if(!needs_delete) - { - rd_panel_remove_tab_view(panel, view); - } - } - } - - //- rjf: close all panels/views - for(RD_HandleNode *n = panels_to_close.first; n != 0; n = n->next) - { - RD_Panel *panel = rd_panel_from_handle(n->handle); - if(panel != ws->root_panel) - { - rd_panel_release(ws, panel); - } - else - { - rd_panel_release_all_views(panel); - panel->first = panel->last = &rd_nil_panel; - } - } - - //- rjf: allocate any missing views - if(rd_view_is_nil(watch)) - { - watch = rd_view_alloc(); - rd_view_equip_spec(watch, rd_view_rule_info_from_kind(RD_ViewRuleKind_Watch), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(locals)) - { - locals = rd_view_alloc(); - rd_view_equip_spec(locals, rd_view_rule_info_from_kind(RD_ViewRuleKind_Locals), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(regs)) - { - regs = rd_view_alloc(); - rd_view_equip_spec(regs, rd_view_rule_info_from_kind(RD_ViewRuleKind_Registers), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(globals)) - { - globals = rd_view_alloc(); - rd_view_equip_spec(globals, rd_view_rule_info_from_kind(RD_ViewRuleKind_Globals), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(tlocals)) - { - tlocals = rd_view_alloc(); - rd_view_equip_spec(tlocals, rd_view_rule_info_from_kind(RD_ViewRuleKind_ThreadLocals), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(types)) - { - types = rd_view_alloc(); - rd_view_equip_spec(types, rd_view_rule_info_from_kind(RD_ViewRuleKind_Types), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(procs)) - { - procs = rd_view_alloc(); - rd_view_equip_spec(procs, rd_view_rule_info_from_kind(RD_ViewRuleKind_Procedures), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(callstack)) - { - callstack = rd_view_alloc(); - rd_view_equip_spec(callstack, rd_view_rule_info_from_kind(RD_ViewRuleKind_CallStack), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(breakpoints)) - { - breakpoints = rd_view_alloc(); - rd_view_equip_spec(breakpoints, rd_view_rule_info_from_kind(RD_ViewRuleKind_Breakpoints), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(watch_pins)) - { - watch_pins = rd_view_alloc(); - rd_view_equip_spec(watch_pins, rd_view_rule_info_from_kind(RD_ViewRuleKind_WatchPins), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(output)) - { - output = rd_view_alloc(); - rd_view_equip_spec(output, rd_view_rule_info_from_kind(RD_ViewRuleKind_Output), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(targets)) - { - targets = rd_view_alloc(); - rd_view_equip_spec(targets, rd_view_rule_info_from_kind(RD_ViewRuleKind_Targets), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(scheduler)) - { - scheduler = rd_view_alloc(); - rd_view_equip_spec(scheduler, rd_view_rule_info_from_kind(RD_ViewRuleKind_Scheduler), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(modules)) - { - modules = rd_view_alloc(); - rd_view_equip_spec(modules, rd_view_rule_info_from_kind(RD_ViewRuleKind_Modules), str8_zero(), &md_nil_node); - } - if(rd_view_is_nil(disasm)) - { - disasm = rd_view_alloc(); - rd_view_equip_spec(disasm, rd_view_rule_info_from_kind(RD_ViewRuleKind_Disasm), str8_zero(), &md_nil_node); - } - if(layout == Layout_Default && rd_view_is_nil(memory)) - { - memory = rd_view_alloc(); - rd_view_equip_spec(memory, rd_view_rule_info_from_kind(RD_ViewRuleKind_Memory), str8_zero(), &md_nil_node); - } - if(code_views.count == 0 && rd_view_is_nil(getting_started)) - { - getting_started = rd_view_alloc(); - rd_view_equip_spec(getting_started, rd_view_rule_info_from_kind(RD_ViewRuleKind_GettingStarted), str8_zero(), &md_nil_node); - } - - //- rjf: apply layout - switch(layout) - { - //- rjf: default layout - case Layout_Default: + + //- rjf: (default layout) + case RD_CmdKind_ResetToDefaultPanels: { // rjf: root split - ws->root_panel->split_axis = Axis2_X; - RD_Panel *root_0 = rd_panel_alloc(ws); - RD_Panel *root_1 = rd_panel_alloc(ws); - rd_panel_insert(ws->root_panel, ws->root_panel->last, root_0); - rd_panel_insert(ws->root_panel, ws->root_panel->last, root_1); - root_0->pct_of_parent = 0.85f; - root_1->pct_of_parent = 0.15f; + rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); + RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.85")); + RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.15")); // rjf: root_0 split - root_0->split_axis = Axis2_Y; - RD_Panel *root_0_0 = rd_panel_alloc(ws); - RD_Panel *root_0_1 = rd_panel_alloc(ws); - rd_panel_insert(root_0, root_0->last, root_0_0); - rd_panel_insert(root_0, root_0->last, root_0_1); - root_0_0->pct_of_parent = 0.80f; - root_0_1->pct_of_parent = 0.20f; + RD_Cfg *root_0_0 = rd_cfg_new(root_0, str8_lit("0.80")); + RD_Cfg *root_0_1 = rd_cfg_new(root_0, str8_lit("0.20")); // rjf: root_1 split - root_1->split_axis = Axis2_Y; - RD_Panel *root_1_0 = rd_panel_alloc(ws); - RD_Panel *root_1_1 = rd_panel_alloc(ws); - rd_panel_insert(root_1, root_1->last, root_1_0); - rd_panel_insert(root_1, root_1->last, root_1_1); - root_1_0->pct_of_parent = 0.50f; - root_1_1->pct_of_parent = 0.50f; - rd_panel_insert_tab_view(root_1_0, root_1_0->last_tab_view, targets); - rd_panel_insert_tab_view(root_1_1, root_1_1->last_tab_view, scheduler); - root_1_0->selected_tab_view = rd_handle_from_view(targets); - root_1_1->selected_tab_view = rd_handle_from_view(scheduler); - root_1_1->tab_side = Side_Max; + RD_Cfg *root_1_0 = rd_cfg_new(root_1, str8_lit("0.50")); + RD_Cfg *root_1_1 = rd_cfg_new(root_1, str8_lit("0.50")); + rd_cfg_insert_child(root_1_0, root_1_0->last, targets); + rd_cfg_insert_child(root_1_1, root_1_1->last, threads); + rd_cfg_insert_child(root_1_1, root_1_1->last, processes); + rd_cfg_insert_child(root_1_1, root_1_1->last, machines); + rd_cfg_new(targets, str8_lit("selected")); + rd_cfg_new(threads, str8_lit("selected")); - // rjf: root_0_0 split - root_0_0->split_axis = Axis2_X; - RD_Panel *root_0_0_0 = rd_panel_alloc(ws); - RD_Panel *root_0_0_1 = rd_panel_alloc(ws); - rd_panel_insert(root_0_0, root_0_0->last, root_0_0_0); - rd_panel_insert(root_0_0, root_0_0->last, root_0_0_1); - root_0_0_0->pct_of_parent = 0.25f; - root_0_0_1->pct_of_parent = 0.75f; + // rjf: root 0_0 split + RD_Cfg *root_0_0_0 = rd_cfg_new(root_0_0, str8_lit("0.25")); + RD_Cfg *root_0_0_1 = rd_cfg_new(root_0_0, str8_lit("0.75")); // rjf: root_0_0_0 split - root_0_0_0->split_axis = Axis2_Y; - RD_Panel *root_0_0_0_0 = rd_panel_alloc(ws); - RD_Panel *root_0_0_0_1 = rd_panel_alloc(ws); - rd_panel_insert(root_0_0_0, root_0_0_0->last, root_0_0_0_0); - rd_panel_insert(root_0_0_0, root_0_0_0->last, root_0_0_0_1); - root_0_0_0_0->pct_of_parent = 0.5f; - root_0_0_0_1->pct_of_parent = 0.5f; - rd_panel_insert_tab_view(root_0_0_0_0, root_0_0_0_0->last_tab_view, disasm); - root_0_0_0_0->selected_tab_view = rd_handle_from_view(disasm); - rd_panel_insert_tab_view(root_0_0_0_1, root_0_0_0_1->last_tab_view, breakpoints); - rd_panel_insert_tab_view(root_0_0_0_1, root_0_0_0_1->last_tab_view, watch_pins); - rd_panel_insert_tab_view(root_0_0_0_1, root_0_0_0_1->last_tab_view, output); - rd_panel_insert_tab_view(root_0_0_0_1, root_0_0_0_1->last_tab_view, memory); - root_0_0_0_1->selected_tab_view = rd_handle_from_view(output); + RD_Cfg *root_0_0_0_0 = rd_cfg_new(root_0_0_0, str8_lit("0.50")); + RD_Cfg *root_0_0_0_1 = rd_cfg_new(root_0_0_0, str8_lit("0.50")); + rd_cfg_insert_child(root_0_0_0_0, root_0_0_0_0->last, disasm); + rd_cfg_new(disasm, str8_lit("selected")); + rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, breakpoints); + rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, watch_pins); + rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, output); + rd_cfg_insert_child(root_0_0_0_1, root_0_0_0_1->last, memory); + rd_cfg_new(output, str8_lit("selected")); // rjf: root_0_1 split - root_0_1->split_axis = Axis2_X; - RD_Panel *root_0_1_0 = rd_panel_alloc(ws); - RD_Panel *root_0_1_1 = rd_panel_alloc(ws); - rd_panel_insert(root_0_1, root_0_1->last, root_0_1_0); - rd_panel_insert(root_0_1, root_0_1->last, root_0_1_1); - root_0_1_0->pct_of_parent = 0.60f; - root_0_1_1->pct_of_parent = 0.40f; - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, watch); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, locals); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, regs); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, globals); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, tlocals); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, types); - rd_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, procs); - root_0_1_0->selected_tab_view = rd_handle_from_view(watch); - root_0_1_0->tab_side = Side_Max; - rd_panel_insert_tab_view(root_0_1_1, root_0_1_1->last_tab_view, callstack); - rd_panel_insert_tab_view(root_0_1_1, root_0_1_1->last_tab_view, modules); - root_0_1_1->selected_tab_view = rd_handle_from_view(callstack); - root_0_1_1->tab_side = Side_Max; + RD_Cfg *root_0_1_0 = rd_cfg_new(root_0_1, str8_lit("0.60")); + RD_Cfg *root_0_1_1 = rd_cfg_new(root_0_1, str8_lit("0.40")); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, watches); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, locals); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, registers); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, globals); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, thread_locals); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, types); + rd_cfg_insert_child(root_0_1_0, root_0_1_0->last, procedures); + rd_cfg_new(watches, str8_lit("selected")); + rd_cfg_new(root_0_1_0, str8_lit("tabs_on_bottom")); + rd_cfg_insert_child(root_0_1_1, root_0_1_1->last, call_stack); + rd_cfg_insert_child(root_0_1_1, root_0_1_1->last, modules); + rd_cfg_new(call_stack, str8_lit("selected")); + rd_cfg_new(root_0_1_1, str8_lit("tabs_on_bottom")); // rjf: fill main panel with getting started, OR all collected code views - if(!rd_view_is_nil(getting_started)) + RD_Cfg *main_panel = root_0_0_1; + if(getting_started != &rd_nil_cfg) { - rd_panel_insert_tab_view(root_0_0_1, root_0_0_1->last_tab_view, getting_started); + rd_cfg_insert_child(main_panel, main_panel->last, getting_started); + rd_cfg_new(getting_started, str8_lit("selected")); } - for(RD_HandleNode *n = code_views.first; n != 0; n = n->next) + else if(texts.first) { - RD_View *view = rd_view_from_handle(n->handle); - if(!rd_view_is_nil(view)) - { - rd_panel_insert_tab_view(root_0_0_1, root_0_0_1->last_tab_view, view); - } + rd_cfg_new(texts.first->v, str8_lit("selected")); + } + for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + { + rd_cfg_insert_child(main_panel, main_panel->last, n->v); } - // rjf: choose initial focused panel - ws->focused_panel = root_0_0_1; + // rjf: set main panel as selected + rd_cfg_new(main_panel, str8_lit("selected")); }break; - //- rjf: compact layout: - case Layout_Compact: + //- rjf: (compact layout) + case RD_CmdKind_ResetToCompactPanels: { // rjf: root split - ws->root_panel->split_axis = Axis2_X; - RD_Panel *root_0 = rd_panel_alloc(ws); - RD_Panel *root_1 = rd_panel_alloc(ws); - rd_panel_insert(ws->root_panel, ws->root_panel->last, root_0); - rd_panel_insert(ws->root_panel, ws->root_panel->last, root_1); - root_0->pct_of_parent = 0.25f; - root_1->pct_of_parent = 0.75f; + rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); + RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.25")); + RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.75")); // rjf: root_0 split - root_0->split_axis = Axis2_Y; - RD_Panel *root_0_0 = rd_panel_alloc(ws); - { - if(!rd_view_is_nil(watch)) { rd_panel_insert_tab_view(root_0_0, root_0_0->last_tab_view, watch); } - if(!rd_view_is_nil(types)) { rd_panel_insert_tab_view(root_0_0, root_0_0->last_tab_view, types); } - root_0_0->selected_tab_view = rd_handle_from_view(watch); - } - RD_Panel *root_0_1 = rd_panel_alloc(ws); - { - if(!rd_view_is_nil(scheduler)) { rd_panel_insert_tab_view(root_0_1, root_0_1->last_tab_view, scheduler); } - if(!rd_view_is_nil(targets)) { rd_panel_insert_tab_view(root_0_1, root_0_1->last_tab_view, targets); } - if(!rd_view_is_nil(breakpoints)) { rd_panel_insert_tab_view(root_0_1, root_0_1->last_tab_view, breakpoints); } - if(!rd_view_is_nil(watch_pins)) { rd_panel_insert_tab_view(root_0_1, root_0_1->last_tab_view, watch_pins); } - root_0_1->selected_tab_view = rd_handle_from_view(scheduler); - } - RD_Panel *root_0_2 = rd_panel_alloc(ws); - { - if(!rd_view_is_nil(disasm)) { rd_panel_insert_tab_view(root_0_2, root_0_2->last_tab_view, disasm); } - if(!rd_view_is_nil(output)) { rd_panel_insert_tab_view(root_0_2, root_0_2->last_tab_view, output); } - root_0_2->selected_tab_view = rd_handle_from_view(disasm); - } - RD_Panel *root_0_3 = rd_panel_alloc(ws); - { - if(!rd_view_is_nil(callstack)) { rd_panel_insert_tab_view(root_0_3, root_0_3->last_tab_view, callstack); } - if(!rd_view_is_nil(modules)) { rd_panel_insert_tab_view(root_0_3, root_0_3->last_tab_view, modules); } - root_0_3->selected_tab_view = rd_handle_from_view(callstack); - } - rd_panel_insert(root_0, root_0->last, root_0_0); - rd_panel_insert(root_0, root_0->last, root_0_1); - rd_panel_insert(root_0, root_0->last, root_0_2); - rd_panel_insert(root_0, root_0->last, root_0_3); - root_0_0->pct_of_parent = 0.25f; - root_0_1->pct_of_parent = 0.25f; - root_0_2->pct_of_parent = 0.25f; - root_0_3->pct_of_parent = 0.25f; + RD_Cfg *root_0_0 = rd_cfg_new(root_0, str8_lit("0.25")); + RD_Cfg *root_0_1 = rd_cfg_new(root_0, str8_lit("0.25")); + RD_Cfg *root_0_2 = rd_cfg_new(root_0, str8_lit("0.25")); + RD_Cfg *root_0_3 = rd_cfg_new(root_0, str8_lit("0.25")); + rd_cfg_insert_child(root_0_0, root_0_0->last, watches); + rd_cfg_insert_child(root_0_0, root_0_0->last, types); + rd_cfg_new(watches, str8_lit("selected")); + rd_cfg_insert_child(root_0_1, root_0_1->last, threads); + rd_cfg_insert_child(root_0_1, root_0_1->last, targets); + rd_cfg_insert_child(root_0_1, root_0_1->last, breakpoints); + rd_cfg_insert_child(root_0_1, root_0_1->last, watch_pins); + rd_cfg_new(threads, str8_lit("selected")); + rd_cfg_insert_child(root_0_2, root_0_2->last, disasm); + rd_cfg_insert_child(root_0_2, root_0_2->last, output); + rd_cfg_new(disasm, str8_lit("selected")); + rd_cfg_insert_child(root_0_3, root_0_3->last, call_stack); + rd_cfg_insert_child(root_0_3, root_0_3->last, modules); + rd_cfg_new(call_stack, str8_lit("selected")); // rjf: fill main panel with getting started, OR all collected code views - if(!rd_view_is_nil(getting_started)) + RD_Cfg *main_panel = root_1; + if(getting_started != &rd_nil_cfg) { - rd_panel_insert_tab_view(root_1, root_1->last_tab_view, getting_started); + rd_cfg_insert_child(main_panel, main_panel->last, getting_started); + rd_cfg_new(getting_started, str8_lit("selected")); } - for(RD_HandleNode *n = code_views.first; n != 0; n = n->next) + else if(texts.first) { - RD_View *view = rd_view_from_handle(n->handle); - if(!rd_view_is_nil(view)) - { - rd_panel_insert_tab_view(root_1, root_1->last_tab_view, view); - } + rd_cfg_new(texts.first->v, str8_lit("selected")); + } + for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + { + rd_cfg_insert_child(main_panel, main_panel->last, n->v); } - // rjf: choose initial focused panel - ws->focused_panel = root_1; + // rjf: set main panel as selected + rd_cfg_new(main_panel, str8_lit("selected")); + }break; + + //- rjf: simple layout + case RD_CmdKind_ResetToSimplePanels: + { + // rjf: root split + rd_cfg_child_from_string_or_alloc(window, str8_lit("split_x")); + RD_Cfg *root_0 = rd_cfg_new(panels, str8_lit("0.25")); + RD_Cfg *root_1 = rd_cfg_new(panels, str8_lit("0.75")); + + // rjf: fill smaller panel with watch + rd_cfg_insert_child(root_0, root_0->last, watches); + rd_cfg_new(watches, str8_lit("selected")); + + // rjf: fill main panel with getting started, OR all collected code views + RD_Cfg *main_panel = root_1; + if(getting_started != &rd_nil_cfg) + { + rd_cfg_insert_child(main_panel, main_panel->last, getting_started); + rd_cfg_new(getting_started, str8_lit("selected")); + } + else if(texts.first) + { + rd_cfg_new(texts.first->v, str8_lit("selected")); + } + for(RD_CfgNode *n = texts.first; n != 0; n = n->next) + { + rd_cfg_insert_child(main_panel, main_panel->last, n->v); + } + + // rjf: set main panel as selected + rd_cfg_new(main_panel, str8_lit("selected")); }break; } - // rjf: dispatch cfg saves - for(RD_CfgSrc src = (RD_CfgSrc)0; src < RD_CfgSrc_COUNT; src = (RD_CfgSrc)(src+1)) + //- rjf: release any unused views from the previous layout +#define X(name) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} +#define Y(name, rule, expr) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} +#define Z(name) if(name->parent == &rd_nil_cfg) {rd_cfg_release(name);} + RD_FixedTabXList +#undef X +#undef Y +#undef Z + + //- rjf: remember that we reset the panel layouts + RD_WindowState *ws = rd_window_state_from_cfg(window); + if(ws != &rd_nil_window_state) { - RD_CmdKind write_cmd = rd_cfg_src_write_cmd_kind_table[src]; - rd_cmd(write_cmd, .file_path = rd_cfg_path_from_src(src)); + ws->window_layout_reset = 1; } }break; //- rjf: thread finding case RD_CmdKind_FindThread: - for(RD_Window *ws = rd_state->first_window; ws != 0; ws = ws->next) + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) + RD_RegsScope(.window = ws->cfg_id) { DI_Scope *scope = di_scope_open(); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); U64 unwind_index = rd_regs()->unwind_count; U64 inline_depth = rd_regs()->inline_depth; if(thread->kind == CTRL_EntityKind_Thread) @@ -14768,7 +14370,7 @@ rd_frame(void) // rjf: snap to resolved line B32 missing_rip = (rip_vaddr == 0); B32 dbgi_missing = (dbgi_key.min_timestamp == 0 || dbgi_key.path.size == 0); - B32 dbgi_pending = !dbgi_missing && rdi == &di_rdi_parsed_nil; + B32 dbgi_pending = !dbgi_missing && rdi == &rdi_parsed_nil; B32 has_line_info = (line.voff_range.max != 0); B32 has_module = (module != &ctrl_entity_nil); B32 has_dbg_info = has_module && !dbgi_missing; @@ -14806,9 +14408,10 @@ rd_frame(void) di_scope_close(scope); }break; case RD_CmdKind_FindSelectedThread: - for(RD_Window *ws = rd_state->first_window; ws != 0; ws = ws->next) + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) + RD_RegsScope(.window = ws->cfg_id) { - CTRL_Entity *selected_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_base_regs()->thread); + CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); rd_cmd(RD_CmdKind_FindThread, .thread = selected_thread->handle, .unwind_count = rd_base_regs()->unwind_count, @@ -14823,6 +14426,12 @@ rd_frame(void) { B32 name_resolved = 0; + // rjf: strip `s + if(name.size >= 2 && name.str[0] == '`' && name.str[name.size-1] == '`') + { + name = str8_skip(str8_chop(name, 1), 1); + } + // rjf: try to resolve name as a symbol U64 voff = 0; DI_Key voff_dbgi_key = {0}; @@ -14858,8 +14467,9 @@ rd_frame(void) String8List search_parts = str8_split_path(scratch.arena, file_part_of_name); // rjf: get source path - RD_View *src_view = rd_view_from_handle(rd_regs()->view); - String8 src_file_path = rd_file_path_from_eval_string(scratch.arena, str8(src_view->query_buffer, src_view->query_string_size)); + RD_Cfg *src_view = rd_cfg_from_id(rd_regs()->view); + String8 src_view_expr = rd_expr_from_cfg(src_view); + String8 src_file_path = rd_file_path_from_eval_string(scratch.arena, src_view_expr); String8List src_file_parts = str8_split_path(scratch.arena, src_file_path); // rjf: search for actual file @@ -14903,7 +14513,7 @@ rd_frame(void) U64 vaddr = 0; if(voff_dbgi_key.path.size != 0) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &voff_dbgi_key); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &voff_dbgi_key); CTRL_Entity *module = ctrl_entity_list_first(&modules); process = ctrl_entity_ancestor_from_kind(module, CTRL_EntityKind_Process); if(process != &ctrl_entity_nil) @@ -14972,7 +14582,8 @@ rd_frame(void) // the biggest empty panel. // 4. If there is no empty panel, then we will pick the biggest // panel. - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); // rjf: grab things to find. path * point, process * address, etc. String8 file_path = {0}; @@ -14984,8 +14595,8 @@ rd_frame(void) { file_path = rd_mapped_from_file_path(scratch.arena, rd_regs()->file_path); point = rd_regs()->cursor; - thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - process = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->process); + thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); + process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); vaddr = rd_regs()->vaddr; if(file_path.size == 0) { @@ -15000,33 +14611,36 @@ rd_frame(void) D_LineList lines = d_lines_from_file_path_line_num(scratch.arena, file_path, point.line); for(D_LineNode *n = lines.first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &n->v.dbgi_key); - CTRL_Entity *module = ctrl_module_from_thread_candidates(d_state->ctrl_entity_store, thread, &modules); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); break; } } // rjf: first, try to find panel/view pair that already has the src file open - RD_Panel *panel_w_this_src_code = &rd_nil_panel; - RD_View *view_w_this_src_code = &rd_nil_view; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + RD_PanelNode *panel_w_this_src_code = &rd_nil_panel_node; + RD_Cfg *view_w_this_src_code = &rd_nil_cfg; + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(!rd_panel_is_nil(panel->first)) + if(panel->first != &rd_nil_panel_node) { continue; } - for(RD_View *view = panel->first_tab_view; !rd_view_is_nil(view); view = view->order_next) + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - if(rd_view_is_project_filtered(view)) { continue; } - String8 view_file_path = rd_file_path_from_eval_string(scratch.arena, str8(view->query_buffer, view->query_string_size)); - RD_ViewRuleKind view_kind = rd_view_rule_kind_from_string(view->spec->string); - if((view_kind == RD_ViewRuleKind_Text || view_kind == RD_ViewRuleKind_PendingFile) && - path_match_normalized(view_file_path, file_path)) + RD_Cfg *tab = tab_n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } + String8 tab_expr = rd_expr_from_cfg(tab); + String8 tab_file_path = rd_file_path_from_eval_string(scratch.arena, tab_expr); + if((str8_match(tab->string, str8_lit("text"), 0) || str8_match(tab->string, str8_lit("pending"), 0)) && + path_match_normalized(tab_file_path, file_path)) { panel_w_this_src_code = panel; - view_w_this_src_code = view; - if(view == rd_selected_tab_from_panel(panel)) + view_w_this_src_code = tab; + if(tab == panel->selected_tab) { break; } @@ -15034,25 +14648,56 @@ rd_frame(void) } } - // rjf: find a panel that already has *any* code open (prioritize largest) - RD_Panel *panel_w_any_src_code = &rd_nil_panel; + // rjf: try to find panel/view pair that has any *auto* source code tab open + RD_PanelNode *panel_w_auto = &rd_nil_panel_node; + RD_Cfg *view_w_auto = &rd_nil_cfg; + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - Rng2F32 root_rect = os_client_rect_from_window(ws->os); - F32 best_panel_area = 0; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + if(panel->first != &rd_nil_panel_node) { - if(!rd_panel_is_nil(panel->first)) + continue; + } + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + { + RD_Cfg *tab = tab_n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } + RD_RegsScope(.tab = tab->id, .view = tab->id) + { + if(str8_match(tab->string, str8_lit("text"), 0) && + rd_view_setting_b32_from_name(str8_lit("auto"))) + { + panel_w_auto = panel; + view_w_auto = tab; + } + } + } + } + + // rjf: find a panel that already has *any* code open (prioritize largest) + RD_PanelNode *panel_w_any_src_code = &rd_nil_panel_node; + { + Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); + F32 best_panel_area = 0; + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) + { + if(panel->first != &rd_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel(root_rect, ws->root_panel, panel); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; - for(RD_View *view = panel->first_tab_view; !rd_view_is_nil(view); view = view->order_next) + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - if(rd_view_is_project_filtered(view)) { continue; } - RD_ViewRuleKind view_kind = rd_view_rule_kind_from_string(view->spec->string); - if(view_kind == RD_ViewRuleKind_Text && panel_area > best_panel_area) + RD_Cfg *tab = tab_n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } + String8 view_expr = rd_expr_from_cfg(tab); + String8 file_path = rd_file_path_from_eval_string(scratch.arena, view_expr); + if(str8_match(tab->string, str8_lit("text"), 0) && file_path.size != 0 && panel_area > best_panel_area) { panel_w_any_src_code = panel; best_panel_area = panel_area; @@ -15063,34 +14708,39 @@ rd_frame(void) } // rjf: try to find panel/view pair that has disassembly open (prioritize largest) - RD_Panel *panel_w_disasm = &rd_nil_panel; - RD_View *view_w_disasm = &rd_nil_view; + RD_PanelNode *panel_w_disasm = &rd_nil_panel_node; + RD_Cfg *view_w_disasm = &rd_nil_cfg; { - Rng2F32 root_rect = os_client_rect_from_window(ws->os); + Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(!rd_panel_is_nil(panel->first)) + if(panel->first != &rd_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel(root_rect, ws->root_panel, panel); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; - RD_View *panel_selected_tab = rd_selected_tab_from_panel(panel); - for(RD_View *view = panel->first_tab_view; !rd_view_is_nil(view); view = view->order_next) + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) { - if(rd_view_is_project_filtered(view)) { continue; } - RD_ViewRuleKind view_kind = rd_view_rule_kind_from_string(view->spec->string); - B32 view_is_selected = (view == panel_selected_tab); - if(view_kind == RD_ViewRuleKind_Disasm && view->query_string_size == 0 && panel_area > best_panel_area) + RD_Cfg *tab = tab_n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } + RD_RegsScope(.view = tab->id, .tab = tab->id) { - panel_w_disasm = panel; - view_w_disasm = view; - best_panel_area = panel_area; - if(view_is_selected) + B32 tab_is_selected = (tab == panel->selected_tab); + String8 expr_string = rd_expr_from_cfg(tab); + if(str8_match(tab->string, str8_lit("disasm"), 0) && expr_string.size == 0 && panel_area > best_panel_area) { - break; + panel_w_disasm = panel; + view_w_disasm = tab; + best_panel_area = panel_area; + if(tab_is_selected) + { + break; + } } } } @@ -15098,73 +14748,81 @@ rd_frame(void) } // rjf: find the biggest panel - RD_Panel *biggest_panel = &rd_nil_panel; + RD_PanelNode *biggest_panel = &rd_nil_panel_node; { - Rng2F32 root_rect = os_client_rect_from_window(ws->os); + Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(!rd_panel_is_nil(panel->first)) + if(panel->first != &rd_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel(root_rect, ws->root_panel, panel); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); - F32 area = panel_rect_dim.x * panel_rect_dim.y; - if((best_panel_area == 0 || area > best_panel_area)) + F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; + if((best_panel_area == 0 || panel_area > best_panel_area)) { - best_panel_area = area; + best_panel_area = panel_area; biggest_panel = panel; } } } // rjf: find the biggest empty panel - RD_Panel *biggest_empty_panel = &rd_nil_panel; + RD_PanelNode *biggest_empty_panel = &rd_nil_panel_node; { - Rng2F32 root_rect = os_client_rect_from_window(ws->os); + Rng2F32 root_rect = r2f32(v2f32(0, 0), v2f32(1000, 1000)); F32 best_panel_area = 0; - for(RD_Panel *panel = ws->root_panel; !rd_panel_is_nil(panel); panel = rd_panel_rec_depth_first_pre(panel).next) + for(RD_PanelNode *panel = panel_tree.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panel_tree.root, panel).next) { - if(!rd_panel_is_nil(panel->first)) + if(panel->first != &rd_nil_panel_node) { continue; } - Rng2F32 panel_rect = rd_target_rect_from_panel(root_rect, ws->root_panel, panel); + Rng2F32 panel_rect = rd_target_rect_from_panel_node(root_rect, panel_tree.root, panel); Vec2F32 panel_rect_dim = dim_2f32(panel_rect); - F32 area = panel_rect_dim.x * panel_rect_dim.y; + F32 panel_area = panel_rect_dim.x*panel_rect_dim.y; B32 panel_is_empty = 1; - for(RD_View *v = panel->first_tab_view; !rd_view_is_nil(v); v = v->order_next) + for(RD_CfgNode *n = panel->tabs.first; n != 0; n = n->next) { - if(!rd_view_is_project_filtered(v)) + RD_Cfg *tab = n->v; + if(!rd_cfg_is_project_filtered(tab)) { panel_is_empty = 0; break; } } - if(panel_is_empty && (best_panel_area == 0 || area > best_panel_area)) + if(panel_is_empty && (best_panel_area == 0 || panel_area > best_panel_area)) { - best_panel_area = area; + best_panel_area = panel_area; biggest_empty_panel = panel; } } } // rjf: choose panel for source code - RD_Panel *src_code_dst_panel = &rd_nil_panel; + RD_PanelNode *src_code_dst_panel = &rd_nil_panel_node; + if(file_path.size != 0) { - if(rd_panel_is_nil(src_code_dst_panel)) { src_code_dst_panel = panel_w_this_src_code; } - if(rd_panel_is_nil(src_code_dst_panel)) { src_code_dst_panel = panel_w_any_src_code; } - if(rd_panel_is_nil(src_code_dst_panel)) { src_code_dst_panel = biggest_empty_panel; } - if(rd_panel_is_nil(src_code_dst_panel)) { src_code_dst_panel = biggest_panel; } + if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = panel_w_this_src_code; } + if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = panel_w_auto; } + if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = panel_w_any_src_code; } + if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = biggest_empty_panel; } + if(src_code_dst_panel == &rd_nil_panel_node) { src_code_dst_panel = biggest_panel; } } // rjf: choose panel for disassembly - RD_Panel *disasm_dst_panel = &rd_nil_panel; + RD_PanelNode *disasm_dst_panel = &rd_nil_panel_node; + if(vaddr != 0) { - if(rd_panel_is_nil(disasm_dst_panel)) { disasm_dst_panel = panel_w_disasm; } - if(rd_panel_is_nil(disasm_dst_panel)) { disasm_dst_panel = biggest_empty_panel; } - if(rd_panel_is_nil(disasm_dst_panel)) { disasm_dst_panel = biggest_panel; } + if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = panel_w_disasm; } + if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = biggest_empty_panel; } + if(disasm_dst_panel == &rd_nil_panel_node) { disasm_dst_panel = biggest_panel; } } // rjf: if disasm and source code match: @@ -15174,56 +14832,81 @@ rd_frame(void) { if(rd_regs()->prefer_disasm) { - src_code_dst_panel = &rd_nil_panel; + src_code_dst_panel = &rd_nil_panel_node; } else { - disasm_dst_panel = &rd_nil_panel; + disasm_dst_panel = &rd_nil_panel_node; } } // rjf: if disasm is not preferred, and we have no disassembly view // open at all, cancel disasm, so that it doesn't open if the user // doesn't want it. - if(!rd_regs()->prefer_disasm && panel_w_disasm == &rd_nil_panel) + if(!rd_regs()->prefer_disasm && panel_w_disasm == &rd_nil_panel_node && file_path.size != 0) { - disasm_dst_panel = &rd_nil_panel; + disasm_dst_panel = &rd_nil_panel_node; + } + + // rjf: if disasm is not preferred, and we have no disassembly view + // *selected* at all, cancel disasm, so that it doesn't open if the user + // doesn't want it. + if(!rd_regs()->prefer_disasm && view_w_disasm != &rd_nil_cfg && rd_cfg_child_from_string(view_w_disasm, str8_lit("selected")) == &rd_nil_cfg && + file_path.size != 0) + { + disasm_dst_panel = &rd_nil_panel_node; } // rjf: given the above, find source code location. - if(file_path.size != 0 && src_code_dst_panel != &rd_nil_panel) + if(file_path.size != 0 && src_code_dst_panel != &rd_nil_panel_node) { - RD_Panel *dst_panel = src_code_dst_panel; + RD_PanelNode *dst_panel = src_code_dst_panel; // rjf: construct new view if needed - RD_View *dst_view = view_w_this_src_code; - if(!rd_panel_is_nil(dst_panel) && rd_view_is_nil(view_w_this_src_code)) + RD_Cfg *dst_tab = view_w_this_src_code; + if(dst_tab == &rd_nil_cfg && dst_panel == panel_w_auto && view_w_auto != &rd_nil_cfg) { - RD_View *view = rd_view_alloc(); - String8 file_path_query = rd_eval_string_from_file_path(scratch.arena, file_path); - rd_view_equip_spec(view, rd_view_rule_info_from_kind(RD_ViewRuleKind_Text), file_path_query, &md_nil_node); - rd_panel_insert_tab_view(dst_panel, dst_panel->last_tab_view, view); - dst_view = view; + dst_tab = view_w_auto; + RD_ViewState *vs = rd_view_state_from_cfg(dst_tab); + vs->last_frame_index_built = 0; + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(dst_tab, str8_lit("expression")); + rd_cfg_new_replace(expr, rd_eval_string_from_file_path(scratch.arena, file_path)); + rd_cfg_new_replace(rd_cfg_child_from_string(dst_tab, str8_lit("cursor_line")), str8_lit("1")); + rd_cfg_new_replace(rd_cfg_child_from_string(dst_tab, str8_lit("cursor_column")), str8_lit("1")); + rd_cfg_new_replace(rd_cfg_child_from_string(dst_tab, str8_lit("mark_line")), str8_lit("1")); + rd_cfg_new_replace(rd_cfg_child_from_string(dst_tab, str8_lit("mark_column")), str8_lit("1")); + } + else if(dst_panel != &rd_nil_panel_node && dst_tab == &rd_nil_cfg) + { + dst_tab = rd_cfg_new(dst_panel->cfg, str8_lit("text")); + RD_Cfg *expr = rd_cfg_new(dst_tab, str8_lit("expression")); + rd_cfg_new(expr, rd_eval_string_from_file_path(scratch.arena, file_path)); + RD_Cfg *auto_root = rd_cfg_new(dst_tab, str8_lit("auto")); + rd_cfg_new(auto_root, str8_lit("1")); } // rjf: determine if we need a contain or center RD_CmdKind cursor_snap_kind = RD_CmdKind_CenterCursor; - if(!rd_panel_is_nil(dst_panel) && dst_view == view_w_this_src_code && rd_selected_tab_from_panel(dst_panel) == dst_view) + if(dst_panel != &rd_nil_panel_node && dst_tab == view_w_this_src_code && dst_panel->selected_tab == dst_tab) { cursor_snap_kind = RD_CmdKind_ContainCursor; } // rjf: move cursor & snap-to-cursor - if(!rd_panel_is_nil(dst_panel)) + if(dst_panel != &rd_nil_panel_node) RD_RegsScope(.panel = dst_panel->cfg->id, + .view = dst_tab->id, + .tab = dst_tab->id) { - dst_panel->selected_tab_view = rd_handle_from_view(dst_view); - rd_cmd(RD_CmdKind_GoToLine, - .panel = rd_handle_from_panel(dst_panel), - .view = rd_handle_from_view(dst_view), - .cursor = point); - rd_cmd(cursor_snap_kind, - .panel = rd_handle_from_panel(dst_panel), - .view = rd_handle_from_view(dst_view)); + if(rd_regs()->force_focus) + { + rd_cmd(RD_CmdKind_FocusPanel); + } + rd_cmd(RD_CmdKind_FocusTab); + if(point.line != 0) + { + rd_cmd(RD_CmdKind_GoToLine, .cursor = point); + } + rd_cmd(cursor_snap_kind); } // rjf: record @@ -15231,268 +14914,328 @@ rd_frame(void) } // rjf: given the above, find disassembly location. - if(process != &ctrl_entity_nil && vaddr != 0 && disasm_dst_panel != &rd_nil_panel) + if(process != &ctrl_entity_nil && vaddr != 0 && disasm_dst_panel != &rd_nil_panel_node) { - RD_Panel *dst_panel = disasm_dst_panel; + RD_PanelNode *dst_panel = disasm_dst_panel; - // rjf: construct new view if needed - RD_View *dst_view = view_w_disasm; - if(!rd_panel_is_nil(dst_panel) && rd_view_is_nil(view_w_disasm)) + // rjf: construct new tab if needed + RD_Cfg *dst_tab = view_w_disasm; + if(dst_panel != &rd_nil_panel_node && view_w_disasm == &rd_nil_cfg) { - RD_View *view = rd_view_alloc(); - rd_view_equip_spec(view, rd_view_rule_info_from_kind(RD_ViewRuleKind_Disasm), str8_zero(), &md_nil_node); - rd_panel_insert_tab_view(dst_panel, dst_panel->last_tab_view, view); - dst_view = view; + dst_tab = rd_cfg_new(dst_panel->cfg, str8_lit("disasm")); } // rjf: determine if we need a contain or center RD_CmdKind cursor_snap_kind = RD_CmdKind_CenterCursor; - if(dst_view == view_w_disasm && rd_selected_tab_from_panel(dst_panel) == dst_view) + if(dst_tab == view_w_disasm && dst_panel->selected_tab == dst_tab) { cursor_snap_kind = RD_CmdKind_ContainCursor; } // rjf: move cursor & snap-to-cursor - if(!rd_panel_is_nil(dst_panel)) + if(dst_panel != &rd_nil_panel_node) RD_RegsScope(.panel = dst_panel->cfg->id, + .tab = dst_tab->id, + .view = dst_tab->id) { - dst_panel->selected_tab_view = rd_handle_from_view(dst_view); - rd_cmd(RD_CmdKind_GoToAddress, - .process = process->handle, .vaddr = vaddr, - .panel = rd_handle_from_panel(dst_panel), - .view = rd_handle_from_view(dst_view)); + rd_cmd(RD_CmdKind_FocusTab); + rd_cmd(RD_CmdKind_GoToAddress, .process = process->handle, .vaddr = vaddr); rd_cmd(cursor_snap_kind); } } }break; - //- rjf: filtering - case RD_CmdKind_Filter: + //- rjf: queries + case RD_CmdKind_PushQuery: { - RD_View *view = rd_view_from_handle(rd_regs()->view); - RD_Panel *panel = rd_panel_from_handle(rd_regs()->panel); - B32 view_is_tab = 0; - for(RD_View *tab = panel->first_tab_view; !rd_view_is_nil(tab); tab = tab->order_next) + String8 cmd_name = rd_regs()->cmd_name; + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + + // rjf: floating queries -> set up window to build immediate-mode top-level query + RD_Cfg *view = &rd_nil_cfg; + B32 is_floating = (cmd_name.size == 0 || cmd_kind_info->query.flags & RD_QueryFlag_Floating); + if(is_floating) { - if(rd_view_is_project_filtered(tab)) { continue; } - if(tab == view) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + if(ws != &rd_nil_window_state) { - view_is_tab = 1; - break; + ws->query_is_active = 1; + arena_clear(ws->query_arena); + ws->query_regs = rd_regs_copy(ws->query_arena, rd_regs()); } + RD_Cfg *window_query = rd_immediate_cfg_from_keyf("window_query_%p", window); + rd_cfg_release_all_children(window_query); + view = rd_cfg_child_from_string_or_alloc(window_query, str8_lit("watch")); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(view, str8_lit("expression")); + rd_cfg_new_replace(expr, rd_regs()->expr); } - if(view_is_tab && view->spec->flags & RD_ViewRuleInfoFlag_CanFilter) + + // rjf: non-floating -> embed in view + else { - view->is_filtering ^= 1; - view->query_cursor = txt_pt(1, 1+(S64)view->query_string_size); - view->query_mark = txt_pt(1, 1); + view = rd_cfg_from_id(rd_regs()->view); + } + + // rjf: determine if the target view is a lister (and thus already has a command) + B32 view_is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); + + // rjf: target view is a lister -> do not do anything - cannot replace the command + if(!view_is_lister) + { + // rjf: unpack view's query info + RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); + RD_Cfg *cmd = rd_cfg_child_from_string_or_alloc(query, str8_lit("cmd")); + RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + if(is_floating) + { + if(rd_regs()->do_implicit_root) + { + rd_cfg_release(rd_cfg_child_from_string(view, str8_lit("explicit_root"))); + } + else + { + rd_cfg_child_from_string_or_alloc(view, str8_lit("explicit_root")); + } + if(!rd_regs()->do_lister) + { + rd_cfg_release(rd_cfg_child_from_string(view, str8_lit("lister"))); + } + else + { + rd_cfg_child_from_string_or_alloc(view, str8_lit("lister")); + } + } + + // rjf: choose initial input string + String8 initial_input = {0}; + if(cmd_name.size != 0) + { + if(cmd_kind_info->query.slot == RD_RegSlot_FilePath) + { + RD_Cfg *user = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + RD_Cfg *current_path = rd_cfg_child_from_string(user, str8_lit("current_path")); + String8 current_path_string = current_path->first->string; + if(current_path_string.size == 0) + { + current_path_string = path_normalized_from_string(scratch.arena, os_get_current_path(scratch.arena)); + } + initial_input = current_path_string; + initial_input = push_str8f(scratch.arena, "%S/", initial_input); + } + else if(cmd_kind_info->query.flags & RD_QueryFlag_KeepOldInput) + { + initial_input = input->first->string; + } + } + + // rjf: build query state + String8 current_query_cmd_name = cmd->first->string; + rd_cfg_new_replace(input, initial_input); + rd_cfg_new_replace(cmd, cmd_name); + RD_ViewState *vs = rd_view_state_from_cfg(view); + if(cmd_name.size != 0) + { + if(!vs->query_is_open && cmd_kind_info->query.flags & RD_QueryFlag_SelectOldInput) + { + vs->query_cursor = txt_pt(1, 1+input->first->string.size); + vs->query_mark = txt_pt(1, 1); + } + else + { + vs->query_cursor = txt_pt(1, 1+input->first->string.size); + vs->query_mark = vs->query_cursor; + } + if(!str8_match(current_query_cmd_name, cmd_name, 0)) + { + vs->query_is_open = 1; + } + else + { + vs->query_is_open ^= 1; + } + } + if(rd_regs()->do_lister) + { + vs->query_is_open = 1; + } + vs->contents_are_focused = 0; } }break; - case RD_CmdKind_ClearFilter: - { - RD_View *view = rd_view_from_handle(rd_regs()->view); - if(!rd_view_is_nil(view)) - { - view->query_string_size = 0; - view->is_filtering = 0; - view->query_cursor = view->query_mark = txt_pt(1, 1); - } - }break; - case RD_CmdKind_ApplyFilter: - { - RD_View *view = rd_view_from_handle(rd_regs()->view); - if(!rd_view_is_nil(view)) - { - view->is_filtering = 0; - } - }break; - - //- rjf: query completion case RD_CmdKind_CompleteQuery: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - String8 query_cmd_name = ws->query_cmd_name; - RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(query_cmd_name); - RD_RegSlot slot = info->query.slot; + // rjf: unpack params + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + String8 cmd_name = rd_view_query_cmd(); - // rjf: compound command parameters - if(slot != RD_RegSlot_Null && !(ws->query_cmd_regs_mask[slot/64] & (1ull<<(slot%64)))) + // rjf: find out if this view is a lister + B32 is_lister = (rd_cfg_child_from_string(view, str8_lit("lister")) != &rd_nil_cfg); + + // rjf: push command + if(cmd_name.size != 0) RD_RegsScope() { - RD_Regs *regs_copy = rd_regs_copy(ws->query_cmd_arena, rd_regs()); - Rng1U64 offset_range_in_regs = rd_reg_slot_range_table[slot]; - MemoryCopy((U8 *)(ws->query_cmd_regs) + offset_range_in_regs.min, - (U8 *)(regs_copy) + offset_range_in_regs.min, - dim_1u64(offset_range_in_regs)); - ws->query_cmd_regs_mask[slot/64] |= (1ull<<(slot%64)); + if(is_lister) + { + rd_regs()->view = ws->query_regs->view; + } + rd_push_cmd(cmd_name, rd_regs()); } - // rjf: determine if command is ready to run - B32 command_ready = 1; - if(slot != RD_RegSlot_Null && !(ws->query_cmd_regs_mask[slot/64] & (1ull<<(slot%64)))) + // rjf: complete query, either by closing the query popup, or closing the + // tab-embedded query edit + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_name); + if(is_lister) { - command_ready = 0; + ws->query_is_active = 0; } - - // rjf: end this query - if(!(info->query.flags & RD_QueryFlag_KeepOldInput)) + else if(!(cmd_kind_info->query.flags & RD_QueryFlag_KeepOldInput)) { - rd_cmd(RD_CmdKind_CancelQuery); - } - - // rjf: unset command register slot, if we keep old input (and thus need - // to re-query user) - if(info->query.flags & RD_QueryFlag_KeepOldInput) - { - ws->query_cmd_regs_mask[slot/64] &= ~(1ull<<(slot%64)); - } - - // rjf: push command if possible - if(command_ready) - { - rd_push_cmd(ws->query_cmd_name, ws->query_cmd_regs); + RD_ViewState *vs = rd_view_state_from_cfg(view); + vs->query_is_open = 0; + vs->query_string_size = 0; } }break; case RD_CmdKind_CancelQuery: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); - arena_clear(ws->query_cmd_arena); - MemoryZeroStruct(&ws->query_cmd_name); - ws->query_cmd_regs = 0; - MemoryZeroArray(ws->query_cmd_regs_mask); - for(RD_View *v = ws->query_view_stack_top, *next = 0; !rd_view_is_nil(v); v = next) + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + if(ws != &rd_nil_window_state) { - next = v->order_next; - rd_view_release(v); + ws->query_is_active = 0; + arena_clear(ws->query_arena); + ws->query_regs = 0; } - ws->query_view_stack_top = &rd_nil_view; + }break; + case RD_CmdKind_UpdateQuery: + { + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); + RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + rd_cfg_new_replace(input, rd_regs()->string); + RD_ViewState *vs = rd_view_state_from_cfg(view); + vs->query_cursor = vs->query_mark = txt_pt(1, rd_regs()->string.size+1); + vs->query_string_size = Min(sizeof(vs->query_buffer), rd_regs()->string.size); + MemoryCopy(vs->query_buffer, rd_regs()->string.str, vs->query_string_size); }break; //- rjf: developer commands case RD_CmdKind_ToggleDevMenu: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); ws->dev_menu_is_open ^= 1; }break; //- rjf: general entity operations - case RD_CmdKind_SelectEntity: + case RD_CmdKind_SelectCfg: case RD_CmdKind_SelectTarget: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - RD_EntityList all_of_the_same_kind = rd_query_cached_entity_list_with_kind(entity->kind); - B32 is_selected = !entity->disabled; - for(RD_EntityNode *n = all_of_the_same_kind.first; n != 0; n = n->next) + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + RD_CfgList all_of_the_same_kind = rd_cfg_top_level_list_from_string(scratch.arena, cfg->string); + B32 is_selected = !rd_disabled_from_cfg(cfg); + for(RD_CfgNode *n = all_of_the_same_kind.first; n != 0; n = n->next) { - RD_Entity *e = n->entity; - rd_entity_equip_disabled(e, 1); - } - if(!is_selected) - { - rd_entity_equip_disabled(entity, 0); + RD_Cfg *c = n->v; + rd_cfg_release(rd_cfg_child_from_string(c, str8_lit("enabled"))); } + RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); + rd_cfg_new_replace(enabled_root, str8_lit("1")); }break; - case RD_CmdKind_EnableEntity: + case RD_CmdKind_EnableCfg: case RD_CmdKind_EnableBreakpoint: case RD_CmdKind_EnableTarget: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - rd_entity_equip_disabled(entity, 0); + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); + rd_cfg_new_replacef(enabled_root, "1"); }break; - case RD_CmdKind_DisableEntity: + case RD_CmdKind_DisableCfg: case RD_CmdKind_DisableBreakpoint: case RD_CmdKind_DisableTarget: + case RD_CmdKind_DeselectCfg: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - rd_entity_equip_disabled(entity, 1); + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *enabled_root = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("enabled")); + rd_cfg_new_replacef(enabled_root, "0"); }break; - case RD_CmdKind_RemoveEntity: + case RD_CmdKind_RemoveCfg: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - RD_EntityKindFlags kind_flags = rd_entity_kind_flags_table[entity->kind]; - if(kind_flags & RD_EntityKindFlag_CanDelete) + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + rd_cfg_release(cfg); + }break; + case RD_CmdKind_NameCfg: + { + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + if(rd_regs()->string.size != 0) { - rd_entity_mark_for_deletion(entity); - } - }break; - case RD_CmdKind_NameEntity: - { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - String8 string = rd_regs()->string; - rd_entity_equip_name(entity, string); - }break; - case RD_CmdKind_ConditionEntity: - { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - String8 string = rd_regs()->string; - if(string.size != 0) - { - RD_Entity *child = rd_entity_child_from_kind_or_alloc(entity, RD_EntityKind_Condition); - rd_entity_equip_name(child, string); + RD_Cfg *label = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("label")); + rd_cfg_new(label, rd_regs()->string); } else { - RD_Entity *child = rd_entity_child_from_kind(entity, RD_EntityKind_Condition); - rd_entity_mark_for_deletion(child); + rd_cfg_release(rd_cfg_child_from_string(cfg, str8_lit("label"))); } }break; - case RD_CmdKind_DuplicateEntity: + case RD_CmdKind_ConditionCfg: { - RD_Entity *src = rd_entity_from_handle(rd_regs()->entity); - if(!rd_entity_is_nil(src)) + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + if(rd_regs()->string.size != 0) { - typedef struct Task Task; - struct Task + RD_Cfg *cnd = rd_cfg_child_from_string_or_alloc(cfg, str8_lit("condition")); + rd_cfg_new(cnd, rd_regs()->string); + } + else + { + rd_cfg_release(rd_cfg_child_from_string(cfg, str8_lit("condition"))); + } + }break; + case RD_CmdKind_DuplicateCfg: + { + RD_Cfg *src = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *dst = rd_cfg_deep_copy(src); + rd_cfg_insert_child(src->parent, src, dst); + }break; + case RD_CmdKind_RelocateCfg: + { + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + + // rjf: release old location info + { + RD_Cfg *src_loc = rd_cfg_child_from_string(cfg, str8_lit("source_location")); + RD_Cfg *addr_loc = rd_cfg_child_from_string(cfg, str8_lit("address_location")); + rd_cfg_release(src_loc); + rd_cfg_release(addr_loc); + } + + // rjf: attach new location info + { + String8 file_path = rd_regs()->file_path; + TxtPt pt = rd_regs()->cursor; + String8 expr_string = rd_regs()->expr; + U64 vaddr = rd_regs()->vaddr; + if(expr_string.size == 0 && vaddr != 0) { - Task *next; - RD_Entity *src_n; - RD_Entity *dst_parent; - }; - Task starter_task = {0, src, src->parent}; - Task *first_task = &starter_task; - Task *last_task = &starter_task; - for(Task *task = first_task; task != 0; task = task->next) + expr_string = push_str8f(scratch.arena, "0x%I64x", vaddr); + } + if(file_path.size != 0 && pt.line != 0) { - RD_Entity *src_n = task->src_n; - RD_Entity *dst_n = rd_entity_alloc(task->dst_parent, task->src_n->kind); - if(src_n->flags & RD_EntityFlag_HasTextPoint) {rd_entity_equip_txt_pt(dst_n, src_n->text_point);} - if(src_n->flags & RD_EntityFlag_HasU64) {rd_entity_equip_u64(dst_n, src_n->u64);} - if(src_n->flags & RD_EntityFlag_HasColor) {rd_entity_equip_color_hsva(dst_n, rd_hsva_from_entity(src_n));} - if(src_n->flags & RD_EntityFlag_HasVAddr) {rd_entity_equip_vaddr(dst_n, src_n->vaddr);} - if(src_n->disabled) {rd_entity_equip_disabled(dst_n, 1);} - if(src_n->string.size != 0) {rd_entity_equip_name(dst_n, src_n->string);} - dst_n->cfg_src = src_n->cfg_src; - for(RD_Entity *src_child = task->src_n->first; !rd_entity_is_nil(src_child); src_child = src_child->next) - { - Task *child_task = push_array(scratch.arena, Task, 1); - child_task->src_n = src_child; - child_task->dst_parent = dst_n; - SLLQueuePush(first_task, last_task, child_task); - } + RD_Cfg *src_loc = rd_cfg_new(cfg, str8_lit("source_location")); + rd_cfg_newf(src_loc, "%S:%I64d:%I64d", file_path, pt.line, pt.column); + } + else if(expr_string.size != 0) + { + RD_Cfg *vaddr_loc = rd_cfg_new(cfg, str8_lit("address_location")); + rd_cfg_new(vaddr_loc, expr_string); } } }break; - case RD_CmdKind_RelocateEntity: + case RD_CmdKind_SaveToProject: { - RD_Entity *entity = rd_entity_from_handle(rd_regs()->entity); - RD_Entity *location = rd_entity_child_from_kind(entity, RD_EntityKind_Location); - if(rd_entity_is_nil(location)) - { - location = rd_entity_alloc(entity, RD_EntityKind_Location); - } - location->flags &= ~RD_EntityFlag_HasTextPoint; - location->flags &= ~RD_EntityFlag_HasVAddr; - if(rd_regs()->cursor.line != 0) - { - rd_entity_equip_txt_pt(location, rd_regs()->cursor); - } - if(rd_regs()->vaddr != 0) - { - rd_entity_equip_vaddr(location, rd_regs()->vaddr); - rd_entity_equip_name(location, str8_zero()); - } - if(rd_regs()->file_path.size != 0) - { - rd_entity_equip_name(location, rd_regs()->file_path); - } + RD_Cfg *cfg = rd_cfg_from_id(rd_regs()->cfg); + rd_cfg_unhook(cfg->parent, cfg); + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + rd_cfg_insert_child(project, project->last, cfg); }break; //- rjf: breakpoints @@ -15501,99 +15244,60 @@ rd_frame(void) { String8 file_path = rd_regs()->file_path; TxtPt pt = rd_regs()->cursor; - String8 string = rd_regs()->string; U64 vaddr = rd_regs()->vaddr; - if(file_path.size != 0 || string.size != 0 || vaddr != 0) + String8 expr = rd_regs()->expr; + if(expr.size == 0 && vaddr != 0) { - //- TODO(rjf): @cfg add/toggle breakpoint + expr = push_str8f(scratch.arena, "0x%I64x", vaddr); + } + if(file_path.size != 0 || expr.size != 0) + { + B32 already_exists = 0; + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) { - B32 removed_already_existing = 0; - if(kind == RD_CmdKind_ToggleBreakpoint) + RD_Cfg *bp = n->v; + RD_Cfg *cnd = rd_cfg_child_from_string(bp, str8_lit("condition")); + RD_Location loc = rd_location_from_cfg(bp); + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); + B32 loc_matches_expr = (expr.size != 0 && str8_match(expr, loc.expr, 0)); + if((loc_matches_file_pt || loc_matches_expr) && cnd->first->string.size == 0) { - RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); - for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + if(kind == RD_CmdKind_ToggleBreakpoint) { - RD_Cfg *bp = n->v; - RD_Cfg *loc = rd_cfg_child_from_string(bp, str8_lit("location")); - S64 loc_line = 0; - U64 loc_vaddr = 0; - B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); - B32 loc_matches_string = (string.size != 0 && str8_match(loc->first->string, string, 0)); - B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); - if(loc_matches_file_pt || loc_matches_string || loc_matches_vaddr) - { - rd_cfg_release(bp); - removed_already_existing = 1; - break; - } - } - } - if(!removed_already_existing) - { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint")); - RD_Cfg *loc = rd_cfg_new(bp, str8_lit("location")); - if(vaddr != 0) - { - rd_cfg_newf(loc, "0x%I64x", vaddr); - } - else if(string.size != 0) - { - rd_cfg_new(loc, string); - } - else if(file_path.size != 0) - { - RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); - rd_cfg_newf(file_path_cfg, "%I64d", pt.line); + rd_cfg_release(bp); } + already_exists = 1; + break; } } - B32 removed_already_existing = 0; - if(kind == RD_CmdKind_ToggleBreakpoint) + if(!already_exists) { - RD_EntityList bps = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - for(RD_EntityNode *n = bps.first; n != 0; n = n->next) + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *bp = rd_cfg_new(project, str8_lit("breakpoint")); + rd_cmd(RD_CmdKind_RelocateCfg, .cfg = bp->id); + if(rd_regs()->do_lister) { - RD_Entity *bp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(bp, RD_EntityKind_Location); - if((loc->flags & RD_EntityFlag_HasTextPoint && path_match_normalized(loc->string, file_path) && loc->text_point.line == pt.line) || - (loc->flags & RD_EntityFlag_HasVAddr && loc->vaddr == vaddr) || - (!(loc->flags & RD_EntityFlag_HasTextPoint) && str8_match(loc->string, string, 0))) - { - rd_entity_mark_for_deletion(bp); - removed_already_existing = 1; - break; - } - } - } - if(!removed_already_existing) - { - RD_Entity *bp = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Breakpoint); - rd_entity_equip_cfg_src(bp, RD_CfgSrc_Project); - RD_Entity *loc = rd_entity_alloc(bp, RD_EntityKind_Location); - if(vaddr != 0) - { - rd_entity_equip_vaddr(loc, vaddr); - } - else if(string.size != 0) - { - rd_entity_equip_name(loc, string); - } - else if(file_path.size != 0 && pt.line != 0) - { - rd_entity_equip_name(loc, file_path); - rd_entity_equip_txt_pt(loc, pt); + rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x", bp->id), .do_lister = 0); } } } }break; case RD_CmdKind_AddAddressBreakpoint: { - rd_cmd(RD_CmdKind_AddBreakpoint, .string = str8_zero()); + rd_cmd(RD_CmdKind_AddBreakpoint, .file_path = str8_zero(), .do_lister = 1); }break; case RD_CmdKind_AddFunctionBreakpoint: { - rd_cmd(RD_CmdKind_AddBreakpoint, .vaddr = 0); + rd_cmd(RD_CmdKind_AddBreakpoint, .file_path = str8_zero(), .expr = rd_regs()->string); + }break; + case RD_CmdKind_ClearBreakpoints: + { + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) + { + rd_cfg_release(n->v); + } }break; //- rjf: watch pins @@ -15602,82 +15306,141 @@ rd_frame(void) { String8 file_path = rd_regs()->file_path; TxtPt pt = rd_regs()->cursor; - String8 string = rd_regs()->string; + String8 expr_string = rd_regs()->expr; U64 vaddr = rd_regs()->vaddr; - //- TODO(rjf): @cfg add/toggle watch pin - { - B32 removed_already_existing = 0; - if(kind == RD_CmdKind_ToggleWatchPin) - { - RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); - for(RD_CfgNode *n = wps.first; n != 0; n = n->next) - { - RD_Cfg *wp = n->v; - RD_Cfg *name = rd_cfg_child_from_string(wp, str8_lit("name")); - RD_Cfg *loc = rd_cfg_child_from_string(wp, str8_lit("location")); - S64 loc_line = 0; - U64 loc_vaddr = 0; - B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc->first->string, file_path) && try_s64_from_str8_c_rules(loc->first->first->string, &loc_line) && loc_line == pt.line); - B32 loc_matches_vaddr = (vaddr != 0 && try_u64_from_str8_c_rules(loc->first->string, &loc_vaddr) && loc_vaddr == vaddr); - B32 loc_matches_expr = (string.size != 0 && str8_match(name->first->string, string, 0)); - if(loc_matches_expr && (loc_matches_file_pt || loc_matches_vaddr)) - { - rd_cfg_release(wp); - removed_already_existing = 1; - break; - } - } - } - if(!removed_already_existing) - { - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin")); - RD_Cfg *name = rd_cfg_new(wp, str8_lit("name")); - RD_Cfg *loc = rd_cfg_new(wp, str8_lit("location")); - rd_cfg_new(name, string); - if(vaddr != 0) - { - rd_cfg_newf(loc, "0x%I64x", vaddr); - } - else if(file_path.size != 0) - { - RD_Cfg *file_path_cfg = rd_cfg_new(loc, file_path); - rd_cfg_newf(file_path_cfg, "%I64d", pt.line); - } - } - } B32 removed_already_existing = 0; if(kind == RD_CmdKind_ToggleWatchPin) { - RD_EntityList wps = rd_query_cached_entity_list_with_kind(RD_EntityKind_WatchPin); - for(RD_EntityNode *n = wps.first; n != 0; n = n->next) + RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(RD_CfgNode *n = wps.first; n != 0; n = n->next) { - RD_Entity *wp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(wp, RD_EntityKind_Location); - if(str8_match(wp->string, string, 0) && - ((loc->flags & RD_EntityFlag_HasTextPoint && path_match_normalized(loc->string, file_path) && loc->text_point.line == pt.line) || - (loc->flags & RD_EntityFlag_HasVAddr && loc->vaddr == vaddr))) + RD_Cfg *wp = n->v; + RD_Cfg *expr = rd_cfg_child_from_string(wp, str8_lit("expression")); + RD_Location loc = rd_location_from_cfg(wp); + B32 loc_matches_file_pt = (file_path.size != 0 && path_match_normalized(loc.file_path, file_path) && loc.pt.line == pt.line); + B32 loc_matches_expr = (expr_string.size != 0 && str8_match(expr_string, loc.expr, 0)); + if((loc_matches_file_pt || loc_matches_expr) && str8_match(expr->first->string, expr_string, 0)) { - rd_entity_mark_for_deletion(wp); + rd_cfg_release(wp); removed_already_existing = 1; - break; } } } if(!removed_already_existing) { - RD_Entity *wp = rd_entity_alloc(rd_entity_root(), RD_EntityKind_WatchPin); - rd_entity_equip_name(wp, string); - rd_entity_equip_cfg_src(wp, RD_CfgSrc_Project); - RD_Entity *loc = rd_entity_alloc(wp, RD_EntityKind_Location); - if(file_path.size != 0 && pt.line != 0) + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *wp = rd_cfg_new(project, str8_lit("watch_pin")); + RD_Cfg *expr = rd_cfg_new(wp, str8_lit("expression")); + rd_cfg_new(expr, expr_string); + rd_cmd(RD_CmdKind_RelocateCfg, .cfg = wp->id, .expr = str8_zero()); + } + }break; + + //- rjf: type views + case RD_CmdKind_AddTypeView: + { + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + rd_cfg_new(project, str8_lit("type_view")); + }break; + + //- rjf: file path maps + case RD_CmdKind_AddFilePathMap: + { + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + rd_cfg_new(project, str8_lit("file_path_map")); + }break; + + //- rjf: themes + case RD_CmdKind_EditUserTheme: + { + RD_Cfg *parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("user")); + rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x.theme_colors", parent->id)); + }break; + case RD_CmdKind_EditProjectTheme: + { + RD_Cfg *parent = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x.theme_colors", parent->id)); + }break; + case RD_CmdKind_AddThemeColor: + { + HS_Scope *hs_scope = hs_scope_open(); + RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); + RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme->first->string); + if(theme_tree == &md_nil_node) + { + rd_cfg_new_replace(theme, rd_theme_preset_display_string_table[RD_ThemePreset_DefaultDark]); + } + RD_Cfg *color = rd_cfg_new(parent, str8_lit("theme_color")); + rd_cfg_new(color, str8_lit("tags")); + RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); + rd_cfg_new(value, str8_lit("0xffffffff")); + hs_scope_close(hs_scope); + }break; + case RD_CmdKind_ForkTheme: + { + HS_Scope *hs_scope = hs_scope_open(); + RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); + RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); + for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + { + rd_cfg_release(n->v); + } + RD_Cfg *theme_cfg = rd_cfg_child_from_string(parent, str8_lit("theme")); + String8 theme_name = theme_cfg->first->string; + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, theme_name); + if(theme_tree == &md_nil_node) + { + theme_tree = rd_state->theme_preset_trees[RD_ThemePreset_DefaultDark]; + } + for(MD_Node *n = theme_tree; !md_node_is_nil(n); n = md_node_rec_depth_first_pre(n, theme_tree).next) + { + if(str8_match(n->string, str8_lit("theme_color"), 0)) { - rd_entity_equip_name(loc, file_path); - rd_entity_equip_txt_pt(loc, pt); + RD_Cfg *color = rd_cfg_new(parent, str8_lit("theme_color")); + RD_Cfg *tags = rd_cfg_new(color, str8_lit("tags")); + RD_Cfg *value = rd_cfg_new(color, str8_lit("value")); + rd_cfg_new(tags, md_child_from_string(n, str8_lit("tags"), 0)->first->string); + rd_cfg_new(value, md_child_from_string(n, str8_lit("value"), 0)->first->string); } - else if(vaddr != 0) + } + rd_cfg_release(theme_cfg); + hs_scope_close(hs_scope); + }break; + case RD_CmdKind_SaveTheme: + case RD_CmdKind_SaveAndSetTheme: + { + String8 name = rd_regs()->string; + if(name.size != 0) + { + String8 themes_folder = push_str8f(scratch.arena, "%S/raddbg/themes", os_get_process_info()->user_program_data_path); + if(os_make_directory(themes_folder)) { - rd_entity_equip_vaddr(loc, vaddr); + String8 dst_path = push_str8f(scratch.arena, "%S/%S", themes_folder, name); + RD_Cfg *parent = rd_cfg_from_id(rd_regs()->cfg); + RD_CfgList colors = rd_cfg_child_list_from_string(scratch.arena, parent, str8_lit("theme_color")); + String8List strings = {0}; + for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &strings, rd_string_from_cfg_tree(scratch.arena, str8_chop_last_slash(dst_path), n->v)); + } + String8 data = str8_list_join(scratch.arena, &strings, 0); + if(os_write_data_to_file_path(dst_path, data)) + { + if(kind == RD_CmdKind_SaveAndSetTheme) + { + for(RD_CfgNode *n = colors.first; n != 0; n = n->next) + { + rd_cfg_release(n->v); + } + RD_Cfg *theme = rd_cfg_child_from_string_or_alloc(parent, str8_lit("theme")); + rd_cfg_new_replace(theme, name); + } + } + else + { + log_user_errorf("Could not successfully write to '%S'.", dst_path); + } } } }break; @@ -15686,17 +15449,68 @@ rd_frame(void) case RD_CmdKind_ToggleWatchExpression: if(rd_regs()->string.size != 0) { - RD_Entity *existing_watch = rd_entity_from_name_and_kind(rd_regs()->string, RD_EntityKind_Watch); - if(rd_entity_is_nil(existing_watch)) + // rjf: pick a watch tab from all the windows to toggle this expression within + RD_Cfg *watch_tab = &rd_nil_cfg; { - RD_Entity *watch = &rd_nil_entity; - watch = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Watch); - rd_entity_equip_cfg_src(watch, RD_CfgSrc_Project); - rd_entity_equip_name(watch, rd_regs()->string); + B32 watch_tab_has_no_label = 0; + B32 watch_tab_matches_src_window = 0; + RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(RD_CfgNode *n = windows.first; n != 0; n = n->next) + { + RD_Cfg *window = n->v; + RD_PanelTree panels = rd_panel_tree_from_cfg(scratch.arena, window); + for(RD_PanelNode *panel = panels.root; + panel != &rd_nil_panel_node; + panel = rd_panel_node_rec__depth_first_pre(panels.root, panel).next) + { + for(RD_CfgNode *tab_n = panel->tabs.first; tab_n != 0; tab_n = tab_n->next) + { + RD_Cfg *tab = tab_n->v; + RD_Cfg *label = rd_cfg_child_from_string(tab, str8_lit("label")); + if(str8_match(tab->string, str8_lit("watch"), 0) && + rd_expr_from_cfg(tab).size == 0) + { + B32 tab_has_no_label = (label->first->string.size == 0); + B32 tab_matches_src_window = (window->id == rd_regs()->window); + if(tab_has_no_label > watch_tab_has_no_label || + tab_matches_src_window > watch_tab_matches_src_window || + watch_tab == &rd_nil_cfg) + { + watch_tab = tab; + if(tab_has_no_label && tab_matches_src_window) + { + goto end_watch_tab_search; + } + } + } + } + } + } + end_watch_tab_search:; } - else + + // rjf: find the existing watch in the selected tab, if it exists + RD_Cfg *existing_watch = &rd_nil_cfg; + for(RD_Cfg *child = watch_tab->first; child != &rd_nil_cfg; child = child->next) { - rd_entity_mark_for_deletion(existing_watch); + if(str8_match(child->string, str8_lit("watch"), 0) && str8_match(child->first->string, rd_regs()->string, 0)) + { + existing_watch = child; + break; + } + } + + // rjf: if this watch exists -> delete it + if(existing_watch != &rd_nil_cfg) + { + rd_cfg_release(existing_watch); + } + + // rjf: otherwise, create it + else if(watch_tab != &rd_nil_cfg) + { + RD_Cfg *watch = rd_cfg_new(watch_tab, str8_lit("watch")); + rd_cfg_new(watch, rd_regs()->string); } }break; @@ -15707,7 +15521,7 @@ rd_frame(void) HS_Scope *hs_scope = hs_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); RD_Regs *regs = rd_regs(); - U128 text_key = regs->text_key; + HS_Key text_key = regs->text_key; TXT_LangKind lang_kind = regs->lang_kind; TxtRng range = txt_rng(regs->cursor, regs->mark); U128 hash = {0}; @@ -15730,20 +15544,9 @@ rd_frame(void) txt_scope_close(txt_scope); hs_scope_close(hs_scope); }break; - case RD_CmdKind_RunToCursor: - { - if(rd_regs()->file_path.size != 0) - { - rd_cmd(RD_CmdKind_RunToLine); - } - else - { - rd_cmd(RD_CmdKind_RunToAddress); - } - }break; case RD_CmdKind_SetNextStatement: { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); String8 file_path = rd_regs()->file_path; U64 new_rip_vaddr = rd_regs()->vaddr_range.min; if(file_path.size != 0) @@ -15751,8 +15554,8 @@ rd_frame(void) D_LineList *lines = &rd_regs()->lines; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &n->v.dbgi_key); - CTRL_Entity *module = ctrl_module_from_thread_candidates(d_state->ctrl_entity_store, thread, &modules); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { new_rip_vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); @@ -15766,37 +15569,19 @@ rd_frame(void) //- rjf: targets case RD_CmdKind_AddTarget: { - //- TODO(rjf): @cfg add new target + String8 file_path = rd_regs()->file_path; + RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); + RD_Cfg *target = rd_cfg_new(project, str8_lit("target")); + RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); + rd_cfg_new(exe, file_path); + String8 working_directory = str8_chop_last_slash(file_path); + if(working_directory.size != 0) { - String8 file_path = rd_regs()->file_path; - RD_Cfg *project = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("project")); - RD_Cfg *target = rd_cfg_new(project, str8_lit("target")); - RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); - rd_cfg_new(exe, file_path); - String8 working_directory = str8_chop_last_slash(file_path); - if(working_directory.size != 0) - { - RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); - rd_cfg_newf(wdir, "%S/", working_directory); - } - // TODO(rjf): (select target here) + RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); + rd_cfg_newf(wdir, "%S/", working_directory); } - - // rjf: build target - RD_Entity *entity = &rd_nil_entity; - entity = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target); - rd_entity_equip_disabled(entity, 1); - rd_entity_equip_cfg_src(entity, RD_CfgSrc_Project); - RD_Entity *exe = rd_entity_alloc(entity, RD_EntityKind_Executable); - rd_entity_equip_name(exe, rd_regs()->file_path); - String8 working_dir = str8_chop_last_slash(rd_regs()->file_path); - if(working_dir.size != 0) - { - String8 working_dir_path = push_str8f(scratch.arena, "%S/", working_dir); - RD_Entity *execution_path = rd_entity_alloc(entity, RD_EntityKind_WorkingDirectory); - rd_entity_equip_name(execution_path, working_dir_path); - } - rd_cmd(RD_CmdKind_SelectTarget, .entity = rd_handle_from_entity(entity)); + rd_cmd(RD_CmdKind_SelectTarget, .cfg = target->id); + rd_cmd(RD_CmdKind_PushQuery, .expr = push_str8f(scratch.arena, "query:config.$%I64x", target->id)); }break; //- rjf: jit-debugger registration @@ -15846,8 +15631,8 @@ rd_frame(void) case RD_CmdKind_OSEvent: { OS_Event *os_event = rd_regs()->os_event; - RD_Window *ws = rd_window_from_os_handle(os_event->window); - if(os_event != 0 && ws != 0) + RD_WindowState *ws = rd_window_state_from_os_handle(os_event->window); + if(os_event != 0 && ws != &rd_nil_window_state) { UI_Event ui_event = zero_struct; UI_EventKind kind = UI_EventKind_Null; @@ -15876,11 +15661,15 @@ rd_frame(void) }break; //- rjf: debug control context management operations + case RD_CmdKind_SelectEntity: + { + rd_cmd(RD_CmdKind_SelectThread, .thread = rd_regs()->ctrl_entity); + }break; case RD_CmdKind_SelectThread: { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle)); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle)); CTRL_Entity *machine = ctrl_entity_ancestor_from_kind(process, CTRL_EntityKind_Machine); rd_state->base_regs.v.unwind_count = 0; rd_state->base_regs.v.inline_depth = 0; @@ -15892,81 +15681,59 @@ rd_frame(void) }break; case RD_CmdKind_SelectUnwind: { - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_base_regs()->thread); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &base_unwind); - if(rd_regs()->unwind_count < rich_unwind.concrete_frame_count) + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); + CTRL_CallStackFrame *frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); + if(frame == 0) + { + frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, 0); + } + if(frame) { - CTRL_CallStackFrame *frame = &rich_unwind.frames[rd_regs()->unwind_count]; - U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, frame->regs); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); - rd_state->base_regs.v.module = module->handle; rd_state->base_regs.v.unwind_count = rd_regs()->unwind_count; - rd_state->base_regs.v.inline_depth = 0; - if(rd_regs()->inline_depth <= frame->inline_frame_count) - { - rd_state->base_regs.v.inline_depth = rd_regs()->inline_depth; - } + rd_state->base_regs.v.inline_depth = rd_regs()->inline_depth; } rd_cmd(RD_CmdKind_FindThread, .thread = thread->handle, .unwind_count = rd_state->base_regs.v.unwind_count, .inline_depth = rd_state->base_regs.v.inline_depth); - di_scope_close(di_scope); + ctrl_scope_close(ctrl_scope); }break; case RD_CmdKind_UpOneFrame: case RD_CmdKind_DownOneFrame: { - DI_Scope *di_scope = di_scope_open(); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_base_regs()->thread); - CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, process, &base_unwind); - U64 crnt_unwind_idx = rd_state->base_regs.v.unwind_count; - U64 crnt_inline_dpt = rd_state->base_regs.v.inline_depth; - U64 next_unwind_idx = crnt_unwind_idx; - U64 next_inline_dpt = crnt_inline_dpt; - if(crnt_unwind_idx < rich_unwind.concrete_frame_count) + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, os_now_microseconds()+10000); + CTRL_CallStackFrame *current_frame = ctrl_call_stack_frame_from_unwind_and_inline_depth(&call_stack, rd_regs()->unwind_count, rd_regs()->inline_depth); + CTRL_CallStackFrame *next_frame = current_frame; + if(current_frame != 0) switch(kind) { - CTRL_CallStackFrame *f = &rich_unwind.frames[crnt_unwind_idx]; - switch(kind) + default:{}break; + case RD_CmdKind_UpOneFrame: + if(current_frame > call_stack.frames) { - default:{}break; - case RD_CmdKind_UpOneFrame: - { - if(crnt_inline_dpt < f->inline_frame_count) - { - next_inline_dpt += 1; - } - else if(crnt_unwind_idx > 0) - { - next_unwind_idx -= 1; - next_inline_dpt = 0; - } - }break; - case RD_CmdKind_DownOneFrame: - { - if(crnt_inline_dpt > 0) - { - next_inline_dpt -= 1; - } - else if(crnt_unwind_idx < rich_unwind.concrete_frame_count) - { - next_unwind_idx += 1; - next_inline_dpt = (f+1)->inline_frame_count; - } - }break; - } + next_frame = current_frame-1; + }break; + case RD_CmdKind_DownOneFrame: + if(current_frame+1 < call_stack.frames + call_stack.frames_count) + { + next_frame = current_frame+1; + }break; } - rd_cmd(RD_CmdKind_SelectUnwind, - .unwind_count = next_unwind_idx, - .inline_depth = next_inline_dpt); - di_scope_close(di_scope); + if(next_frame != 0) + { + CTRL_CallStackFrame *next_base_frame = next_frame + next_frame->inline_depth; + rd_cmd(RD_CmdKind_SelectUnwind, + .unwind_count = next_frame->unwind_count, + .inline_depth = next_frame->inline_depth); + } + ctrl_scope_close(ctrl_scope); }break; //- rjf: meta controls case RD_CmdKind_Edit: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; evt.slot = UI_EventActionSlot_Edit; @@ -15974,7 +15741,8 @@ rd_frame(void) }break; case RD_CmdKind_Accept: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; evt.slot = UI_EventActionSlot_Accept; @@ -15982,7 +15750,8 @@ rd_frame(void) }break; case RD_CmdKind_Cancel: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Press; evt.slot = UI_EventActionSlot_Cancel; @@ -15997,7 +15766,8 @@ rd_frame(void) // case RD_CmdKind_MoveLeft: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_PickSelectSide|UI_EventFlag_ZeroDeltaOnSelect|UI_EventFlag_ExplicitDirectional; @@ -16007,7 +15777,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveRight: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_PickSelectSide|UI_EventFlag_ZeroDeltaOnSelect|UI_EventFlag_ExplicitDirectional; @@ -16017,27 +15788,30 @@ rd_frame(void) }break; case RD_CmdKind_MoveUp: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Char; evt.delta_2s32 = v2s32(+0, -1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveDown: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Char; evt.delta_2s32 = v2s32(+0, +1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveLeftSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16047,7 +15821,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16057,27 +15832,30 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Char; evt.delta_2s32 = v2s32(+0, -1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveDownSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Char; evt.delta_2s32 = v2s32(+0, +1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveLeftChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_ExplicitDirectional; @@ -16087,7 +15865,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_ExplicitDirectional; @@ -16097,63 +15876,74 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Word; evt.delta_2s32 = v2s32(+0, -1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveDownChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; - evt.flags = UI_EventFlag_ExplicitDirectional; + evt.flags = UI_EventFlag_ExplicitDirectional|UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Word; evt.delta_2s32 = v2s32(+0, +1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveUpPage: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Page; evt.delta_2s32 = v2s32(+0, -1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveDownPage: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Page; evt.delta_2s32 = v2s32(+0, +1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveUpWhole: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Whole; evt.delta_2s32 = v2s32(+0, -1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveDownWhole: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; evt.delta_unit = UI_EventDeltaUnit_Whole; evt.delta_2s32 = v2s32(+0, +1); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_MoveLeftChunkSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16163,7 +15953,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveRightChunkSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16173,7 +15964,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpChunkSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16183,7 +15975,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownChunkSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark|UI_EventFlag_ExplicitDirectional; @@ -16193,7 +15986,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpPageSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16203,7 +15997,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownPageSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16213,7 +16008,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpWholeSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16223,7 +16019,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownWholeSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16233,7 +16030,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveUpReorder: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_Reorder; @@ -16243,7 +16041,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveDownReorder: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_Reorder; @@ -16253,7 +16052,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveHome: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.delta_unit = UI_EventDeltaUnit_Line; @@ -16262,7 +16062,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveEnd: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.delta_unit = UI_EventDeltaUnit_Line; @@ -16271,7 +16072,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveHomeSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16281,7 +16083,8 @@ rd_frame(void) }break; case RD_CmdKind_MoveEndSelect: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Navigate; evt.flags = UI_EventFlag_KeepMark; @@ -16291,7 +16094,8 @@ rd_frame(void) }break; case RD_CmdKind_SelectAll: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt1 = zero_struct; evt1.kind = UI_EventKind_Navigate; evt1.delta_unit = UI_EventDeltaUnit_Whole; @@ -16306,27 +16110,30 @@ rd_frame(void) }break; case RD_CmdKind_DeleteSingle: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; - evt.flags = UI_EventFlag_Delete; + evt.flags = UI_EventFlag_Delete|UI_EventFlag_ZeroDeltaOnSelect; evt.delta_unit = UI_EventDeltaUnit_Char; evt.delta_2s32 = v2s32(+1, +0); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_DeleteChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; - evt.flags = UI_EventFlag_Delete; + evt.flags = UI_EventFlag_Delete|UI_EventFlag_ZeroDeltaOnSelect; evt.delta_unit = UI_EventDeltaUnit_Word; evt.delta_2s32 = v2s32(+1, +0); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_BackspaceSingle: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; evt.flags = UI_EventFlag_Delete|UI_EventFlag_ZeroDeltaOnSelect; @@ -16336,17 +16143,19 @@ rd_frame(void) }break; case RD_CmdKind_BackspaceChunk: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; - evt.flags = UI_EventFlag_Delete; + evt.flags = UI_EventFlag_Delete|UI_EventFlag_ZeroDeltaOnSelect; evt.delta_unit = UI_EventDeltaUnit_Word; evt.delta_2s32 = v2s32(-1, +0); ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; case RD_CmdKind_Copy: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; evt.flags = UI_EventFlag_Copy|UI_EventFlag_KeepMark; @@ -16354,7 +16163,8 @@ rd_frame(void) }break; case RD_CmdKind_Cut: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Edit; evt.flags = UI_EventFlag_Copy|UI_EventFlag_Delete; @@ -16362,7 +16172,8 @@ rd_frame(void) }break; case RD_CmdKind_Paste: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Text; evt.string = os_get_clipboard_text(scratch.arena); @@ -16370,12 +16181,37 @@ rd_frame(void) }break; case RD_CmdKind_InsertText: { - RD_Window *ws = rd_window_from_handle(rd_regs()->window); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); UI_Event evt = zero_struct; evt.kind = UI_EventKind_Text; evt.string = rd_regs()->string; ui_event_list_push(scratch.arena, &ws->ui_events, &evt); }break; + + //- rjf: directionless navigation + case RD_CmdKind_MoveNext: + { + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, +1); + ui_event_list_push(scratch.arena, &ws->ui_events, &evt); + }break; + case RD_CmdKind_MovePrev: + { + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + UI_Event evt = zero_struct; + evt.kind = UI_EventKind_Navigate; + evt.flags = UI_EventFlag_Secondary; + evt.delta_unit = UI_EventDeltaUnit_Char; + evt.delta_2s32 = v2s32(+0, -1); + ui_event_list_push(scratch.arena, &ws->ui_events, &evt); + }break; } } } @@ -16386,19 +16222,20 @@ rd_frame(void) D_TargetArray targets = {0}; ProfScope("gather targets") { - RD_EntityList target_entities = rd_query_cached_entity_list_with_kind(RD_EntityKind_Target); - targets.count = target_entities.count; + RD_CfgList target_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("target")); + targets.count = target_cfgs.count; targets.v = push_array(scratch.arena, D_Target, targets.count); U64 idx = 0; - for(RD_EntityNode *n = target_entities.first; n != 0; n = n->next) + for(RD_CfgNode *n = target_cfgs.first; n != 0; n = n->next) { - RD_Entity *src_target = n->entity; - if(src_target->disabled) + RD_Cfg *src = n->v; + B32 src_is_disabled = rd_disabled_from_cfg(src); + if(src_is_disabled) { targets.count -= 1; continue; } - targets.v[idx] = rd_d_target_from_entity(src_target); + targets.v[idx] = rd_target_from_cfg(scratch.arena, src); idx += 1; } } @@ -16407,32 +16244,23 @@ rd_frame(void) //- rjf: gather breakpoints & meta-evals (for the engine, meta-evals can only be referenced by breakpoints) // D_BreakpointArray breakpoints = {0}; - CTRL_MetaEvalArray meta_evals = {0}; ProfScope("gather breakpoints & meta-evals") { - typedef struct MetaEvalNode MetaEvalNode; - struct MetaEvalNode - { - MetaEvalNode *next; - CTRL_MetaEval *meval; - }; - U64 meval_count = 0; - MetaEvalNode *first_meval = 0; - MetaEvalNode *last_meval = 0; - RD_EntityList bp_entities = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - breakpoints.count = bp_entities.count; + RD_CfgList bp_cfgs = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + breakpoints.count = bp_cfgs.count; breakpoints.v = push_array(scratch.arena, D_Breakpoint, breakpoints.count); U64 idx = 0; - for(RD_EntityNode *n = bp_entities.first; n != 0; n = n->next) + for(RD_CfgNode *n = bp_cfgs.first; n != 0; n = n->next) { - RD_Entity *src_bp = n->entity; - if(src_bp->disabled) + RD_Cfg *src_bp = n->v; + B32 src_bp_is_disabled = rd_disabled_from_cfg(src_bp); + if(src_bp_is_disabled) { breakpoints.count -= 1; continue; } - RD_Entity *src_bp_loc = rd_entity_child_from_kind(src_bp, RD_EntityKind_Location); - RD_Entity *src_bp_cnd = rd_entity_child_from_kind(src_bp, RD_EntityKind_Condition); + RD_Location src_bp_loc = rd_location_from_cfg(src_bp); + String8 src_bp_cnd = rd_cfg_child_from_string(src_bp, str8_lit("condition"))->first->string; //- rjf: walk conditional breakpoint expression tree - for each leaf identifier, // determine if it resolves to a meta-evaluation. if it does, compute the meta @@ -16445,7 +16273,7 @@ rd_frame(void) // or not it is 'static', w.r.t. the control thread. // B32 is_static_for_ctrl_thread = 0; - if(src_bp_cnd->string.size != 0) + if(src_bp_cnd.size != 0) { typedef struct ExprWalkTask ExprWalkTask; struct ExprWalkTask @@ -16453,32 +16281,24 @@ rd_frame(void) ExprWalkTask *next; E_Expr *expr; }; - E_Expr *expr = e_parse_expr_from_text(scratch.arena, src_bp_cnd->string); + E_Expr *expr = e_parse_from_string(src_bp_cnd).expr; ExprWalkTask start_task = {0, expr}; ExprWalkTask *first_task = &start_task; for(ExprWalkTask *t = first_task; t != 0; t = t->next) { - if(t->expr->kind == E_ExprKind_LeafIdent) + if(t->expr->kind == E_ExprKind_LeafIdentifier) { - E_Expr *macro_expr = e_string2expr_lookup(e_ir_ctx->macro_map, t->expr->string); - if(macro_expr != &e_expr_nil) + E_Expr *macro_expr = e_string2expr_map_lookup(e_ir_ctx->macro_map, t->expr->string); + E_Eval eval = e_eval_from_string(t->expr->string); + if(eval.msgs.max_kind == E_MsgKind_Null) { - E_Eval eval = e_eval_from_expr(scratch.arena, macro_expr); switch(eval.space.kind) { default:{is_static_for_ctrl_thread = 0;}break; case E_SpaceKind_Null: - case RD_EvalSpaceKind_MetaEntity: + case RD_EvalSpaceKind_MetaCfg: { is_static_for_ctrl_thread = 1; - RD_Entity *entity = rd_entity_from_eval_space(eval.space); - if(!rd_entity_is_nil(entity)) - { - MetaEvalNode *meval_node = push_array(scratch.arena, MetaEvalNode, 1); - meval_node->meval = rd_ctrl_meta_eval_from_entity(scratch.arena, entity); - SLLQueuePush(first_meval, last_meval, meval_node); - meval_count += 1; - } }break; } } @@ -16497,14 +16317,16 @@ rd_frame(void) // we can evaluate this condition early, and decide whether or not to send this // breakpoint. B32 is_statically_disqualified = 0; + String8 non_ctrl_thread_static_condition = src_bp_cnd; if(is_static_for_ctrl_thread) { - E_Eval eval = e_eval_from_string(scratch.arena, src_bp_cnd->string); + E_Eval eval = e_eval_from_string(src_bp_cnd); E_Eval value_eval = e_value_eval_from_eval(eval); if(value_eval.value.u64 == 0) { is_statically_disqualified = 1; } + MemoryZeroStruct(&non_ctrl_thread_static_condition); } //- rjf: statically disqualified? -> skip @@ -16514,27 +16336,39 @@ rd_frame(void) continue; } + //- rjf: compute breakpoint flags + D_BreakpointFlags flags = 0; + if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_write"))->first->string, str8_lit("1"), 0)) + { + flags |= D_BreakpointFlag_BreakOnWrite; + } + if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_read"))->first->string, str8_lit("1"), 0)) + { + flags |= D_BreakpointFlag_BreakOnRead; + } + if(str8_match(rd_cfg_child_from_string(src_bp, str8_lit("break_on_execute"))->first->string, str8_lit("1"), 0)) + { + flags |= D_BreakpointFlag_BreakOnExecute; + } + + //- rjf: compute address range size + U64 addr_range_size = 0; + { + RD_Cfg *address_range_size_cfg = rd_cfg_child_from_string(src_bp, str8_lit("address_range_size")); + try_u64_from_str8_c_rules(address_range_size_cfg->first->string, &addr_range_size); + } + //- rjf: fill breakpoint D_Breakpoint *dst_bp = &breakpoints.v[idx]; - dst_bp->file_path = src_bp_loc->string; - dst_bp->pt = src_bp_loc->text_point; - dst_bp->symbol_name = src_bp_loc->string; - dst_bp->vaddr = src_bp_loc->vaddr; - dst_bp->condition = src_bp_cnd->string; + dst_bp->flags = flags; + dst_bp->id = src_bp->id; + dst_bp->file_path = src_bp_loc.file_path; + dst_bp->pt = src_bp_loc.pt; + dst_bp->vaddr_expr = src_bp_loc.expr; + dst_bp->condition = non_ctrl_thread_static_condition; + dst_bp->size = addr_range_size; idx += 1; } - - //- rjf: meta-eval list -> array - meta_evals.count = meval_count; - meta_evals.v = push_array(scratch.arena, CTRL_MetaEval, meta_evals.count); - { - U64 idx = 0; - for(MetaEvalNode *n = first_meval; n != 0; n = n->next) - { - MemoryCopyStruct(&meta_evals.v[idx], n->meval); - idx += 1; - } - } } //////////////////////////// @@ -16542,15 +16376,15 @@ rd_frame(void) // D_PathMapArray path_maps = {0}; { - RD_EntityList maps = rd_query_cached_entity_list_with_kind(RD_EntityKind_FilePathMap); + RD_CfgList maps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("file_path_map")); path_maps.count = maps.count; path_maps.v = push_array(scratch.arena, D_PathMap, path_maps.count); U64 idx = 0; - for(RD_EntityNode *n = maps.first; n != 0; n = n->next, idx += 1) + for(RD_CfgNode *n = maps.first; n != 0; n = n->next, idx += 1) { - RD_Entity *map = n->entity; - path_maps.v[idx].src = rd_entity_child_from_kind(map, RD_EntityKind_Source)->string; - path_maps.v[idx].dst = rd_entity_child_from_kind(map, RD_EntityKind_Dest)->string; + RD_Cfg *map = n->v; + path_maps.v[idx].src = rd_cfg_child_from_string(map, str8_lit("source"))->first->string; + path_maps.v[idx].dst = rd_cfg_child_from_string(map, str8_lit("dest"))->first->string; } } @@ -16559,14 +16393,22 @@ rd_frame(void) // U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64] = {0}; { - MemoryCopyArray(exception_code_filters, rd_state->ctrl_exception_code_filters); + for EachNonZeroEnumVal(CTRL_ExceptionCodeKind, k) + { + String8 name = ctrl_exception_code_kind_lowercase_code_string_table[k]; + B32 setting = rd_setting_b32_from_name(name); + if(setting) + { + exception_code_filters[k/64] |= 1ull<<(k%64); + } + } } //////////////////////////// //- rjf: tick debug engine // U64 cmd_count_pre_tick = rd_state->cmds[0].count; - D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, exception_code_filters, &meta_evals); + D_EventList engine_events = d_tick(scratch.arena, &targets, &breakpoints, &path_maps, exception_code_filters); //////////////////////////// //- rjf: process debug engine events @@ -16580,7 +16422,7 @@ rd_frame(void) case D_EventKind_ProcessEnd: if(rd_state->quit_after_success) { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); if(evt->code == 0 && processes.count == 0) { rd_cmd(RD_CmdKind_Exit); @@ -16593,13 +16435,13 @@ rd_frame(void) case D_EventKind_Stop: { B32 need_refocus = (evt->cause != D_EventCause_SoftHalt); - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, evt->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, evt->thread); U64 vaddr = evt->vaddr; CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 voff = ctrl_voff_from_vaddr(module, vaddr); - U64 test_cached_vaddr = ctrl_query_cached_rip_from_thread(d_state->ctrl_entity_store, thread->handle); + U64 test_cached_vaddr = ctrl_rip_from_thread(&d_state->ctrl_entity_store->ctx, thread->handle); // rjf: valid stop thread? -> select & snap if(need_refocus && thread != &ctrl_entity_nil && evt->cause != D_EventCause_Halt) @@ -16608,7 +16450,7 @@ rd_frame(void) } // rjf: no stop-causing thread, but have selected thread? -> snap to selected - CTRL_Entity *selected_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_base_regs()->thread); + CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_base_regs()->thread); if(need_refocus && (evt->cause == D_EventCause_Halt || thread == &ctrl_entity_nil) && selected_thread != &ctrl_entity_nil) { rd_cmd(RD_CmdKind_SelectThread, .thread = selected_thread->handle); @@ -16617,43 +16459,22 @@ rd_frame(void) // rjf: no stop-causing thread, but don't have selected thread? -> snap to first available thread if(need_refocus && thread == &ctrl_entity_nil && selected_thread == &ctrl_entity_nil) { - CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread); - CTRL_Entity *first_available_thread = ctrl_entity_list_first(&threads); + CTRL_EntityArray threads = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Thread); + CTRL_Entity *first_available_thread = ctrl_entity_array_first(&threads); rd_cmd(RD_CmdKind_SelectThread, .thread = first_available_thread->handle); } // rjf: increment breakpoint hit counts if(evt->cause == D_EventCause_UserBreakpoint) { - RD_EntityList user_bps = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - for(RD_EntityNode *n = user_bps.first; n != 0; n = n->next) + RD_Cfg *bp = rd_cfg_from_id(evt->id); + if(bp != &rd_nil_cfg) { - RD_Entity *bp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(bp, RD_EntityKind_Location); - D_LineList loc_lines = d_lines_from_file_path_line_num(scratch.arena, loc->string, loc->text_point.line); - if(loc_lines.first != 0) - { - for(D_LineNode *n = loc_lines.first; n != 0; n = n->next) - { - if(contains_1u64(n->v.voff_range, voff)) - { - bp->u64 += 1; - break; - } - } - } - else if(loc->flags & RD_EntityFlag_HasVAddr && vaddr == loc->vaddr) - { - bp->u64 += 1; - } - else if(loc->string.size != 0) - { - U64 symb_voff = d_voff_from_dbgi_key_symbol_name(&dbgi_key, loc->string); - if(symb_voff == voff) - { - bp->u64 += 1; - } - } + RD_Cfg *hit_count_root = rd_cfg_child_from_string_or_alloc(bp, str8_lit("hit_count")); + U64 hit_count = 0; + try_u64_from_str8_c_rules(hit_count_root->first->string, &hit_count); + hit_count += 1; + rd_cfg_new_replacef(hit_count_root, "%I64u", hit_count); } } @@ -16661,9 +16482,9 @@ rd_frame(void) if(need_refocus && (selected_thread != &ctrl_entity_nil || thread != &ctrl_entity_nil)) { B32 any_window_is_focused = 0; - for(RD_Window *window = rd_state->first_window; window != 0; window = window->next) + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) { - if(os_window_is_focused(window->os)) + if(os_window_is_focused(ws->os)) { any_window_is_focused = 1; break; @@ -16671,16 +16492,17 @@ rd_frame(void) } if(!any_window_is_focused) { - RD_Window *window = rd_window_from_handle(rd_state->last_focused_window); - if(window == 0) + RD_Cfg *last_focused_window = rd_cfg_from_id(rd_state->last_focused_window); + RD_WindowState *ws = rd_window_state_from_cfg(last_focused_window); + if(ws == &rd_nil_window_state) { - window = rd_state->first_window; + ws = rd_state->first_window_state; } - if(window != 0) + if(ws != &rd_nil_window_state) { - os_window_set_minimized(window->os, 0); - os_window_bring_to_front(window->os); - os_window_focus(window->os); + os_window_set_minimized(ws->os, 0); + os_window_bring_to_front(ws->os); + os_window_focus(ws->os); } } } @@ -16705,65 +16527,6 @@ rd_frame(void) rd_cmd(RD_CmdKind_FindThread, .thread = find_thread_retry); } - ////////////////////////////// - //- rjf: animate confirmation - // - { - F32 rate = rd_setting_val_from_code(RD_SettingCode_MenuAnimations).s32 ? 1 - pow_f32(2, (-10.f * rd_state->frame_dt)) : 1.f; - B32 popup_open = rd_state->popup_active; - rd_state->popup_t += rate * ((F32)!!popup_open-rd_state->popup_t); - if(abs_f32(rd_state->popup_t - (F32)!!popup_open) > 0.005f) - { - rd_request_frame(); - } - } - - ////////////////////////////// - //- rjf: animate theme - // - { - RD_Theme *current = &rd_state->cfg_theme; - RD_Theme *target = &rd_state->cfg_theme_target; - F32 rate = 1 - pow_f32(2, (-50.f * rd_state->frame_dt)); - for(RD_ThemeColor color = RD_ThemeColor_Null; - color < RD_ThemeColor_COUNT; - color = (RD_ThemeColor)(color+1)) - { - if(abs_f32(target->colors[color].x - current->colors[color].x) > 0.01f || - abs_f32(target->colors[color].y - current->colors[color].y) > 0.01f || - abs_f32(target->colors[color].z - current->colors[color].z) > 0.01f || - abs_f32(target->colors[color].w - current->colors[color].w) > 0.01f) - { - rd_request_frame(); - } - current->colors[color].x += (target->colors[color].x - current->colors[color].x) * rate; - current->colors[color].y += (target->colors[color].y - current->colors[color].y) * rate; - current->colors[color].z += (target->colors[color].z - current->colors[color].z) * rate; - current->colors[color].w += (target->colors[color].w - current->colors[color].w) * rate; - } - } - - ////////////////////////////// - //- rjf: capture is active? -> keep rendering - // - if(ProfIsCapturing()) - { - // rd_request_frame(); - } - - ////////////////////////////// - //- rjf: commit params changes for all views - // - { - for(RD_View *v = rd_state->first_view; !rd_view_is_nil(v); v = v->alloc_next) - { - if(v->params_write_gen == v->params_read_gen+1) - { - v->params_read_gen += 1; - } - } - } - //////////////////////////// //- rjf: rotate command slots, bump command gen counter // @@ -16784,7 +16547,7 @@ rd_frame(void) // the commands pushed by the view will be in the queue, and the core can // treat that queue as r/w again. // - if(depth == 0) + if(rd_state->frame_depth == 1) { // rjf: rotate { @@ -16820,41 +16583,47 @@ rd_frame(void) Temp scratch = scratch_begin(0, 0); rd_state->ambiguous_path_slots_count = 512; rd_state->ambiguous_path_slots = push_array(rd_frame_arena(), RD_AmbiguousPathNode *, rd_state->ambiguous_path_slots_count); - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) { - for(RD_Panel *p = w->root_panel; !rd_panel_is_nil(p); p = rd_panel_rec_depth_first_pre(p).next) + RD_Cfg *window = rd_cfg_from_id(ws->cfg_id); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, window); + for(RD_PanelNode *p = panel_tree.root; p != &rd_nil_panel_node; p = rd_panel_node_rec__depth_first_pre(panel_tree.root, p).next) { - for(RD_View *v = p->first_tab_view; !rd_view_is_nil(v); v = v->order_next) + for(RD_CfgNode *tab_n = p->tabs.first; tab_n != 0; tab_n = tab_n->next) { - if(rd_view_is_project_filtered(v)) + RD_Cfg *tab = tab_n->v; + if(rd_cfg_is_project_filtered(tab)) { continue; } - String8 eval_string = str8(v->query_buffer, v->query_string_size); - String8 file_path = rd_file_path_from_eval_string(scratch.arena, eval_string); - if(file_path.size != 0) + RD_RegsScope(.tab = tab->id, .view = tab->id) { - String8 name = str8_skip_last_slash(file_path); - U64 hash = d_hash_from_string__case_insensitive(name); - U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; - RD_AmbiguousPathNode *node = 0; - for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; - n != 0; - n = n->next) + String8 eval_string = rd_expr_from_cfg(tab); + String8 file_path = rd_file_path_from_eval_string(scratch.arena, eval_string); + if(file_path.size != 0) { - if(str8_match(n->name, name, StringMatchFlag_CaseInsensitive)) + String8 name = str8_skip_last_slash(file_path); + U64 hash = d_hash_from_string__case_insensitive(name); + U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; + RD_AmbiguousPathNode *node = 0; + for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; + n != 0; + n = n->next) { - node = n; - break; + if(str8_match(n->name, name, StringMatchFlag_CaseInsensitive)) + { + node = n; + break; + } } + if(node == 0) + { + node = push_array(rd_frame_arena(), RD_AmbiguousPathNode, 1); + SLLStackPush(rd_state->ambiguous_path_slots[slot_idx], node); + node->name = push_str8_copy(rd_frame_arena(), name); + } + str8_list_push(rd_frame_arena(), &node->paths, push_str8_copy(rd_frame_arena(), file_path)); } - if(node == 0) - { - node = push_array(rd_frame_arena(), RD_AmbiguousPathNode, 1); - SLLStackPush(rd_state->ambiguous_path_slots[slot_idx], node); - node->name = push_str8_copy(rd_frame_arena(), name); - } - str8_list_push(rd_frame_arena(), &node->paths, push_str8_copy(rd_frame_arena(), file_path)); } } } @@ -16871,30 +16640,91 @@ rd_frame(void) di_match_store_begin(rd_state->match_store, keys); } + ////////////////////////////// + //- rjf: compute animation rates, given config + // + { + F32 master_animations_f = (F32)!!rd_setting_b32_from_name(str8_lit("animations")); + F32 scrolling_animations_f = (F32)!!rd_setting_b32_from_name(str8_lit("scrolling_animations")); + F32 tooltip_animations_f = (F32)!!rd_setting_b32_from_name(str8_lit("tooltip_animations")); + F32 menu_animations_f = (F32)!!rd_setting_b32_from_name(str8_lit("menu_animations")); + rd_state->catchall_animation_rate = 1 - master_animations_f*pow_f32(2, (-60.f * rd_state->frame_dt)); + rd_state->menu_animation_rate = 1 - master_animations_f*menu_animations_f*pow_f32(2, (-70.f * rd_state->frame_dt)); + rd_state->menu_animation_rate__slow = 1 - master_animations_f*menu_animations_f*pow_f32(2, (-50.f * rd_state->frame_dt)); + rd_state->entity_alive_animation_rate = 1 - master_animations_f*menu_animations_f*pow_f32(2, (-30.f * rd_state->frame_dt)); + rd_state->rich_hover_animation_rate = 1 - master_animations_f*menu_animations_f*pow_f32(2, (-50.f * rd_state->frame_dt)); + rd_state->scrolling_animation_rate = 1 - master_animations_f*scrolling_animations_f*pow_f32(2, (-60.f * rd_state->frame_dt)); + rd_state->tooltip_animation_rate = 1 - master_animations_f*tooltip_animations_f*pow_f32(2, (-60.f * rd_state->frame_dt)); + } + + ////////////////////////////// + //- rjf: animate confirmation + // + { + F32 rate = rd_setting_b32_from_name(str8_lit("menu_animations")) ? 1 - pow_f32(2, (-30.f * rd_state->frame_dt)) : 1.f; + B32 popup_open = rd_state->popup_active; + rd_state->popup_t += rate * ((F32)!!popup_open-rd_state->popup_t); + if(abs_f32(rd_state->popup_t - (F32)!!popup_open) > 0.005f) + { + rd_request_frame(); + } + } + ////////////////////////////// //- rjf: update/render all windows // { - dr_begin_frame(); - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + dr_begin_frame(rd_font_from_slot(RD_FontSlot_Icons)); + RD_CfgList windows = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("window")); + for(RD_CfgNode *n = windows.first; n != 0; n = n->next) { + RD_Cfg *window = n->v; + RD_WindowState *w = rd_window_state_from_cfg(window); B32 window_is_focused = os_window_is_focused(w->os); if(window_is_focused) { - rd_state->last_focused_window = rd_handle_from_window(w); + rd_state->last_focused_window = w->cfg_id; } rd_push_regs(); - rd_regs()->window = rd_handle_from_window(w); - rd_window_frame(w); + rd_regs()->window = w->cfg_id; + rd_window_frame(); MemoryZeroStruct(&w->ui_events); RD_Regs *window_regs = rd_pop_regs(); - if(rd_window_from_handle(rd_state->last_focused_window) == w) + if(rd_state->last_focused_window == w->cfg_id) { MemoryCopyStruct(rd_regs(), window_regs); } } } + ////////////////////////////// + //- rjf: garbage collect untouched window states + // + { + for EachIndex(slot_idx, rd_state->window_state_slots_count) + { + for(RD_WindowState *ws = rd_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next) + { + next = ws->hash_next; + RD_Cfg *cfg = rd_cfg_from_id(ws->cfg_id); + if(cfg == &rd_nil_cfg || ws->last_frame_index_touched < rd_state->frame_index) + { + ui_state_release(ws->ui); + r_window_unequip(ws->os, ws->r); + os_window_close(ws->os); + arena_release(ws->drop_completion_arena); + arena_release(ws->query_arena); + arena_release(ws->hover_eval_arena); + arena_release(ws->autocomp_arena); + arena_release(ws->arena); + DLLRemove_NPZ(&rd_nil_window_state, rd_state->first_window_state, rd_state->last_window_state, ws, order_next, order_prev); + DLLRemove_NP(rd_state->window_state_slots[slot_idx].first, rd_state->window_state_slots[slot_idx].last, ws, hash_next, hash_prev); + SLLStackPush_N(rd_state->free_window_state, ws, order_next); + } + } + } + } + ////////////////////////////// //- rjf: simulate lag // @@ -16919,21 +16749,13 @@ rd_frame(void) rd_state->num_frames_requested -= 1; } - ////////////////////////////// - //- rjf: close scopes - // - if(depth == 0) - { - di_scope_close(rd_state->frame_di_scope); - } - ////////////////////////////// //- rjf: submit rendering to all windows // ProfScope("submit rendering to all windows") { r_begin_frame(); - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) { r_window_begin_frame(w->os, w->r); dr_submit_bucket(w->os, w->r, w->draw_bucket); @@ -16945,48 +16767,21 @@ rd_frame(void) ////////////////////////////// //- rjf: show windows after first frame // - if(depth == 0) + if(rd_state->frame_depth == 1) { - RD_HandleList windows_to_show = {0}; - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + RD_CfgIDList windows_to_show = {0}; + for(RD_WindowState *w = rd_state->first_window_state; w != &rd_nil_window_state; w = w->order_next) { if(w->frames_alive == 1) { - rd_handle_list_push(scratch.arena, &windows_to_show, rd_handle_from_window(w)); + rd_cfg_id_list_push(scratch.arena, &windows_to_show, w->cfg_id); } } - for(RD_HandleNode *n = windows_to_show.first; n != 0; n = n->next) + for(RD_CfgIDNode *n = windows_to_show.first; n != 0; n = n->next) { - RD_Window *window = rd_window_from_handle(n->handle); - DeferLoop(depth += 1, depth -= 1) os_window_first_paint(window->os); - } - } - - ////////////////////////////// - //- rjf: eliminate entities that are marked for deletion - // - ProfScope("eliminate deleted entities") - { - for(RD_Entity *entity = rd_entity_root(), *next = 0; !rd_entity_is_nil(entity); entity = next) - { - next = rd_entity_rec_depth_first_pre(entity, &rd_nil_entity).next; - if(entity->flags & RD_EntityFlag_MarkedForDeletion) - { - B32 undoable = (rd_entity_kind_flags_table[entity->kind] & RD_EntityKindFlag_UserDefinedLifetime); - - // rjf: fixup next entity to iterate to - next = rd_entity_rec_depth_first(entity, &rd_nil_entity, OffsetOf(RD_Entity, next), OffsetOf(RD_Entity, next)).next; - - // rjf: eliminate root entity if we're freeing it - if(entity == rd_state->entities_root) - { - rd_state->entities_root = &rd_nil_entity; - } - - // rjf: unhook & release this entity tree - rd_entity_change_parent(entity, entity->parent, &rd_nil_entity, &rd_nil_entity); - rd_entity_release(entity); - } + RD_Cfg *window = rd_cfg_from_id(n->v); + RD_WindowState *ws = rd_window_state_from_cfg(window); + os_window_first_paint(ws->os); } } @@ -17002,11 +16797,12 @@ rd_frame(void) // rd_state->frame_index += 1; rd_state->time_in_seconds += rd_state->frame_dt; + rd_state->time_in_us += frame_time_us; ////////////////////////////// //- rjf: bump command batch ring buffer generation // - if(depth == 0) + if(rd_state->frame_depth == 1) { rd_state->cmds_gen += 1; } @@ -17020,15 +16816,26 @@ rd_frame(void) os_append_data_to_file_path(rd_state->log_path, log.strings[LogMsgKind_Info]); if(log.strings[LogMsgKind_UserError].size != 0) { - for(RD_Window *w = rd_state->first_window; w != 0; w = w->next) + for(RD_WindowState *ws = rd_state->first_window_state; ws != &rd_nil_window_state; ws = ws->order_next) { - w->error_string_size = Min(sizeof(w->error_buffer), log.strings[LogMsgKind_UserError].size); - MemoryCopy(w->error_buffer, log.strings[LogMsgKind_UserError].str, w->error_string_size); - w->error_t = 1.f; + ws->error_string_size = Min(sizeof(ws->error_buffer), log.strings[LogMsgKind_UserError].size); + MemoryCopy(ws->error_buffer, log.strings[LogMsgKind_UserError].str, ws->error_string_size); + ws->error_t = 1.f; } } } + ////////////////////////////// + //- rjf: [windows] clear pages from working set shortly after startup, many of which will not be needed + // +#if OS_WINDOWS + if(rd_state->frame_index == 10) + { + SetProcessWorkingSetSize(GetCurrentProcess(), max_U64, max_U64); + } +#endif + + rd_state->frame_depth -= 1; scratch_end(scratch); ProfEnd(); } diff --git a/src/raddbg/raddbg_core.h b/src/raddbg/raddbg_core.h index 196a6328..6468fbc6 100644 --- a/src/raddbg/raddbg_core.h +++ b/src/raddbg/raddbg_core.h @@ -5,87 +5,27 @@ #define RADDBG_CORE_H //////////////////////////////// -//~ rjf: Handles +//~ rjf: Config IDs -typedef struct RD_Handle RD_Handle; -struct RD_Handle +typedef U64 RD_CfgID; + +typedef struct RD_CfgIDNode RD_CfgIDNode; +struct RD_CfgIDNode { - U64 u64[2]; + RD_CfgIDNode *next; + RD_CfgID v; }; -typedef struct RD_HandleNode RD_HandleNode; -struct RD_HandleNode +typedef struct RD_CfgIDList RD_CfgIDList; +struct RD_CfgIDList { - RD_HandleNode *next; - RD_HandleNode *prev; - RD_Handle handle; -}; - -typedef struct RD_HandleList RD_HandleList; -struct RD_HandleList -{ - RD_HandleNode *first; - RD_HandleNode *last; + RD_CfgIDNode *first; + RD_CfgIDNode *last; U64 count; }; //////////////////////////////// -//~ rjf: Evaluation Spaces - -typedef U64 RD_EvalSpaceKind; -enum -{ - RD_EvalSpaceKind_CtrlEntity = E_SpaceKind_FirstUserDefined, - RD_EvalSpaceKind_MetaEntity, - RD_EvalSpaceKind_MetaCtrlEntity, - RD_EvalSpaceKind_MetaCollection, -}; - -//////////////////////////////// -//~ rjf: Entity Kind Flags - -typedef U32 RD_EntityKindFlags; -enum -{ - //- rjf: allowed operations - RD_EntityKindFlag_CanDelete = (1<<0), - RD_EntityKindFlag_CanFreeze = (1<<1), - RD_EntityKindFlag_CanEdit = (1<<2), - RD_EntityKindFlag_CanRename = (1<<3), - RD_EntityKindFlag_CanEnable = (1<<4), - RD_EntityKindFlag_CanCondition = (1<<5), - RD_EntityKindFlag_CanDuplicate = (1<<6), - - //- rjf: name categorization - RD_EntityKindFlag_NameIsCode = (1<<7), - RD_EntityKindFlag_NameIsPath = (1<<8), - - //- rjf: lifetime categorization - RD_EntityKindFlag_UserDefinedLifetime = (1<<9), - - //- rjf: serialization - RD_EntityKindFlag_IsSerializedToConfig = (1<<10), -}; - -//////////////////////////////// -//~ rjf: Entity Flags - -typedef U32 RD_EntityFlags; -enum -{ - //- rjf: allocationless, simple equipment - RD_EntityFlag_HasTextPoint = (1<<0), - RD_EntityFlag_HasEntityHandle = (1<<2), - RD_EntityFlag_HasU64 = (1<<4), - RD_EntityFlag_HasColor = (1<<6), - RD_EntityFlag_HasVAddr = (1<<15), - - //- rjf: deletion - RD_EntityFlag_MarkedForDeletion = (1<<31), -}; - -//////////////////////////////// -//~ rjf: Binding Types +//~ rjf: Key Bindings typedef struct RD_Binding RD_Binding; struct RD_Binding @@ -94,40 +34,31 @@ struct RD_Binding OS_Modifiers modifiers; }; -typedef struct RD_BindingNode RD_BindingNode; -struct RD_BindingNode -{ - RD_BindingNode *next; - RD_Binding binding; -}; - -typedef struct RD_BindingList RD_BindingList; -struct RD_BindingList -{ - RD_BindingNode *first; - RD_BindingNode *last; - U64 count; -}; - -typedef struct RD_StringBindingPair RD_StringBindingPair; -struct RD_StringBindingPair -{ - String8 string; - RD_Binding binding; -}; - -//////////////////////////////// -//~ rjf: Key Map Types - typedef struct RD_KeyMapNode RD_KeyMapNode; struct RD_KeyMapNode { - RD_KeyMapNode *hash_next; - RD_KeyMapNode *hash_prev; + RD_KeyMapNode *name_hash_next; + RD_KeyMapNode *binding_hash_next; + RD_CfgID cfg_id; String8 name; RD_Binding binding; }; +typedef struct RD_KeyMapNodePtr RD_KeyMapNodePtr; +struct RD_KeyMapNodePtr +{ + RD_KeyMapNodePtr *next; + RD_KeyMapNode *v; +}; + +typedef struct RD_KeyMapNodePtrList RD_KeyMapNodePtrList; +struct RD_KeyMapNodePtrList +{ + RD_KeyMapNodePtr *first; + RD_KeyMapNodePtr *last; + U64 count; +}; + typedef struct RD_KeyMapSlot RD_KeyMapSlot; struct RD_KeyMapSlot { @@ -135,169 +66,64 @@ struct RD_KeyMapSlot RD_KeyMapNode *last; }; -//////////////////////////////// -//~ rjf: Setting Types - -typedef struct RD_SettingVal RD_SettingVal; -struct RD_SettingVal +typedef struct RD_KeyMap RD_KeyMap; +struct RD_KeyMap { - B32 set; - S32 s32; + U64 name_slots_count; + RD_KeyMapSlot *name_slots; + U64 binding_slots_count; + RD_KeyMapSlot *binding_slots; }; //////////////////////////////// -//~ rjf: View Rule Info Types +//~ rjf: Evaluation Spaces -typedef U32 RD_ViewRuleInfoFlags; +typedef U64 RD_EvalSpaceKind; enum { - RD_ViewRuleInfoFlag_ShowInDocs = (1<<0), - RD_ViewRuleInfoFlag_CanFilter = (1<<1), - RD_ViewRuleInfoFlag_FilterIsCode = (1<<2), - RD_ViewRuleInfoFlag_TypingAutomaticallyFilters = (1<<3), - RD_ViewRuleInfoFlag_CanUseInWatchTable = (1<<4), - RD_ViewRuleInfoFlag_CanFillValueCell = (1<<5), - RD_ViewRuleInfoFlag_CanExpand = (1<<6), - RD_ViewRuleInfoFlag_ProjectFiltered = (1<<7), -}; - -#define RD_VIEW_RULE_UI_FUNCTION_SIG(name) void name(String8 string, MD_Node *params, Rng2F32 rect) -#define RD_VIEW_RULE_UI_FUNCTION_NAME(name) rd_view_rule_ui_##name -#define RD_VIEW_RULE_UI_FUNCTION_DEF(name) internal RD_VIEW_RULE_UI_FUNCTION_SIG(RD_VIEW_RULE_UI_FUNCTION_NAME(name)) -typedef RD_VIEW_RULE_UI_FUNCTION_SIG(RD_ViewRuleUIFunctionType); - -//////////////////////////////// -//~ rjf: View Types - -typedef struct RD_View RD_View; - -typedef struct RD_ArenaExt RD_ArenaExt; -struct RD_ArenaExt -{ - RD_ArenaExt *next; - Arena *arena; -}; - -typedef struct RD_TransientViewNode RD_TransientViewNode; -struct RD_TransientViewNode -{ - RD_TransientViewNode *next; - RD_TransientViewNode *prev; - EV_Key key; - RD_View *view; - Arena *initial_params_arena; - MD_Node *initial_params; - U64 first_frame_index_touched; - U64 last_frame_index_touched; -}; - -typedef struct RD_TransientViewSlot RD_TransientViewSlot; -struct RD_TransientViewSlot -{ - RD_TransientViewNode *first; - RD_TransientViewNode *last; -}; - -typedef struct RD_View RD_View; -struct RD_View -{ - // rjf: allocation links (for iterating all views) - RD_View *alloc_next; - RD_View *alloc_prev; - - // rjf: ownership links ('owners' can have lists of views) - RD_View *order_next; - RD_View *order_prev; - - // rjf: transient view children - RD_View *first_transient; - RD_View *last_transient; - - // rjf: view specification info - struct RD_ViewRuleInfo *spec; - - // rjf: allocation info - U64 generation; - - // rjf: loading animation state - F32 loading_t; - F32 loading_t_target; - U64 loading_progress_v; - U64 loading_progress_v_target; - - // rjf: view project (for project-specific/filtered views) - Arena *project_path_arena; - String8 project_path; - - // rjf: view state - UI_ScrollPt2 scroll_pos; - - // rjf: view-lifetime allocation & user data extensions - Arena *arena; - RD_ArenaExt *first_arena_ext; - RD_ArenaExt *last_arena_ext; - U64 transient_view_slots_count; - RD_TransientViewSlot *transient_view_slots; - RD_TransientViewNode *free_transient_view_node; - void *user_data; - - // rjf: filter mode - B32 is_filtering; - F32 is_filtering_t; - - // rjf: params tree state - Arena *params_arenas[2]; - MD_Node *params_roots[2]; - U64 params_write_gen; - U64 params_read_gen; - - // rjf: text query state - TxtPt query_cursor; - TxtPt query_mark; - U64 query_string_size; - U8 query_buffer[KB(4)]; + RD_EvalSpaceKind_CtrlEntity = E_SpaceKind_FirstUserDefined, + RD_EvalSpaceKind_MetaQuery, + RD_EvalSpaceKind_MetaCfg, + RD_EvalSpaceKind_MetaCmd, + RD_EvalSpaceKind_MetaTheme, + RD_EvalSpaceKind_MetaCtrlEntity, + RD_EvalSpaceKind_MetaUnattachedProcess, }; //////////////////////////////// -//~ rjf: Panel Types +//~ rjf: View UI Hook Types -typedef struct RD_Panel RD_Panel; -struct RD_Panel +#define RD_VIEW_UI_FUNCTION_SIG(name) void name(E_Eval eval, Rng2F32 rect) +#define RD_VIEW_UI_FUNCTION_NAME(name) rd_view_ui__##name +#define RD_VIEW_UI_FUNCTION_DEF(name) internal RD_VIEW_UI_FUNCTION_SIG(RD_VIEW_UI_FUNCTION_NAME(name)) +typedef RD_VIEW_UI_FUNCTION_SIG(RD_ViewUIFunctionType); + +typedef struct RD_ViewUIRule RD_ViewUIRule; +struct RD_ViewUIRule { - // rjf: tree links/data - RD_Panel *first; - RD_Panel *last; - RD_Panel *next; - RD_Panel *prev; - RD_Panel *parent; - U64 child_count; - - // rjf: allocation data - U64 generation; - - // rjf: split data - Axis2 split_axis; - F32 pct_of_parent; - - // rjf: animated rectangle data - Rng2F32 animated_rect_pct; - - // rjf: tab params - Side tab_side; - - // rjf: stable views (tabs) - RD_View *first_tab_view; - RD_View *last_tab_view; - U64 tab_view_count; - RD_Handle selected_tab_view; + String8 name; + RD_ViewUIFunctionType *ui; }; -typedef struct RD_PanelRec RD_PanelRec; -struct RD_PanelRec +typedef struct RD_ViewUIRuleNode RD_ViewUIRuleNode; +struct RD_ViewUIRuleNode { - RD_Panel *next; - int push_count; - int pop_count; + RD_ViewUIRuleNode *next; + RD_ViewUIRule v; +}; + +typedef struct RD_ViewUIRuleSlot RD_ViewUIRuleSlot; +struct RD_ViewUIRuleSlot +{ + RD_ViewUIRuleNode *first; + RD_ViewUIRuleNode *last; +}; + +typedef struct RD_ViewUIRuleMap RD_ViewUIRuleMap; +struct RD_ViewUIRuleMap +{ + RD_ViewUIRuleSlot *slots; + U64 slots_count; }; //////////////////////////////// @@ -323,7 +149,8 @@ enum RD_QueryFlag_CodeInput = (1<<2), RD_QueryFlag_KeepOldInput = (1<<3), RD_QueryFlag_SelectOldInput = (1<<4), - RD_QueryFlag_Required = (1<<5), + RD_QueryFlag_Floating = (1<<5), + RD_QueryFlag_Required = (1<<6), }; typedef U32 RD_CmdKindFlags; @@ -331,6 +158,22 @@ enum { RD_CmdKindFlag_ListInUI = (1<<0), RD_CmdKindFlag_ListInIPCDocs = (1<<1), + RD_CmdKindFlag_ListInTab = (1<<2), + RD_CmdKindFlag_ListInTextPt = (1<<3), + RD_CmdKindFlag_ListInTextRng = (1<<4), +}; + +//////////////////////////////// +//~ rjf: Autocompletion Cursor Info Type + +typedef struct RD_AutocompCursorInfo RD_AutocompCursorInfo; +struct RD_AutocompCursorInfo +{ + String8 list_expr; + String8 filter; + Rng1U64 replaced_range; + String8 callee_expr; + MD_Node *arg_schema; }; //////////////////////////////// @@ -339,45 +182,93 @@ enum #include "generated/raddbg.meta.h" //////////////////////////////// -//~ rjf: Config Types +//~ rjf: View State Types -typedef struct RD_CfgTree RD_CfgTree; -struct RD_CfgTree +typedef struct RD_ArenaExt RD_ArenaExt; +struct RD_ArenaExt { - RD_CfgTree *next; - RD_CfgSrc source; - MD_Node *root; + RD_ArenaExt *next; + Arena *arena; }; -typedef struct RD_CfgVal RD_CfgVal; -struct RD_CfgVal +typedef struct RD_ViewState RD_ViewState; +struct RD_ViewState { - RD_CfgVal *hash_next; - RD_CfgVal *linear_next; - RD_CfgTree *first; - RD_CfgTree *last; - U64 insertion_stamp; - String8 string; + // rjf: hash links & key + RD_ViewState *hash_next; + RD_ViewState *hash_prev; + RD_CfgID cfg_id; + + // rjf: touch info + U64 last_frame_index_touched; + U64 last_frame_index_built; + + // rjf: loading indicator info + F32 loading_t; + F32 loading_t_target; + U64 loading_progress_v; + U64 loading_progress_v_target; + + // rjf: scroll position + UI_ScrollPt2 scroll_pos; + + // rjf: eval visualization view state + EV_View *ev_view; + + // rjf: view-lifetime allocation & user data extensions + Arena *arena; + U64 arena_reset_pos; + RD_ArenaExt *first_arena_ext; + RD_ArenaExt *last_arena_ext; + void *user_data; + + // rjf: query state + B32 query_is_open; + TxtPt query_cursor; + TxtPt query_mark; + U8 query_buffer[KB(1)]; + U64 query_string_size; + + // rjf: contents are focused (disables query focus) + B32 contents_are_focused; }; -typedef struct RD_CfgSlot RD_CfgSlot; -struct RD_CfgSlot +typedef struct RD_ViewStateSlot RD_ViewStateSlot; +struct RD_ViewStateSlot { - RD_CfgVal *first; -}; - -typedef struct RD_CfgTable RD_CfgTable; -struct RD_CfgTable -{ - U64 slot_count; - RD_CfgSlot *slots; - U64 insertion_stamp_counter; - RD_CfgVal *first_val; - RD_CfgVal *last_val; + RD_ViewState *first; + RD_ViewState *last; }; //////////////////////////////// -//~ rjf: New Config/Entity Data Structure +//~ rjf: Vocabulary Map + +typedef struct RD_VocabInfoMapNode RD_VocabInfoMapNode; +struct RD_VocabInfoMapNode +{ + RD_VocabInfoMapNode *single_next; + RD_VocabInfoMapNode *plural_next; + RD_VocabInfo v; +}; + +typedef struct RD_VocabInfoMapSlot RD_VocabInfoMapSlot; +struct RD_VocabInfoMapSlot +{ + RD_VocabInfoMapNode *first; + RD_VocabInfoMapNode *last; +}; + +typedef struct RD_VocabInfoMap RD_VocabInfoMap; +struct RD_VocabInfoMap +{ + U64 single_slots_count; + RD_VocabInfoMapSlot *single_slots; + U64 plural_slots_count; + RD_VocabInfoMapSlot *plural_slots; +}; + +//////////////////////////////// +//~ rjf: Config Tree typedef struct RD_Cfg RD_Cfg; struct RD_Cfg @@ -387,7 +278,7 @@ struct RD_Cfg RD_Cfg *next; RD_Cfg *prev; RD_Cfg *parent; - U64 gen; + RD_CfgID id; String8 string; }; @@ -395,9 +286,17 @@ typedef struct RD_CfgNode RD_CfgNode; struct RD_CfgNode { RD_CfgNode *next; + RD_CfgNode *prev; RD_Cfg *v; }; +typedef struct RD_CfgSlot RD_CfgSlot; +struct RD_CfgSlot +{ + RD_CfgNode *first; + RD_CfgNode *last; +}; + typedef struct RD_CfgList RD_CfgList; struct RD_CfgList { @@ -406,6 +305,13 @@ struct RD_CfgList U64 count; }; +typedef struct RD_CfgArray RD_CfgArray; +struct RD_CfgArray +{ + RD_Cfg **v; + U64 count; +}; + typedef struct RD_CfgRec RD_CfgRec; struct RD_CfgRec { @@ -415,67 +321,54 @@ struct RD_CfgRec }; //////////////////////////////// -//~ rjf: Entity Types +//~ rjf: Structured Locations, Parsed From Config Trees -typedef U64 RD_EntityID; - -typedef struct RD_Entity RD_Entity; -struct RD_Entity +typedef struct RD_Location RD_Location; +struct RD_Location { - // rjf: tree links - RD_Entity *first; - RD_Entity *last; - RD_Entity *next; - RD_Entity *prev; - RD_Entity *parent; + String8 file_path; + TxtPt pt; + String8 expr; +}; + +//////////////////////////////// +//~ rjf: Structured Panel Trees, Parsed From Config Trees + +typedef struct RD_PanelNode RD_PanelNode; +struct RD_PanelNode +{ + // rjf: links data + RD_PanelNode *first; + RD_PanelNode *last; + RD_PanelNode *next; + RD_PanelNode *prev; + RD_PanelNode *parent; + U64 child_count; + RD_Cfg *cfg; - // rjf: metadata - RD_EntityKind kind; - RD_EntityFlags flags; - RD_EntityID id; - U64 gen; - U64 alloc_time_us; + // rjf: split data + Axis2 split_axis; + F32 pct_of_parent; - // rjf: basic equipment - TxtPt text_point; - B32 disabled; - B32 debug_subprocesses; - U64 u64; - U64 vaddr; - Vec4F32 color_hsva; - RD_CfgSrc cfg_src; - U64 timestamp; + // rjf: tab params + Side tab_side; - // rjf: string equipment - String8 string; + // rjf: which tabs are attached + RD_CfgList tabs; + RD_Cfg *selected_tab; }; -typedef struct RD_EntityNode RD_EntityNode; -struct RD_EntityNode +typedef struct RD_PanelTree RD_PanelTree; +struct RD_PanelTree { - RD_EntityNode *next; - RD_Entity *entity; + RD_PanelNode *root; + RD_PanelNode *focused; }; -typedef struct RD_EntityList RD_EntityList; -struct RD_EntityList +typedef struct RD_PanelNodeRec RD_PanelNodeRec; +struct RD_PanelNodeRec { - RD_EntityNode *first; - RD_EntityNode *last; - U64 count; -}; - -typedef struct RD_EntityArray RD_EntityArray; -struct RD_EntityArray -{ - RD_Entity **v; - U64 count; -}; - -typedef struct RD_EntityRec RD_EntityRec; -struct RD_EntityRec -{ - RD_Entity *next; + RD_PanelNode *next; S32 push_count; S32 pop_count; }; @@ -517,13 +410,7 @@ struct RD_RegsNode }; //////////////////////////////// -//~ rjf: Theme Types - -typedef struct RD_Theme RD_Theme; -struct RD_Theme -{ - Vec4F32 colors[RD_ThemeColor_COUNT]; -}; +//~ rjf: Structured Theme Types, Parsed From Config typedef enum RD_FontSlot { @@ -534,99 +421,20 @@ typedef enum RD_FontSlot } RD_FontSlot; -typedef enum RD_PaletteCode -{ - RD_PaletteCode_Base, - RD_PaletteCode_MenuBar, - RD_PaletteCode_Floating, - RD_PaletteCode_ImplicitButton, - RD_PaletteCode_PlainButton, - RD_PaletteCode_PositivePopButton, - RD_PaletteCode_NegativePopButton, - RD_PaletteCode_NeutralPopButton, - RD_PaletteCode_ScrollBarButton, - RD_PaletteCode_Tab, - RD_PaletteCode_TabInactive, - RD_PaletteCode_DropSiteOverlay, - RD_PaletteCode_COUNT -} -RD_PaletteCode; - -//////////////////////////////// -//~ rjf: Auto-Complete Lister Types - -typedef U32 RD_AutoCompListerFlags; -enum -{ - RD_AutoCompListerFlag_Locals = (1<<0), - RD_AutoCompListerFlag_Registers = (1<<1), - RD_AutoCompListerFlag_ViewRules = (1<<2), - RD_AutoCompListerFlag_ViewRuleParams= (1<<3), - RD_AutoCompListerFlag_Members = (1<<4), - RD_AutoCompListerFlag_Globals = (1<<5), - RD_AutoCompListerFlag_ThreadLocals = (1<<6), - RD_AutoCompListerFlag_Procedures = (1<<7), - RD_AutoCompListerFlag_Types = (1<<8), - RD_AutoCompListerFlag_Languages = (1<<9), - RD_AutoCompListerFlag_Architectures = (1<<10), - RD_AutoCompListerFlag_Tex2DFormats = (1<<11), - RD_AutoCompListerFlag_Files = (1<<12), -}; - -typedef struct RD_AutoCompListerItem RD_AutoCompListerItem; -struct RD_AutoCompListerItem -{ - String8 string; - String8 kind_string; - FuzzyMatchRangeList matches; - U64 group; - B32 is_non_code; -}; - -typedef struct RD_AutoCompListerItemChunkNode RD_AutoCompListerItemChunkNode; -struct RD_AutoCompListerItemChunkNode -{ - RD_AutoCompListerItemChunkNode *next; - RD_AutoCompListerItem *v; - U64 count; - U64 cap; -}; - -typedef struct RD_AutoCompListerItemChunkList RD_AutoCompListerItemChunkList; -struct RD_AutoCompListerItemChunkList -{ - RD_AutoCompListerItemChunkNode *first; - RD_AutoCompListerItemChunkNode *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct RD_AutoCompListerItemArray RD_AutoCompListerItemArray; -struct RD_AutoCompListerItemArray -{ - RD_AutoCompListerItem *v; - U64 count; -}; - -typedef struct RD_AutoCompListerParams RD_AutoCompListerParams; -struct RD_AutoCompListerParams -{ - RD_AutoCompListerFlags flags; - String8List strings; -}; - //////////////////////////////// //~ rjf: Per-Window State -typedef struct RD_Window RD_Window; -struct RD_Window +typedef struct RD_WindowState RD_WindowState; +struct RD_WindowState { // rjf: links & metadata - RD_Window *next; - RD_Window *prev; - U64 gen; + RD_WindowState *order_next; + RD_WindowState *order_prev; + RD_WindowState *hash_next; + RD_WindowState *hash_prev; + RD_CfgID cfg_id; U64 frames_alive; - RD_CfgSrc cfg_src; + U64 last_frame_index_touched; // rjf: top-level info & handles Arena *arena; @@ -635,10 +443,15 @@ struct RD_Window UI_State *ui; F32 last_dpi; B32 window_temporarily_focused_ipc; + B32 window_layout_reset; + Rng2F32 last_window_rect; - // rjf: config/settings - RD_SettingVal setting_vals[RD_SettingCode_COUNT]; - UI_Palette cfg_palettes[RD_PaletteCode_COUNT]; // derivative from theme + // rjf: theme (recomputed each frame) + UI_Theme *theme; + Vec4F32 theme_code_colors[RD_CodeColorSlot_COUNT]; + + // rjf: font raster flags (recomputed each frame) + FNT_RasterFlags font_slot_raster_flags[RD_FontSlot_COUNT]; // rjf: dev interface state B32 dev_menu_is_open; @@ -649,70 +462,36 @@ struct RD_Window B32 menu_bar_key_held; B32 menu_bar_focus_press_started; - // rjf: context menu state - Arena *ctx_menu_arena; - RD_Regs *ctx_menu_regs; - RD_RegSlot ctx_menu_regs_slot; - U8 *ctx_menu_input_buffer; - U64 ctx_menu_input_buffer_size; - U64 ctx_menu_input_string_size; - TxtPt ctx_menu_input_cursor; - TxtPt ctx_menu_input_mark; - // rjf: drop-completion state Arena *drop_completion_arena; String8List drop_completion_paths; - // rjf: autocomplete lister state - U64 autocomp_last_frame_idx; - B32 autocomp_input_dirty; - UI_Key autocomp_root_key; - Arena *autocomp_lister_params_arena; - RD_AutoCompListerParams autocomp_lister_params; - U64 autocomp_cursor_off; - U8 autocomp_lister_input_buffer[1024]; - U64 autocomp_lister_input_size; - F32 autocomp_open_t; - F32 autocomp_num_visible_rows_t; - S64 autocomp_cursor_num; - - // rjf: query view stack - Arena *query_cmd_arena; - String8 query_cmd_name; - RD_Regs *query_cmd_regs; - U64 query_cmd_regs_mask[(RD_RegSlot_COUNT + 63) / 64]; - RD_View *query_view_stack_top; - B32 query_view_selected; - F32 query_view_selected_t; - F32 query_view_t; + // rjf: query state + B32 query_is_active; + Arena *query_arena; + RD_Regs *query_regs; + RD_CfgID query_view_id; + RD_CfgID query_last_view_id; // rjf: hover eval state B32 hover_eval_focused; - TxtPt hover_eval_txt_cursor; - TxtPt hover_eval_txt_mark; - U8 hover_eval_txt_buffer[1024]; - U64 hover_eval_txt_size; Arena *hover_eval_arena; Vec2F32 hover_eval_spawn_pos; String8 hover_eval_string; - U64 hover_eval_first_frame_idx; - U64 hover_eval_last_frame_idx; - String8 hover_eval_file_path; - TxtPt hover_eval_file_pt; - U64 hover_eval_vaddr; - F32 hover_eval_open_t; - F32 hover_eval_num_visible_rows_t; + U64 hover_eval_firstt_us; + U64 hover_eval_lastt_us; + + // rjf: autocompletion state + U64 autocomp_last_frame_index; + Arena *autocomp_arena; + RD_Regs *autocomp_regs; + RD_AutocompCursorInfo autocomp_cursor_info; // rjf: error state U8 error_buffer[512]; U64 error_string_size; F32 error_t; - // rjf: panel state - RD_Panel *root_panel; - RD_Panel *free_panel; - RD_Panel *focused_panel; - // rjf: per-frame ui events state UI_EventList ui_events; @@ -720,47 +499,28 @@ struct RD_Window DR_Bucket *draw_bucket; }; -//////////////////////////////// -//~ rjf: Eval Visualization View Cache Types - -typedef struct RD_EvalVizViewCacheNode RD_EvalVizViewCacheNode; -struct RD_EvalVizViewCacheNode +typedef struct RD_WindowStateSlot RD_WindowStateSlot; +struct RD_WindowStateSlot { - RD_EvalVizViewCacheNode *next; - RD_EvalVizViewCacheNode *prev; - U64 key; - EV_View *v; -}; - -typedef struct RD_EvalVizViewCacheSlot RD_EvalVizViewCacheSlot; -struct RD_EvalVizViewCacheSlot -{ - RD_EvalVizViewCacheNode *first; - RD_EvalVizViewCacheNode *last; -}; - -//////////////////////////////// -//~ rjf: Meta Evaluation Cache Types - -typedef struct RD_CtrlEntityMetaEvalCacheNode RD_CtrlEntityMetaEvalCacheNode; -struct RD_CtrlEntityMetaEvalCacheNode -{ - RD_CtrlEntityMetaEvalCacheNode *next; - CTRL_Handle handle; - CTRL_MetaEval *meval; - Rng1U64 range; -}; - -typedef struct RD_CtrlEntityMetaEvalCacheSlot RD_CtrlEntityMetaEvalCacheSlot; -struct RD_CtrlEntityMetaEvalCacheSlot -{ - RD_CtrlEntityMetaEvalCacheNode *first; - RD_CtrlEntityMetaEvalCacheNode *last; + RD_WindowState *first; + RD_WindowState *last; }; //////////////////////////////// //~ rjf: Main Per-Process Graphical State +read_only global U64 rd_name_bucket_chunk_sizes[] = +{ + 16, + 64, + 256, + 1024, + 4096, + 16384, + 65536, + 0xffffffffffffffffull, +}; + typedef struct RD_NameChunkNode RD_NameChunkNode; struct RD_NameChunkNode { @@ -768,14 +528,6 @@ struct RD_NameChunkNode U64 size; }; -typedef struct RD_EntityListCache RD_EntityListCache; -struct RD_EntityListCache -{ - Arena *arena; - U64 alloc_gen; - RD_EntityList list; -}; - typedef struct RD_AmbiguousPathNode RD_AmbiguousPathNode; struct RD_AmbiguousPathNode { @@ -791,6 +543,46 @@ struct RD_State Arena *arena; B32 quit; B32 quit_after_success; + S32 frame_depth; + U64 frame_eval_memread_endt_us; + + // rjf: config bucket paths + Arena *user_path_arena; + String8 user_path; + Arena *project_path_arena; + String8 project_path; + Arena *theme_path_arena; + String8 theme_path; + + // rjf: unpacked settings (cached, because they need to be used + // earlier than setting evaluation is legal in a frame) + B32 alt_menu_bar_enabled; + B32 use_default_stl_type_views; + B32 use_default_ue_type_views; + + // rjf: animation rates + F32 catchall_animation_rate; + F32 menu_animation_rate; + F32 menu_animation_rate__slow; + F32 entity_alive_animation_rate; + F32 rich_hover_animation_rate; + F32 scrolling_animation_rate; + F32 tooltip_animation_rate; + + // rjf: serialized config debug string keys + U128 user_cfg_string_key; + U128 project_cfg_string_key; + U128 cmdln_cfg_string_key; + U128 transient_cfg_string_key; + + // rjf: schema table + MD_NodePtrList *schemas; + + // rjf: default theme table + MD_Node *theme_preset_trees[RD_ThemePreset_COUNT]; + + // rjf: vocab table + RD_VocabInfoMap vocab_info_map; // rjf: log Log *log; @@ -802,18 +594,35 @@ struct RD_State U64 frame_time_us_history[64]; U64 num_frames_requested; F64 time_in_seconds; + U64 time_in_us; // rjf: frame parameters F32 frame_dt; DI_Scope *frame_di_scope; + CTRL_Scope *frame_ctrl_scope; // rjf: dbgi match store DI_MatchStore *match_store; - // rjf: ambiguous path table + // rjf: evaluation cache + E_Cache *eval_cache; + + // rjf: ambiguous path table (constructed from-scratch each frame) U64 ambiguous_path_slots_count; RD_AmbiguousPathNode **ambiguous_path_slots; + // rjf: key map (constructed from-scratch each frame) + RD_KeyMap *key_map; + + // rjf: slot -> font tag map (constructed from-scratch each frame) + FNT_Tag font_slot_table[RD_FontSlot_COUNT]; + + // rjf: meta name -> eval type key map (constructed from-scratch each frame) + E_String2TypeKeyMap *meta_name2type_map; + + // rjf: name -> view ui map (constructed from-scratch each frame) + RD_ViewUIRuleMap *view_ui_rule_map; + // rjf: registers stack RD_RegsNode base_regs; RD_RegsNode *top_regs; @@ -838,19 +647,6 @@ struct RD_State // rjf: text editing mode state B32 text_edit_mode; - // rjf: string search state - Arena *string_search_arena; - String8 string_search_string; - - // rjf: eval visualization view cache - U64 eval_viz_view_cache_slots_count; - RD_EvalVizViewCacheSlot *eval_viz_view_cache_slots; - RD_EvalVizViewCacheNode *eval_viz_view_cache_node_free; - - // rjf: ctrl entity meta eval cache - U64 ctrl_entity_meval_cache_slots_count; - RD_CtrlEntityMetaEvalCacheSlot *ctrl_entity_meval_cache_slots; - // rjf: contextual hover info RD_Regs *hover_regs; RD_RegSlot hover_regs_slot; @@ -860,10 +656,6 @@ struct RD_State // rjf: icon texture R_Handle icon_texture; - // rjf: current path - Arena *current_path_arena; - String8 current_path; - // rjf: fixed ui keys UI_Key drop_completion_key; UI_Key ctx_menu_key; @@ -875,86 +667,45 @@ struct RD_State RD_DragDropState drag_drop_state; // rjf: cfg state - RD_NameChunkNode *free_name_chunks[8]; + RD_NameChunkNode *free_name_chunks[ArrayCount(rd_name_bucket_chunk_sizes)]; RD_Cfg *free_cfg; RD_Cfg *root_cfg; + U64 cfg_id_slots_count; + RD_CfgSlot *cfg_id_slots; + RD_CfgNode *free_cfg_id_node; + U64 cfg_id_gen; + RD_CfgID cfg_last_accessed_id; + RD_Cfg *cfg_last_accessed; + U64 cfg_change_gen; - //- - // TODO(rjf): TO BE ELIMINATED OR REPLACED VVVVVVVVVVVVVVVV - //- + // rjf: window state cache + U64 window_state_slots_count; + RD_WindowStateSlot *window_state_slots; + RD_WindowState *free_window_state; + RD_CfgID last_focused_window; + RD_WindowState *first_window_state; + RD_WindowState *last_window_state; + RD_CfgID window_state_last_accessed_id; + RD_WindowState *window_state_last_accessed; - // rjf: entity state - Arena *entities_arena; - RD_Entity *entities_base; - U64 entities_count; - U64 entities_id_gen; - RD_Entity *entities_root; - RD_Entity *entities_free[2]; // [0] -> normal lifetime, not user defined; [1] -> user defined lifetime (& thus undoable) - U64 entities_free_count; - U64 entities_active_count; - - // rjf: entity query caches - U64 kind_alloc_gens[RD_EntityKind_COUNT]; - RD_EntityListCache kind_caches[RD_EntityKind_COUNT]; - - // rjf: key map table - Arena *key_map_arena; - U64 key_map_table_size; - RD_KeyMapSlot *key_map_table; - RD_KeyMapNode *free_key_map_node; - U64 key_map_total_count; + // rjf: view state cache + U64 view_state_slots_count; + RD_ViewStateSlot *view_state_slots; + RD_ViewState *free_view_state; + RD_CfgID view_state_last_accessed_id; + RD_ViewState *view_state_last_accessed; // rjf: bind change Arena *bind_change_arena; B32 bind_change_active; + RD_CfgID bind_change_binding_id; String8 bind_change_cmd_name; - RD_Binding bind_change_binding; - - // rjf: windows - RD_Window *first_window; - RD_Window *last_window; - RD_Window *free_window; - U64 window_count; - B32 last_window_queued_save; - RD_Handle last_focused_window; - - // rjf: view state - RD_View *first_view; - RD_View *last_view; - RD_View *free_view; - U64 free_view_count; - U64 allocated_view_count; - - // rjf: config reading state - Arena *cfg_path_arenas[RD_CfgSrc_COUNT]; - String8 cfg_paths[RD_CfgSrc_COUNT]; - U64 cfg_cached_timestamp[RD_CfgSrc_COUNT]; - Arena *cfg_arena; - RD_CfgTable cfg_table; - U64 ctrl_exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; - - // rjf: running theme state - RD_Theme cfg_theme_target; - RD_Theme cfg_theme; - Arena *cfg_main_font_path_arena; - Arena *cfg_code_font_path_arena; - String8 cfg_main_font_path; - String8 cfg_code_font_path; - FNT_Tag cfg_font_tags[RD_FontSlot_COUNT]; // derivative from font paths - - // rjf: global settings - RD_SettingVal cfg_setting_vals[RD_CfgSrc_COUNT][RD_SettingCode_COUNT]; - - //- - // TODO(rjf): TO BE ELIMINATED OR REPLACED ^^^^^^^^^^^^^^^^^^ - //- }; //////////////////////////////// //~ rjf: Globals -read_only global RD_CfgTree d_nil_cfg_tree = {&d_nil_cfg_tree, RD_CfgSrc_User, &md_nil_node}; -read_only global RD_CfgVal d_nil_cfg_val = {&d_nil_cfg_val, &d_nil_cfg_val, &d_nil_cfg_tree, &d_nil_cfg_tree}; +read_only global RD_VocabInfo rd_nil_vocab_info = {0}; read_only global RD_Cfg rd_nil_cfg = { @@ -965,67 +716,50 @@ read_only global RD_Cfg rd_nil_cfg = &rd_nil_cfg, }; -read_only global RD_Entity rd_nil_entity = +read_only global RD_PanelNode rd_nil_panel_node = { - &rd_nil_entity, - &rd_nil_entity, - &rd_nil_entity, - &rd_nil_entity, - &rd_nil_entity, + &rd_nil_panel_node, + &rd_nil_panel_node, + &rd_nil_panel_node, + &rd_nil_panel_node, + &rd_nil_panel_node, + 0, + &rd_nil_cfg, + .selected_tab = &rd_nil_cfg, }; read_only global RD_CmdKindInfo rd_nil_cmd_kind_info = {0}; -read_only global RD_ViewRuleInfo rd_nil_view_rule_info = +RD_VIEW_UI_FUNCTION_DEF(null); +read_only global RD_ViewUIRule rd_nil_view_ui_rule = { {0}, - {0}, - {0}, - {0}, - RD_IconKind_Null, - 0, - EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_NAME(nil), - RD_VIEW_RULE_UI_FUNCTION_NAME(null) + RD_VIEW_UI_FUNCTION_NAME(null), }; -read_only global RD_View rd_nil_view = +read_only global RD_ViewState rd_nil_view_state = { - &rd_nil_view, - &rd_nil_view, - &rd_nil_view, - &rd_nil_view, - &rd_nil_view, - &rd_nil_view, - &rd_nil_view_rule_info, + &rd_nil_view_state, + &rd_nil_view_state, }; -read_only global RD_Panel rd_nil_panel = +read_only global RD_WindowState rd_nil_window_state = { - &rd_nil_panel, - &rd_nil_panel, - &rd_nil_panel, - &rd_nil_panel, - &rd_nil_panel, + &rd_nil_window_state, + &rd_nil_window_state, + &rd_nil_window_state, + &rd_nil_window_state, }; global RD_State *rd_state = 0; -global RD_Handle rd_last_drag_drop_panel = {0}; -global RD_Handle rd_last_drag_drop_prev_tab = {0}; +global RD_CfgID rd_last_drag_drop_panel = 0; +global RD_CfgID rd_last_drag_drop_prev_tab = 0; //////////////////////////////// -//~ rjf: Handle Type Pure Functions +//~ rjf: Config ID Type Functions -internal RD_Handle rd_handle_zero(void); -internal B32 rd_handle_match(RD_Handle a, RD_Handle b); -internal void rd_handle_list_push_node(RD_HandleList *list, RD_HandleNode *node); -internal void rd_handle_list_push(Arena *arena, RD_HandleList *list, RD_Handle handle); -internal RD_HandleList rd_handle_list_copy(Arena *arena, RD_HandleList list); - -//////////////////////////////// -//~ rjf: Config Type Pure Functions - -internal void rd_cfg_table_push_unparsed_string(Arena *arena, RD_CfgTable *table, String8 string, RD_CfgSrc source); -internal RD_CfgVal *rd_cfg_val_from_string(RD_CfgTable *table, String8 string); +internal void rd_cfg_id_list_push(Arena *arena, RD_CfgIDList *list, RD_CfgID id); +internal RD_CfgIDList rd_cfg_id_list_copy(Arena *arena, RD_CfgIDList *src); //////////////////////////////// //~ rjf: Registers Type Functions @@ -1039,94 +773,12 @@ internal RD_Regs *rd_regs_copy(Arena *arena, RD_Regs *src); internal void rd_cmd_list_push_new(Arena *arena, RD_CmdList *cmds, String8 name, RD_Regs *regs); //////////////////////////////// -//~ rjf: Entity Type Pure Functions +//~ rjf: View UI Rule Functions -//- rjf: nil -internal B32 rd_entity_is_nil(RD_Entity *entity); -#define rd_require_entity_nonnil(entity, if_nil_stmts) do{if(rd_entity_is_nil(entity)){if_nil_stmts;}}while(0) +internal RD_ViewUIRuleMap *rd_view_ui_rule_map_make(Arena *arena, U64 slots_count); +internal void rd_view_ui_rule_map_insert(Arena *arena, RD_ViewUIRuleMap *map, String8 string, RD_ViewUIFunctionType *ui); -//- rjf: handle <-> entity conversions -internal U64 rd_index_from_entity(RD_Entity *entity); -internal RD_Handle rd_handle_from_entity(RD_Entity *entity); -internal RD_Entity *rd_entity_from_handle(RD_Handle handle); - -//- rjf: entity recursion iterators -internal RD_EntityRec rd_entity_rec_depth_first(RD_Entity *entity, RD_Entity *subtree_root, U64 sib_off, U64 child_off); -#define rd_entity_rec_depth_first_pre(entity, subtree_root) rd_entity_rec_depth_first((entity), (subtree_root), OffsetOf(RD_Entity, next), OffsetOf(RD_Entity, first)) -#define rd_entity_rec_depth_first_post(entity, subtree_root) rd_entity_rec_depth_first((entity), (subtree_root), OffsetOf(RD_Entity, prev), OffsetOf(RD_Entity, last)) - -//- rjf: ancestor/child introspection -internal RD_Entity *rd_entity_child_from_kind(RD_Entity *entity, RD_EntityKind kind); - -//- rjf: entity list building -internal void rd_entity_list_push(Arena *arena, RD_EntityList *list, RD_Entity *entity); -internal RD_EntityArray rd_entity_array_from_list(Arena *arena, RD_EntityList *list); -#define rd_first_entity_from_list(list) ((list)->first != 0 ? (list)->first->entity : &rd_nil_entity) - -//- rjf: entity -> color operations -internal Vec4F32 rd_hsva_from_entity(RD_Entity *entity); -internal Vec4F32 rd_rgba_from_entity(RD_Entity *entity); - -//- rjf: entity -> expansion tree keys -internal EV_Key rd_ev_key_from_entity(RD_Entity *entity); -internal EV_Key rd_parent_ev_key_from_entity(RD_Entity *entity); - -//////////////////////////////// -//~ rjf: View Type Functions - -internal B32 rd_view_is_nil(RD_View *view); -internal B32 rd_view_is_project_filtered(RD_View *view); -internal RD_Handle rd_handle_from_view(RD_View *view); -internal RD_View *rd_view_from_handle(RD_Handle handle); - -//////////////////////////////// -//~ rjf: View Spec Type Functions - -internal RD_ViewRuleKind rd_view_rule_kind_from_string(String8 string); -internal RD_ViewRuleInfo *rd_view_rule_info_from_kind(RD_ViewRuleKind kind); -internal RD_ViewRuleInfo *rd_view_rule_info_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Panel Type Functions - -//- rjf: basic type functions -internal B32 rd_panel_is_nil(RD_Panel *panel); -internal RD_Handle rd_handle_from_panel(RD_Panel *panel); -internal RD_Panel *rd_panel_from_handle(RD_Handle handle); -internal UI_Key rd_ui_key_from_panel(RD_Panel *panel); - -//- rjf: tree construction -internal void rd_panel_insert(RD_Panel *parent, RD_Panel *prev_child, RD_Panel *new_child); -internal void rd_panel_remove(RD_Panel *parent, RD_Panel *child); - -//- rjf: tree walk -internal RD_PanelRec rd_panel_rec_depth_first(RD_Panel *panel, U64 sib_off, U64 child_off); -#define rd_panel_rec_depth_first_pre(panel) rd_panel_rec_depth_first(panel, OffsetOf(RD_Panel, next), OffsetOf(RD_Panel, first)) -#define rd_panel_rec_depth_first_pre_rev(panel) rd_panel_rec_depth_first(panel, OffsetOf(RD_Panel, prev), OffsetOf(RD_Panel, last)) - -//- rjf: panel -> rect calculations -internal Rng2F32 rd_target_rect_from_panel_child(Rng2F32 parent_rect, RD_Panel *parent, RD_Panel *panel); -internal Rng2F32 rd_target_rect_from_panel(Rng2F32 root_rect, RD_Panel *root, RD_Panel *panel); - -//- rjf: view ownership insertion/removal -internal void rd_panel_insert_tab_view(RD_Panel *panel, RD_View *prev_view, RD_View *view); -internal void rd_panel_remove_tab_view(RD_Panel *panel, RD_View *view); -internal RD_View *rd_selected_tab_from_panel(RD_Panel *panel); - -//- rjf: icons & display strings -internal RD_IconKind rd_icon_kind_from_view(RD_View *view); -internal DR_FancyStringList rd_title_fstrs_from_view(Arena *arena, RD_View *view, Vec4F32 primary_color, Vec4F32 secondary_color, F32 size); - -//////////////////////////////// -//~ rjf: Window Type Functions - -internal RD_Handle rd_handle_from_window(RD_Window *window); -internal RD_Window *rd_window_from_handle(RD_Handle handle); - -//////////////////////////////// -//~ rjf: Command Parameters From Context - -internal B32 rd_prefer_dasm_from_window(RD_Window *window); +internal RD_ViewUIRule *rd_view_ui_rule_from_string(String8 string); //////////////////////////////// //~ rjf: Global Cross-Window UI Interaction State Functions @@ -1139,102 +791,106 @@ internal void rd_drag_kill(void); internal void rd_set_hover_regs(RD_RegSlot slot); internal RD_Regs *rd_get_hover_regs(void); -internal void rd_open_ctx_menu(UI_Key anchor_box_key, Vec2F32 anchor_box_off, RD_RegSlot slot); - //////////////////////////////// //~ rjf: Name Allocation -internal U64 rd_name_bucket_idx_from_string_size(U64 size); +internal U64 rd_name_bucket_num_from_string_size(U64 size); internal String8 rd_name_alloc(String8 string); internal void rd_name_release(String8 string); //////////////////////////////// -//~ rjf: New Config/Entity Data Structure Functions +//~ rjf: Config Tree Functions internal RD_Cfg *rd_cfg_alloc(void); internal void rd_cfg_release(RD_Cfg *cfg); +internal void rd_cfg_release_all_children(RD_Cfg *cfg); +internal RD_Cfg *rd_cfg_from_id(RD_CfgID id); internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string); internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...); +internal RD_Cfg *rd_cfg_new_replace(RD_Cfg *parent, String8 string); +internal RD_Cfg *rd_cfg_new_replacef(RD_Cfg *parent, char *fmt, ...); +internal RD_Cfg *rd_cfg_deep_copy(RD_Cfg *src_root); internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string); +internal void rd_cfg_equip_stringf(RD_Cfg *cfg, char *fmt, ...); internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child); internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child); internal RD_Cfg *rd_cfg_child_from_string(RD_Cfg *parent, String8 string); +internal RD_Cfg *rd_cfg_child_from_string_or_alloc(RD_Cfg *parent, String8 string); +internal RD_Cfg *rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 string); internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string); internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string); -internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 string); -internal String8 rd_string_from_cfg_tree(Arena *arena, RD_Cfg *cfg); +internal RD_CfgArray rd_cfg_array_from_list(Arena *arena, RD_CfgList *list); +internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string); +internal String8 rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg); internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg); internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); +internal void rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg); +#define rd_cfg_list_first(list) ((list)->count ? (list)->first->v : &rd_nil_cfg) +#define rd_cfg_list_last(list) ((list)->count ? (list)->last->v : &rd_nil_cfg) -//////////////////////////////// -//~ rjf: Entity Stateful Functions +internal RD_PanelTree rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg); +internal RD_PanelNodeRec rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off); +#define rd_panel_node_rec__depth_first_pre(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, next), OffsetOf(RD_PanelNode, first)) +#define rd_panel_node_rec__depth_first_pre_rev(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, prev), OffsetOf(RD_PanelNode, last)) +internal RD_PanelNode *rd_panel_node_from_tree_cfg(RD_PanelNode *root, RD_Cfg *cfg); +internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel); +internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel); -//- rjf: entity allocation + tree forming -internal RD_Entity *rd_entity_alloc(RD_Entity *parent, RD_EntityKind kind); -internal void rd_entity_mark_for_deletion(RD_Entity *entity); -internal void rd_entity_release(RD_Entity *entity); -internal void rd_entity_change_parent(RD_Entity *entity, RD_Entity *old_parent, RD_Entity *new_parent, RD_Entity *prev_child); -internal RD_Entity *rd_entity_child_from_kind_or_alloc(RD_Entity *entity, RD_EntityKind kind); +internal B32 rd_cfg_is_project_filtered(RD_Cfg *cfg); +internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string); +internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding); -//- rjf: entity simple equipment -internal void rd_entity_equip_txt_pt(RD_Entity *entity, TxtPt point); -internal void rd_entity_equip_disabled(RD_Entity *entity, B32 b32); -internal void rd_entity_equip_u64(RD_Entity *entity, U64 u64); -internal void rd_entity_equip_color_rgba(RD_Entity *entity, Vec4F32 rgba); -internal void rd_entity_equip_color_hsva(RD_Entity *entity, Vec4F32 hsva); -internal void rd_entity_equip_cfg_src(RD_Entity *entity, RD_CfgSrc cfg_src); -internal void rd_entity_equip_timestamp(RD_Entity *entity, U64 timestamp); +internal Vec4F32 rd_hsva_from_cfg(RD_Cfg *cfg); +internal Vec4F32 rd_color_from_cfg(RD_Cfg *cfg); -//- rjf: control layer correllation equipment -internal void rd_entity_equip_vaddr(RD_Entity *entity, U64 vaddr); +internal B32 rd_disabled_from_cfg(RD_Cfg *cfg); +internal RD_Location rd_location_from_cfg(RD_Cfg *cfg); +internal String8 rd_label_from_cfg(RD_Cfg *cfg); +internal String8 rd_expr_from_cfg(RD_Cfg *cfg); +internal String8 rd_path_from_cfg(RD_Cfg *cfg); +internal D_Target rd_target_from_cfg(Arena *arena, RD_Cfg *cfg); -//- rjf: name equipment -internal void rd_entity_equip_name(RD_Entity *entity, String8 name); +internal MD_NodePtrList rd_schemas_from_name(String8 name); +internal String8 rd_default_setting_from_names(String8 schema_name, String8 setting_name); + +internal String8 rd_setting_from_name(String8 name); +internal B32 rd_setting_b32_from_name(String8 name); +internal U64 rd_setting_u64_from_name(String8 name); +internal F32 rd_setting_f32_from_name(String8 name); + +internal RD_Cfg *rd_immediate_cfg_from_key(String8 string); +internal RD_Cfg *rd_immediate_cfg_from_keyf(char *fmt, ...); -//- rjf: file path map override lookups internal String8 rd_mapped_from_file_path(Arena *arena, String8 file_path); internal String8List rd_possible_overrides_from_file_path(Arena *arena, String8 file_path); -//- rjf: top-level state queries -internal RD_Entity *rd_entity_root(void); -internal RD_EntityList rd_push_entity_list_with_kind(Arena *arena, RD_EntityKind kind); -internal RD_Entity *rd_entity_from_id(RD_EntityID id); -internal RD_Entity *rd_entity_from_name_and_kind(String8 string, RD_EntityKind kind); - -//////////////////////////////// -//~ rjf: Frontend Entity Info Extraction - -internal D_Target rd_d_target_from_entity(RD_Entity *entity); -internal DR_FancyStringList rd_title_fstrs_from_entity(Arena *arena, RD_Entity *entity, Vec4F32 secondary_color, F32 size); - //////////////////////////////// //~ rjf: Control Entity Info Extraction -internal Vec4F32 rd_rgba_from_ctrl_entity(CTRL_Entity *entity); +internal Vec4F32 rd_color_from_ctrl_entity(CTRL_Entity *entity); internal String8 rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity); -internal DR_FancyStringList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, Vec4F32 secondary_color, F32 size, B32 include_extras); //////////////////////////////// //~ rjf: Evaluation Spaces -//- rjf: entity <-> eval space -internal RD_Entity *rd_entity_from_eval_space(E_Space space); -internal E_Space rd_eval_space_from_entity(RD_Entity *entity); +//- rjf: cfg <-> eval space +internal RD_Cfg *rd_cfg_from_eval_space(E_Space space); +internal E_Space rd_eval_space_from_cfg(RD_Cfg *cfg); //- rjf: ctrl entity <-> eval space internal CTRL_Entity *rd_ctrl_entity_from_eval_space(E_Space space); internal E_Space rd_eval_space_from_ctrl_entity(CTRL_Entity *entity, E_SpaceKind kind); -//- rjf: entity -> meta eval -internal CTRL_MetaEval *rd_ctrl_meta_eval_from_entity(Arena *arena, RD_Entity *entity); -internal CTRL_MetaEval *rd_ctrl_meta_eval_from_ctrl_entity(Arena *arena, CTRL_Entity *entity); +//- rjf: command name <-> eval space +internal String8 rd_cmd_name_from_eval(E_Eval eval); //- rjf: eval space reads/writes +internal U64 rd_eval_space_gen(void *u, E_Space space); internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range); internal B32 rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range); //- rjf: asynchronous streamed reads -> hashes from spaces -internal U128 rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated); +internal HS_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated); //- rjf: space -> entire range internal Rng1U64 rd_whole_range_from_eval_space(E_Space space); @@ -1243,44 +899,22 @@ internal Rng1U64 rd_whole_range_from_eval_space(E_Space space); //~ rjf: Evaluation Visualization //- rjf: writing values back to child processes -internal B32 rd_commit_eval_value_string(E_Eval dst_eval, String8 string, B32 string_needs_unescaping); - -//- rjf: eval / view rule params tree info extraction -internal U64 rd_base_offset_from_eval(E_Eval eval); -internal E_Value rd_value_from_params_key(MD_Node *params, String8 key); -internal Rng1U64 rd_range_from_eval_params(E_Eval eval, MD_Node *params); -internal TXT_LangKind rd_lang_kind_from_eval_params(E_Eval eval, MD_Node *params); -internal Arch rd_arch_from_eval_params(E_Eval eval, MD_Node *params); -internal Vec2S32 rd_dim2s32_from_eval_params(E_Eval eval, MD_Node *params); -internal R_Tex2DFormat rd_tex2dformat_from_eval_params(E_Eval eval, MD_Node *params); +internal B32 rd_commit_eval_value_string(E_Eval dst_eval, String8 string); //- rjf: eval <-> file path +internal String8 rd_file_path_from_eval(Arena *arena, E_Eval eval); internal String8 rd_file_path_from_eval_string(Arena *arena, String8 string); internal String8 rd_eval_string_from_file_path(Arena *arena, String8 string); +//- rjf: eval -> query +internal String8 rd_query_from_eval_string(Arena *arena, String8 string); + //////////////////////////////// -//~ rjf: View State Functions +//~ rjf: View Functions -//- rjf: allocation/releasing -internal RD_View *rd_view_alloc(void); -internal void rd_view_release(RD_View *view); - -//- rjf: equipment -internal void rd_view_equip_spec(RD_View *view, RD_ViewRuleInfo *spec, String8 query, MD_Node *params); -internal void rd_view_equip_query(RD_View *view, String8 query); -internal void rd_view_equip_loading_info(RD_View *view, B32 is_loading, U64 progress_v, U64 progress_target); - -//- rjf: user state extensions -internal void *rd_view_get_or_push_user_state(RD_View *view, U64 size); -internal Arena *rd_view_push_arena_ext(RD_View *view); -#define rd_view_user_state(view, type) (type *)rd_view_get_or_push_user_state((view), sizeof(type)) - -//- rjf: param saving -internal void rd_view_store_param(RD_View *view, String8 key, String8 value); -internal void rd_view_store_paramf(RD_View *view, String8 key, char *fmt, ...); -#define rd_view_store_param_f32(view, key, f32) rd_view_store_paramf((view), (key), "%ff", (f32)) -#define rd_view_store_param_s64(view, key, s64) rd_view_store_paramf((view), (key), "%I64d", (s64)) -#define rd_view_store_param_u64(view, key, u64) rd_view_store_paramf((view), (key), "0x%I64x", (u64)) +internal RD_Cfg *rd_view_from_eval(RD_Cfg *parent, E_Eval eval); +internal RD_ViewState *rd_view_state_from_cfg(RD_Cfg *cfg); +internal void rd_view_ui(Rng2F32 rect); //////////////////////////////// //~ rjf: View Building API @@ -1288,8 +922,18 @@ internal void rd_view_store_paramf(RD_View *view, String8 key, char *fmt, ...); //- rjf: view info extraction internal Arena *rd_view_arena(void); internal UI_ScrollPt2 rd_view_scroll_pos(void); -internal String8 rd_view_expr_string(void); -internal String8 rd_view_filter(void); +internal EV_View *rd_view_eval_view(void); +internal String8 rd_view_query_cmd(void); +internal String8 rd_view_query_input(void); +internal String8 rd_view_setting_from_name(String8 string); +internal E_Value rd_view_setting_value_from_name(String8 string); +internal B32 rd_view_setting_b32_from_name(String8 string); +internal U64 rd_view_setting_u64_from_name(String8 string); +internal F32 rd_view_setting_f32_from_name(String8 string); + +//- rjf: evaluation & tag (a view's 'call') parameter extraction +internal TXT_LangKind rd_lang_kind_from_eval(E_Eval eval); +internal Arch rd_arch_from_eval(E_Eval eval); //- rjf: pushing/attaching view resources internal void *rd_view_state_by_size(U64 size); @@ -1298,7 +942,6 @@ internal Arena *rd_push_view_arena(void); //- rjf: storing view-attached state internal void rd_store_view_expr_string(String8 string); -internal void rd_store_view_filter(String8 string); internal void rd_store_view_loading_info(B32 is_loading, U64 progress_u64, U64 progress_u64_target); internal void rd_store_view_scroll_pos(UI_ScrollPt2 pos); internal void rd_store_view_param(String8 key, String8 value); @@ -1308,108 +951,60 @@ internal void rd_store_view_paramf(String8 key, char *fmt, ...); #define rd_store_view_param_u64(key, u64) rd_store_view_paramf((key), "0x%I64x", (u64)) //////////////////////////////// -//~ rjf: Expand-Keyed Transient View Functions +//~ rjf: Window Functions -internal RD_TransientViewNode *rd_transient_view_node_from_ev_key(RD_View *owner_view, EV_Key key); - -//////////////////////////////// -//~ rjf: Panel State Functions - -internal RD_Panel *rd_panel_alloc(RD_Window *ws); -internal void rd_panel_release(RD_Window *ws, RD_Panel *panel); -internal void rd_panel_release_all_views(RD_Panel *panel); - -//////////////////////////////// -//~ rjf: Window State Functions - -internal RD_Window *rd_window_open(Vec2F32 size, OS_Handle preferred_monitor, RD_CfgSrc cfg_src); - -internal RD_Window *rd_window_from_os_handle(OS_Handle os); - -internal void rd_window_frame(RD_Window *ws); +internal String8 rd_push_window_title(Arena *arena); +internal RD_Cfg *rd_window_from_cfg(RD_Cfg *cfg); +internal RD_WindowState *rd_window_state_from_cfg(RD_Cfg *cfg); +internal RD_WindowState *rd_window_state_from_os_handle(OS_Handle os); +internal void rd_window_frame(void); //////////////////////////////// //~ rjf: Eval Visualization -internal EV_ExpandInfo rd_ev_view_rule_expr_expand_info__meta_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, RD_EntityKind kind); -internal EV_ExpandRangeInfo rd_ev_view_rule_expr_expand_range_info__meta_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, RD_EntityKind kind, B32 add_new_at_top); -internal U64 rd_ev_view_rule_expr_id_from_num__meta_entities(U64 num, void *user_data, RD_EntityKind kind, B32 add_new_at_top); -internal U64 rd_ev_view_rule_expr_num_from_id__meta_entities(U64 id, void *user_data, RD_EntityKind kind, B32 add_new_at_top); - -internal EV_ExpandInfo rd_ev_view_rule_expr_expand_info__meta_ctrl_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, CTRL_EntityKind kind); -internal EV_ExpandRangeInfo rd_ev_view_rule_expr_expand_range_info__meta_ctrl_entities(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, CTRL_EntityKind kind); -internal U64 rd_ev_view_rule_expr_id_from_num__meta_ctrl_entities(U64 num, void *user_data, CTRL_EntityKind kind); -internal U64 rd_ev_view_rule_expr_num_from_id__meta_ctrl_entities(U64 id, void *user_data, CTRL_EntityKind kind); - -internal EV_ExpandInfo rd_ev_view_rule_expr_expand_info__debug_info_tables(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, RDI_SectionKind section); -internal EV_ExpandRangeInfo rd_ev_view_rule_expr_expand_range_info__debug_info_tables(Arena *arena, EV_View *view, String8 filter, E_Expr *expr, MD_Node *params, Rng1U64 idx_range, void *user_data, RDI_SectionKind section); -internal U64 rd_ev_view_rule_expr_id_from_num__debug_info_tables(U64 num, void *user_data, RDI_SectionKind section); -internal U64 rd_ev_view_rule_expr_num_from_id__debug_info_tables(U64 id, void *user_data, RDI_SectionKind section); - -internal EV_View *rd_ev_view_from_key(U64 key); -internal F32 rd_append_value_strings_from_eval(Arena *arena, EV_StringFlags flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size, S32 depth, E_Eval eval, E_Member *member, EV_ViewRuleList *view_rules, String8List *out); -internal String8 rd_value_string_from_eval(Arena *arena, EV_StringFlags flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size, E_Eval eval, E_Member *member, EV_ViewRuleList *view_rules); +internal String8 rd_value_string_from_eval(Arena *arena, String8 filter, EV_StringParams *params, FNT_Tag font, F32 font_size, F32 max_size, E_Eval eval); //////////////////////////////// //~ rjf: Hover Eval -internal void rd_set_hover_eval(Vec2F32 pos, String8 file_path, TxtPt pt, U64 vaddr, String8 string); +internal void rd_set_hover_eval(Vec2F32 pos, String8 string); //////////////////////////////// -//~ rjf: Auto-Complete Lister +//~ rjf: Autocompletion Lister -internal void rd_autocomp_lister_item_chunk_list_push(Arena *arena, RD_AutoCompListerItemChunkList *list, U64 cap, RD_AutoCompListerItem *item); -internal RD_AutoCompListerItemArray rd_autocomp_lister_item_array_from_chunk_list(Arena *arena, RD_AutoCompListerItemChunkList *list); -internal int rd_autocomp_lister_item_qsort_compare(RD_AutoCompListerItem *a, RD_AutoCompListerItem *b); -internal void rd_autocomp_lister_item_array_sort__in_place(RD_AutoCompListerItemArray *array); - -internal String8 rd_autocomp_query_word_from_input_string_off(String8 input, U64 cursor_off); -internal String8 rd_autocomp_query_path_from_input_string_off(String8 input, U64 cursor_off); -internal RD_AutoCompListerParams rd_view_rule_autocomp_lister_params_from_input_cursor(Arena *arena, String8 string, U64 cursor_off); -internal void rd_set_autocomp_lister_query(UI_Key root_key, RD_AutoCompListerParams *params, String8 input, U64 cursor_off); - -//////////////////////////////// -//~ rjf: Search Strings - -internal void rd_set_search_string(String8 string); -internal String8 rd_push_search_string(Arena *arena); +internal void rd_set_autocomp_regs_(E_Eval dst_eval, RD_Regs *regs); +#define rd_set_autocomp_regs(dst_eval, ...) rd_set_autocomp_regs_((dst_eval), &(RD_Regs){rd_regs_lit_init_top __VA_ARGS__}) //////////////////////////////// //~ rjf: Colors, Fonts, Config -//- rjf: keybindings -internal OS_Key rd_os_key_from_cfg_string(String8 string); -internal void rd_clear_bindings(void); -internal RD_BindingList rd_bindings_from_name(Arena *arena, String8 name); -internal void rd_bind_name(String8 name, RD_Binding binding); -internal void rd_unbind_name(String8 name, RD_Binding binding); -internal String8List rd_cmd_name_list_from_binding(Arena *arena, RD_Binding binding); - //- rjf: colors -internal Vec4F32 rd_rgba_from_theme_color(RD_ThemeColor color); -internal RD_ThemeColor rd_theme_color_from_txt_token_kind(TXT_TokenKind kind); -internal RD_ThemeColor rd_theme_color_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string); +internal MD_Node *rd_theme_tree_from_name(Arena *arena, HS_Scope *scope, String8 theme_name); +internal Vec4F32 rd_rgba_from_code_color_slot(RD_CodeColorSlot slot); +internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind(TXT_TokenKind kind); +internal RD_CodeColorSlot rd_code_color_slot_from_txt_token_kind_lookup_string(TXT_TokenKind kind, String8 string); -//- rjf: code -> palette -internal UI_Palette *rd_palette_from_code(RD_PaletteCode code); - -//- rjf: fonts/sizes +//- rjf: fonts +internal F32 rd_font_size(void); internal FNT_Tag rd_font_from_slot(RD_FontSlot slot); -internal F32 rd_font_size_from_slot(RD_FontSlot slot); internal FNT_RasterFlags rd_raster_flags_from_slot(RD_FontSlot slot); -//- rjf: settings -internal RD_SettingVal rd_setting_val_from_code(RD_SettingCode code); - -//- rjf: config serialization -internal int rd_qsort_compare__cfg_string_bindings(RD_StringBindingPair *a, RD_StringBindingPair *b); -internal String8List rd_cfg_strings_from_gfx(Arena *arena, String8 root_path, RD_CfgSrc source); - //////////////////////////////// //~ rjf: Process Control Info Stringification internal String8 rd_string_from_exception_code(U32 code); -internal DR_FancyStringList rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event); +internal DR_FStrList rd_stop_explanation_fstrs_from_ctrl_event(Arena *arena, CTRL_Event *event); + +//////////////////////////////// +//~ rjf: Vocab Info Lookups + +internal RD_VocabInfo *rd_vocab_info_from_code_name(String8 code_name); +internal RD_VocabInfo *rd_vocab_info_from_code_name_plural(String8 code_name_plural); +#define rd_plural_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->code_name_plural) +#define rd_display_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->display_name) +#define rd_display_plural_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->display_name_plural) +#define rd_icon_kind_from_code_name(code_name) (rd_vocab_info_from_code_name(code_name)->icon_kind) +#define rd_singular_from_code_name_plural(code_name_plural) (rd_vocab_info_from_code_name_plural(code_name_plural)->code_name) //////////////////////////////// //~ rjf: Continuous Frame Requests @@ -1422,22 +1017,11 @@ internal void rd_request_frame(void); //- rjf: per-frame arena internal Arena *rd_frame_arena(void); -//- rjf: config paths -internal String8 rd_cfg_path_from_src(RD_CfgSrc src); - -//- rjf: entity cache queries -internal RD_EntityList rd_query_cached_entity_list_with_kind(RD_EntityKind kind); -internal RD_EntityList rd_push_active_target_list(Arena *arena); -internal RD_Entity *rd_entity_from_ev_key_and_kind(EV_Key key, RD_EntityKind kind); - -//- rjf: config state -internal RD_CfgTable *rd_cfg_table(void); - //////////////////////////////// //~ rjf: Registers -internal RD_Regs *rd_regs(void); -internal RD_Regs *rd_base_regs(void); +#define rd_regs() (&rd_state->top_regs->v) +#define rd_base_regs() (&rd_state->base_regs.v) internal RD_Regs *rd_push_regs_(RD_Regs *regs); #define rd_push_regs(...) rd_push_regs_(&(RD_Regs){rd_regs_lit_init_top __VA_ARGS__}) internal RD_Regs *rd_pop_regs(void); @@ -1457,6 +1041,7 @@ internal void rd_push_cmd(String8 name, RD_Regs *regs); //- rjf: iterating internal B32 rd_next_cmd(RD_Cmd **cmd); +internal B32 rd_next_view_cmd(RD_Cmd **cmd); //////////////////////////////// //~ rjf: Main Layer Top-Level Calls diff --git a/src/raddbg/raddbg_eval.c b/src/raddbg/raddbg_eval.c new file mode 100644 index 00000000..f67da862 --- /dev/null +++ b/src/raddbg/raddbg_eval.c @@ -0,0 +1,1707 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: `commands` Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(commands) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_MemberAccess) + { + String8 cmd_name = expr->first->next->string; + RD_CmdKindInfo *cmd_info = rd_cmd_kind_info_from_string(cmd_name); + E_TypeKey cmd_type = e_type_key_cons(.kind = E_TypeKind_U64, .name = str8_lit("command")); + cmd_type = e_type_key_cons_meta_description(cmd_type, cmd_info->description); + result.type_key = cmd_type; + result.mode = E_Mode_Value; + result.root = e_irtree_set_space(arena, e_space_make(RD_EvalSpaceKind_MetaCmd), e_irtree_const_u(arena, e_id_from_string(cmd_name))); + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands) +{ + E_TypeExpandInfo result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + String8List cmd_names = {0}; + E_Type *type = e_type_from_key(eval.irtree.type_key); + for EachNonZeroEnumVal(RD_CmdKind, k) + { + RD_CmdKindInfo *info = &rd_cmd_kind_info_table[k]; + if(info->flags & RD_CmdKindFlag_ListInUI && + (!str8_match(type->name, str8_lit("text_pt_commands"), 0) || info->flags & RD_CmdKindFlag_ListInTextPt) && + (!str8_match(type->name, str8_lit("text_range_commands"), 0) || info->flags & RD_CmdKindFlag_ListInTextRng) && + (!str8_match(type->name, str8_lit("tab_commands"), 0) || info->flags & RD_CmdKindFlag_ListInTab)) + { + String8 code_name = info->string; + String8 description = info->description; + String8 search_tags = info->search_tags; + String8 display_name = rd_display_from_code_name(code_name); + FuzzyMatchRangeList desc_matches = fuzzy_match_find(scratch.arena, filter, description); + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, display_name); + FuzzyMatchRangeList tags_matches = fuzzy_match_find(scratch.arena, filter, search_tags); + B32 binding_matches_good = 0; + RD_KeyMapNodePtrList bindings = rd_key_map_node_ptr_list_from_name(scratch.arena, code_name); + for(RD_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next) + { + String8 binding_text = os_string_from_modifiers_key(scratch.arena, n->v->binding.modifiers, n->v->binding.key); + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, binding_text); + if(matches.count == matches.needle_part_count) + { + binding_matches_good = 1; + break; + } + } + if(name_matches.count == name_matches.needle_part_count || + desc_matches.count == desc_matches.needle_part_count || + tags_matches.count == tags_matches.needle_part_count || + binding_matches_good) + { + str8_list_push(scratch.arena, &cmd_names, code_name); + } + } + } + String8Array *accel = push_array(arena, String8Array, 1); + *accel = str8_array_from_list(arena, &cmd_names); + result.user_data = accel; + result.expr_count = accel->count; + scratch_end(scratch); + } + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands) +{ + U64 out_idx = 0; + String8Array *accel = (String8Array *)user_data; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + String8 cmd_name = accel->v[idx]; + E_Eval cmd_eval = e_eval_from_stringf("query:commands.%S", cmd_name); + evals_out[out_idx] = cmd_eval; + } +} + +//////////////////////////////// +//~ rjf: `themes` Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(themes) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_ArrayIndex && + expr->first->next->kind == E_ExprKind_LeafStringLiteral) + { + String8 theme_name = expr->first->next->string; + E_TypeKey theme_type = e_type_key_cons(.kind = E_TypeKind_U64, .name = str8_lit("theme")); + result.type_key = theme_type; + result.mode = E_Mode_Value; + result.root = e_irtree_set_space(arena, e_space_make(RD_EvalSpaceKind_MetaTheme), e_irtree_const_u(arena, e_id_from_string(theme_name))); + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(themes) +{ + E_TypeExpandInfo result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: gather presets + String8List names = {0}; + for EachEnumVal(RD_ThemePreset, p) + { + String8 name = rd_theme_preset_display_string_table[p]; + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, name); + if(name_matches.count == name_matches.needle_part_count) + { + str8_list_push(scratch.arena, &names, name); + } + } + + //- rjf: gather theme files + { + String8 theme_folder = push_str8f(scratch.arena, "%S/raddbg/themes", os_get_process_info()->user_program_data_path); + OS_FileIter *it = os_file_iter_begin(scratch.arena, theme_folder, OS_FileIterFlag_SkipFolders); + for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, it, &info);) + { + String8 name = info.name; + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, name); + if(name_matches.count == name_matches.needle_part_count) + { + str8_list_push(scratch.arena, &names, push_str8_copy(arena, name)); + } + } + os_file_iter_end(it); + } + + //- rjf: flatten & build accelerator + String8Array *accel = push_array(arena, String8Array, 1); + *accel = str8_array_from_list(arena, &names); + result.user_data = accel; + result.expr_count = accel->count; + scratch_end(scratch); + } + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(themes) +{ + U64 out_idx = 0; + String8Array *accel = (String8Array *)user_data; + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + String8 name = accel->v[idx]; + evals_out[out_idx] = e_eval_wrapf(eval, "$[\"%S\"]", name); + } +} + +//////////////////////////////// +//~ rjf: `locals` Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(locals) +{ + E_TypeExpandInfo result = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + E_String2NumMapNodeArray nodes = e_string2num_map_node_array_from_map(scratch.arena, e_ir_ctx->locals_map); + e_string2num_map_node_array_sort__in_place(&nodes); + String8List exprs_filtered = {0}; + for EachIndex(idx, nodes.count) + { + String8 local_expr_string = nodes.v[idx]->string; + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, local_expr_string); + if(matches.count == matches.needle_part_count) + { + str8_list_push(scratch.arena, &exprs_filtered, local_expr_string); + } + } + String8Array *accel = push_array(arena, String8Array, 1); + *accel = str8_array_from_list(arena, &exprs_filtered); + result.user_data = accel; + result.expr_count = accel->count; + } + scratch_end(scratch); + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(locals) +{ + String8Array *accel = (String8Array *)user_data; + Rng1U64 legal_idx_range = r1u64(0, accel->count); + Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + String8 expr_string = accel->v[read_range.min + idx]; + evals_out[idx] = e_eval_from_string(expr_string); + } +} + +//////////////////////////////// +//~ rjf: `registers` Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers) +{ + Temp scratch = scratch_begin(&arena, 1); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); + Arch arch = thread->arch; + U64 reg_count = regs_reg_code_count_from_arch(arch); + U64 alias_count = regs_alias_code_count_from_arch(arch); + String8 *reg_strings = regs_reg_code_string_table_from_arch(arch); + String8 *alias_strings = regs_alias_code_string_table_from_arch(arch); + String8List exprs_list = {0}; + for(U64 idx = 1; idx < reg_count; idx += 1) + { + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, reg_strings[idx]); + if(matches.count == matches.needle_part_count) + { + str8_list_push(scratch.arena, &exprs_list, reg_strings[idx]); + } + } + for(U64 idx = 1; idx < alias_count; idx += 1) + { + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, alias_strings[idx]); + if(matches.count == matches.needle_part_count) + { + str8_list_push(scratch.arena, &exprs_list, alias_strings[idx]); + } + } + String8Array *accel = push_array(arena, String8Array, 1); + *accel = str8_array_from_list(arena, &exprs_list); + E_TypeExpandInfo info = {accel, accel->count}; + scratch_end(scratch); + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers) +{ + String8Array *accel = (String8Array *)user_data; + Rng1U64 legal_idx_range = r1u64(0, accel->count); + Rng1U64 read_range = intersect_1u64(legal_idx_range, idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + String8 register_name = accel->v[read_range.min + idx]; + String8 register_expr = push_str8f(arena, "reg:%S", register_name); + evals_out[idx] = e_eval_from_string(register_expr); + } +} + +//////////////////////////////// +//~ rjf: Schema Type Hooks + +typedef struct RD_SchemaIRExt RD_SchemaIRExt; +struct RD_SchemaIRExt +{ + RD_Cfg *cfg; + CTRL_Entity *entity; + MD_NodePtrList schemas; +}; + +E_TYPE_IREXT_FUNCTION_DEF(schema) +{ + RD_SchemaIRExt *ext = push_array(arena, RD_SchemaIRExt, 1); + { + Temp scratch = scratch_begin(&arena, 1); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + E_TypeKey type_key = irtree->type_key; + E_Type *type = e_type_from_key(type_key); + ext->cfg = rd_cfg_from_eval_space(interpret.space); + ext->entity = rd_ctrl_entity_from_eval_space(interpret.space); + ext->schemas = rd_schemas_from_name(type->name); + scratch_end(scratch); + } + E_IRExt result = {ext}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(schema) +{ + RD_SchemaIRExt *ext = (RD_SchemaIRExt *)lhs_irtree->user_data; + E_IRTreeAndType irtree = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_MemberAccess) + { + MD_Node *child_schema = &md_nil_node; + for(MD_NodePtrNode *n = ext->schemas.first; n != 0; n = n->next) + { + for MD_EachNode(child, n->v->first) + { + if(str8_match(child->string, expr->first->next->string, 0)) + { + child_schema = child; + break; + } + } + } + if(child_schema != &md_nil_node) + { + RD_Cfg *cfg = ext->cfg; + CTRL_Entity *entity = ext->entity; + RD_Cfg *child = rd_cfg_child_from_string(cfg, child_schema->string); + E_TypeKey child_type_key = zero_struct; + B32 wrap_child_w_meta_expr = 0; + if(0){} + + //- rjf: ctrl entity members + else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("label"), 0)) + { + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, E_TypeFlag_IsCodeText); + } + else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("exe"), 0)) + { + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), entity->string.size, E_TypeFlag_IsPathText); + } + else if(entity != &ctrl_entity_nil && str8_match(child_schema->string, str8_lit("dbg"), 0)) + { + CTRL_Entity *dbg = ctrl_entity_child_from_kind(entity, CTRL_EntityKind_DebugInfoPath); + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), dbg->string.size, E_TypeFlag_IsPathText); + } + + //- rjf: cfg members + else if(str8_match(child_schema->first->string, str8_lit("code_string"), 0) || + str8_match(child_schema->first->string, str8_lit("expr_string"), 0)) + { + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsCodeText); + } + else if(str8_match(child_schema->first->string, str8_lit("path"), 0) || + str8_match(child_schema->first->string, str8_lit("path_pt"), 0)) + { + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsPathText); + } + + else if(str8_match(child_schema->first->string, str8_lit("string"), 0)) + { + child_type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), child->first->string.size, E_TypeFlag_IsPlainText); + } + + //- rjf: catchall cases + else if(str8_match(child_schema->first->string, str8_lit("u64"), 0)) + { + child_type_key = e_type_key_basic(E_TypeKind_U64); + wrap_child_w_meta_expr = 1; + } + else if(str8_match(child_schema->first->string, str8_lit("u32"), 0)) + { + child_type_key = e_type_key_basic(E_TypeKind_U32); + wrap_child_w_meta_expr = 1; + } + else if(str8_match(child_schema->first->string, str8_lit("f32"), 0)) + { + child_type_key = e_type_key_basic(E_TypeKind_F32); + wrap_child_w_meta_expr = 1; + } + else if(str8_match(child_schema->first->string, str8_lit("bool"), 0)) + { + child_type_key = e_type_key_basic(E_TypeKind_Bool); + wrap_child_w_meta_expr = 1; + } + else if(str8_match(child_schema->first->string, str8_lit("vaddr_range"), 0)) + { + Temp scratch = scratch_begin(&arena, 1); + E_MemberList vaddr_range_members_list = {0}; + e_member_list_push_new(scratch.arena, &vaddr_range_members_list, .type_key = e_type_key_basic(E_TypeKind_U64), .name = str8_lit("min"), .off = 0); + e_member_list_push_new(scratch.arena, &vaddr_range_members_list, .type_key = e_type_key_basic(E_TypeKind_U64), .name = str8_lit("max"), .off = 8); + E_MemberArray vaddr_range_members = e_member_array_from_list(scratch.arena, &vaddr_range_members_list); + child_type_key = e_type_key_cons(.kind = E_TypeKind_Struct, .name = str8_lit("vaddr_range"), .count = vaddr_range_members.count, .members = vaddr_range_members.v); + scratch_end(scratch); + } + else if(str8_match(child_schema->first->string, str8_lit("query"), 0)) + { + child_type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, child_schema->string); + } + + //- rjf: extend child type with meta-expression information + if(wrap_child_w_meta_expr) + { + Temp scratch = scratch_begin(&arena, 1); + E_Expr *expr = e_parse_from_string(child->first->string).expr; + B32 expr_is_simple = 0; + if(expr->kind == E_ExprKind_LeafU64 || + expr->kind == E_ExprKind_LeafF64 || + expr->kind == E_ExprKind_LeafF32) + { + expr_is_simple = 1; + } + if((expr->kind == E_ExprKind_Pos || expr->kind == E_ExprKind_Neg) && + expr->first == expr->last && + (expr->first->kind == E_ExprKind_LeafU64 || + expr->first->kind == E_ExprKind_LeafF64 || + expr->first->kind == E_ExprKind_LeafF32)) + { + expr_is_simple = 1; + } + if(expr->kind == E_ExprKind_LeafIdentifier && + (str8_match(expr->string, str8_lit("true"), 0) || + str8_match(expr->string, str8_lit("false"), 0))) + { + expr_is_simple = 1; + } + if(!expr_is_simple && expr != &e_expr_nil) + { + child_type_key = e_type_key_cons_meta_expr(child_type_key, child->first->string); + } + scratch_end(scratch); + } + + //- rjf: extend child type with decorative meta info + { + MD_Node *display_name = md_tag_from_string(child_schema, str8_lit("display_name"), 0); + MD_Node *description = md_tag_from_string(child_schema, str8_lit("description"), 0); + if(!md_node_is_nil(display_name)) + { + child_type_key = e_type_key_cons_meta_display_name(child_type_key, display_name->first->string); + } + if(!md_node_is_nil(description)) + { + child_type_key = e_type_key_cons_meta_description(child_type_key, description->first->string); + } + } + + //- rjf: extend child type with hex lens + { + MD_Node *hex = md_tag_from_string(child_schema->first, str8_lit("hex"), 0); + if(!md_node_is_nil(hex)) + { + child_type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .name = str8_lit("hex"), + .direct_key = child_type_key); + } + } + + //- rjf: extend child type with color lens + { + MD_Node *color = md_tag_from_string(child_schema->first, str8_lit("color"), 0); + if(!md_node_is_nil(color)) + { + child_type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .name = str8_lit("color"), + .direct_key = child_type_key); + } + } + + //- rjf: extend child type with ranges + { + MD_Node *range = md_tag_from_string(child_schema->first, str8_lit("range"), 0); + if(!md_node_is_nil(range)) + { + E_Expr *min_bound = e_parse_from_string(range->first->string).expr; + E_Expr *max_bound = e_parse_from_string(range->first->next->string).expr; + E_Expr *args[] = + { + min_bound, + max_bound, + }; + child_type_key = e_type_key_cons(.kind = E_TypeKind_Lens, + .name = str8_lit("range1"), + .direct_key = child_type_key, + .count = 2, + .args = args); + } + } + + //- rjf: evaluate + E_Space child_eval_space = zero_struct; + if(cfg != &rd_nil_cfg) + { + child_eval_space = e_space_make(RD_EvalSpaceKind_MetaCfg); + child_eval_space.u64s[0] = cfg->id; + child_eval_space.u64s[1] = e_id_from_string(child_schema->string); + } + else + { + child_eval_space = rd_eval_space_from_ctrl_entity(entity, RD_EvalSpaceKind_MetaCtrlEntity); + child_eval_space.u64s[2] = e_id_from_string(child_schema->string); + } + irtree.root = e_irtree_set_space(arena, child_eval_space, e_push_irnode(arena, RDI_EvalOp_ConstU64)); + irtree.type_key = child_type_key; + irtree.mode = E_Mode_Offset; + } + } + return irtree; +} + +typedef struct RD_SchemaExpandAccel RD_SchemaExpandAccel; +struct RD_SchemaExpandAccel +{ + String8Array commands; + MD_Node **children; + U64 children_count; +}; + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(schema) +{ + E_TypeExpandInfo result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: unpack + RD_SchemaIRExt *ext = (RD_SchemaIRExt *)eval.irtree.user_data; + + // rjf: gather expansion commands + String8Array commands = {0}; + { + String8List commands_list = {0}; + for(MD_NodePtrNode *n = ext->schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + MD_Node *tag = md_tag_from_string(schema, str8_lit("expand_commands"), 0); + for MD_EachNode(arg, tag->first) + { + RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(arg->string); + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, rd_display_from_code_name(cmd_kind_info->string)); + FuzzyMatchRangeList desc_matches = fuzzy_match_find(scratch.arena, filter, cmd_kind_info->description); + FuzzyMatchRangeList tags_matches = fuzzy_match_find(scratch.arena, filter, cmd_kind_info->search_tags); + if(name_matches.count == name_matches.needle_part_count || + desc_matches.count == desc_matches.needle_part_count || + tags_matches.count == tags_matches.needle_part_count) + { + str8_list_push(scratch.arena, &commands_list, arg->string); + } + } + } + commands = str8_array_from_list(arena, &commands_list); + } + + // rjf: gather expansion children + typedef struct ExpandChildNode ExpandChildNode; + struct ExpandChildNode + { + ExpandChildNode *next; + MD_Node *n; + }; + ExpandChildNode *first_child_node = 0; + ExpandChildNode *last_child_node = 0; + U64 child_count = 0; + for(MD_NodePtrNode *n = ext->schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + for MD_EachNode(child, schema->first) + { + if(!md_node_has_tag(child, str8_lit("no_expand"), 0)) + { + MD_Node *expand_check = md_tag_from_string(child, str8_lit("expand_if"), 0); + B32 expand_this_child = 1; + if(!md_node_is_nil(expand_check)) E_ParentKey(eval.key) + { + expand_this_child = !!e_value_from_string(expand_check->first->string).u64; + } + if(expand_this_child) + { + String8 display_name = md_tag_from_string(child, str8_lit("display_name"), 0)->first->string; + if(display_name.size == 0) + { + display_name = rd_display_from_code_name(child->string); + } + String8 desc = md_tag_from_string(child, str8_lit("description"), 0)->first->string; + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, child->string); + FuzzyMatchRangeList display_name_matches = fuzzy_match_find(scratch.arena, filter, display_name); + FuzzyMatchRangeList desc_matches = fuzzy_match_find(scratch.arena, filter, desc); + if(name_matches.count == name_matches.needle_part_count || + display_name_matches.count == display_name_matches.needle_part_count || + desc_matches.count == desc_matches.needle_part_count) + { + ExpandChildNode *n = push_array(scratch.arena, ExpandChildNode, 1); + n->n = child; + SLLQueuePush(first_child_node, last_child_node, n); + child_count += 1; + } + } + } + } + } + + // rjf: flatten expansion member list + MD_Node **children = push_array(arena, MD_Node *, child_count); + { + U64 idx = 0; + for(ExpandChildNode *n = first_child_node; n != 0; n = n->next, idx += 1) + { + children[idx] = n->n; + } + } + + // rjf: build accelerator for lookups + RD_SchemaExpandAccel *accel = push_array(arena, RD_SchemaExpandAccel, 1); + accel->commands = commands; + accel->children = children; + accel->children_count = child_count; + + // rjf: fill result + result.user_data = accel; + result.expr_count = child_count + commands.count; + + scratch_end(scratch); + } + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(schema) +{ + RD_SchemaExpandAccel *accel = (RD_SchemaExpandAccel *)user_data; + Rng1U64 cmds_idx_range = r1u64(0, accel->commands.count); + Rng1U64 chld_idx_range = r1u64(cmds_idx_range.max, cmds_idx_range.max + accel->children_count); + U64 out_idx = 0; + + // rjf: read commands + { + Rng1U64 read_range = intersect_1u64(idx_range, cmds_idx_range); + for(U64 idx = read_range.min; idx < read_range.max; idx += 1, out_idx += 1) + { + evals_out[out_idx] = e_eval_from_stringf("query:commands.%S", accel->commands.v[idx - cmds_idx_range.min]); + } + } + + // rjf: read children + { + Rng1U64 read_range = intersect_1u64(idx_range, chld_idx_range); + for(U64 idx = read_range.min; idx < read_range.max; idx += 1, out_idx += 1) + { + MD_Node *child_schema = accel->children[idx - chld_idx_range.min]; + evals_out[out_idx] = e_eval_wrapf(eval, "$.%S", child_schema->string); + } + } +} + +//////////////////////////////// +//~ rjf: Config Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(cfgs) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + E_Expr *rhs = expr->first->next; + if(rhs->kind == E_ExprKind_LeafIdentifier && + str8_match(str8_prefix(rhs->string, 1), str8_lit("$"), 0)) + { + String8 numeric_part = str8_skip(rhs->string, 1); + RD_CfgID id = u64_from_str8(numeric_part, 16); + RD_Cfg *cfg = rd_cfg_from_id(id); + E_Space space = rd_eval_space_from_cfg(cfg); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); + result.type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, cfg->string); + result.mode = E_Mode_Offset; + } + return result; +} + +//////////////////////////////// +//~ rjf: Control Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(control) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + E_Expr *rhs = expr->first->next; + if(rhs->kind == E_ExprKind_LeafIdentifier && + str8_match(str8_prefix(rhs->string, 1), str8_lit("$"), 0)) + { + CTRL_Handle handle = ctrl_handle_from_string(rhs->string); + CTRL_Entity *entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, handle); + E_Space space = rd_eval_space_from_ctrl_entity(entity, RD_EvalSpaceKind_MetaCtrlEntity); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); + result.type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, ctrl_entity_kind_code_name_table[entity->kind]); + result.mode = E_Mode_Offset; + } + return result; +} + +//////////////////////////////// +//~ rjf: Config Collection Type Hooks + +typedef struct RD_CfgsIRExt RD_CfgsIRExt; +struct RD_CfgsIRExt +{ + String8 cfg_name; + String8Array cmds; + RD_CfgArray cfgs; + Rng1U64 cmds_idx_range; + Rng1U64 cfgs_idx_range; +}; + +E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice) +{ + RD_CfgsIRExt *ext = push_array(arena, RD_CfgsIRExt, 1); + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: determine which key we'll be gathering + E_TypeKey type_key = irtree->type_key; + E_Type *type = e_type_from_key(type_key); + String8 cfg_name = rd_singular_from_code_name_plural(type->name); + + //- rjf: gather cfgs + RD_CfgList cfgs_list = rd_cfg_top_level_list_from_string(scratch.arena, cfg_name); + + //- rjf: gather commands + String8List cmds_list = {0}; + { + MD_NodePtrList schemas = rd_schemas_from_name(cfg_name); + for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + MD_Node *collection_cmds_root = md_tag_from_string(schema, str8_lit("collection_commands"), 0); + for MD_EachNode(cmd, collection_cmds_root->first) + { + str8_list_push(arena, &cmds_list, cmd->string); + } + } + } + + //- rjf: package & fill + ext->cfg_name = cfg_name; + ext->cfgs = rd_cfg_array_from_list(arena, &cfgs_list); + ext->cmds = str8_array_from_list(arena, &cmds_list); + + scratch_end(scratch); + } + E_IRExt result = {ext}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + RD_Cfg *cfg = &rd_nil_cfg; + RD_CfgsIRExt *ext = (RD_CfgsIRExt *)lhs_irtree->user_data; + switch(expr->kind) + { + default:{}break; + case E_ExprKind_ArrayIndex: + { + E_Value rhs_value = e_value_from_expr(expr->first->next); + U64 rhs_idx = rhs_value.u64; + if(0 <= rhs_idx && rhs_idx < ext->cfgs.count) + { + cfg = ext->cfgs.v[rhs_idx]; + } + }break; + case E_ExprKind_MemberAccess: + { + String8 rhs_name = expr->first->next->string; + RD_CfgID id = 0; + if(str8_match(str8_prefix(rhs_name, 1), str8_lit("$"), 0)) + { + id = u64_from_str8(str8_skip(rhs_name, 1), 16); + cfg = rd_cfg_from_id(id); + } + }break; + } + if(cfg != &rd_nil_cfg) + { + result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); + result.mode = E_Mode_Offset; + result.type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, ext->cfg_name); + } + return result; +} + +typedef struct RD_CfgsExpandAccel RD_CfgsExpandAccel; +struct RD_CfgsExpandAccel +{ + String8Array cmds; + RD_CfgArray cfgs; + Rng1U64 cmds_idx_range; + Rng1U64 cfgs_idx_range; +}; + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_slice) +{ + RD_CfgsExpandAccel *accel = push_array(arena, RD_CfgsExpandAccel, 1); + E_TypeExpandInfo info = {accel}; + Temp scratch = scratch_begin(&arena, 1); + { + //- rjf: unpack + RD_CfgsIRExt *ext = (RD_CfgsIRExt *)eval.irtree.user_data; + + //- rjf: filter cfgs + RD_CfgArray cfgs__filtered = ext->cfgs; + if(filter.size != 0) + { + RD_CfgList cfgs_list__filtered = {0}; + for EachIndex(idx, ext->cfgs.count) + { + RD_Cfg *cfg = ext->cfgs.v[idx]; + DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, cfg); + String8 string = dr_string_from_fstrs(scratch.arena, &fstrs); + FuzzyMatchRangeList fuzzy_matches = fuzzy_match_find(scratch.arena, filter, string); + if(fuzzy_matches.count == fuzzy_matches.needle_part_count) + { + rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, cfg); + } + } + cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered); + } + + //- rjf: fill + if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) == &rd_nil_cfg) + { + accel->cmds = ext->cmds; + accel->cmds_idx_range = r1u64(0, accel->cmds.count); + } + accel->cfgs = cfgs__filtered; + accel->cfgs_idx_range = r1u64(accel->cmds_idx_range.max, accel->cmds_idx_range.max + accel->cfgs.count); + info.expr_count = (accel->cmds.count + accel->cfgs.count); + } + scratch_end(scratch); + return info; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query) +{ + RD_CfgsExpandAccel *accel = push_array(arena, RD_CfgsExpandAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + RD_Cfg *root_cfg = rd_cfg_from_eval_space(eval.space); + String8 child_key = e_string_from_id(eval.space.u64s[1]); + String8 child_key_singular = rd_singular_from_code_name_plural(child_key); + if(child_key_singular.size != 0) + { + child_key = child_key_singular; + } + String8List cmds = {0}; + MD_NodePtrList schemas = rd_schemas_from_name(child_key); + for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + MD_Node *collection_cmds_root = md_tag_from_string(schema, str8_lit("collection_commands"), 0); + for MD_EachNode(cmd, collection_cmds_root->first) + { + str8_list_push(scratch.arena, &cmds, cmd->string); + } + } + RD_CfgList children = rd_cfg_child_list_from_string(scratch.arena, root_cfg, child_key); + RD_CfgList children__filtered = children; + if(filter.size != 0) + { + MemoryZeroStruct(&children__filtered); + for(RD_CfgNode *n = children.first; n != 0; n = n->next) + { + DR_FStrList cfg_fstrs = rd_title_fstrs_from_cfg(scratch.arena, n->v); + String8 cfg_string = dr_string_from_fstrs(scratch.arena, &cfg_fstrs); + FuzzyMatchRangeList ranges = fuzzy_match_find(scratch.arena, filter, cfg_string); + if(ranges.count == ranges.needle_part_count) + { + rd_cfg_list_push(scratch.arena, &children__filtered, n->v); + } + } + } + accel->cmds = str8_array_from_list(arena, &cmds); + accel->cmds_idx_range = r1u64(0, accel->cmds.count); + accel->cfgs = rd_cfg_array_from_list(arena, &children__filtered); + accel->cfgs_idx_range = r1u64(accel->cmds.count + 0, accel->cmds.count + accel->cfgs.count); + scratch_end(scratch); + } + E_TypeExpandInfo info = {accel, accel->cfgs.count + accel->cmds.count}; + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(cfgs_slice) +{ + RD_CfgsExpandAccel *accel = (RD_CfgsExpandAccel *)user_data; + Rng1U64 cmds_idx_range = accel->cmds_idx_range; + Rng1U64 cfgs_idx_range = accel->cfgs_idx_range; + U64 dst_idx = 0; + + // rjf: fill commands + { + Rng1U64 read_range = intersect_1u64(cmds_idx_range, idx_range); + U64 read_count = dim_1u64(read_range); + E_Eval cmds_eval = e_eval_from_stringf("query:commands"); + for(U64 idx = 0; idx < read_count; idx += 1, dst_idx += 1) + { + String8 cmd_name = accel->cmds.v[idx + read_range.min - cmds_idx_range.min]; + E_Eval cmd_eval = e_eval_wrapf(cmds_eval, "$.%S", cmd_name); + evals_out[dst_idx] = cmd_eval; + } + } + + // rjf: fill cfgs + { + Rng1U64 read_range = intersect_1u64(cfgs_idx_range, idx_range); + U64 read_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_count; idx += 1, dst_idx += 1) + { + RD_Cfg *cfg = accel->cfgs.v[idx + read_range.min - cfgs_idx_range.min]; + evals_out[dst_idx] = e_eval_from_stringf("query:config.$%I64x", cfg->id); + } + } +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(cfgs_slice) +{ + U64 id = 0; + RD_CfgsExpandAccel *accel = (RD_CfgsExpandAccel *)user_data; + if(num != 0) + { + U64 idx = num-1; + if(contains_1u64(accel->cfgs_idx_range, idx)) + { + RD_Cfg *cfg = accel->cfgs.v[idx - accel->cfgs_idx_range.min]; + id = cfg->id; + } + else if(contains_1u64(accel->cmds_idx_range, idx)) + { + id = num; + id |= (1ull<<63); + } + } + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(cfgs_slice) +{ + U64 num = 0; + RD_CfgsExpandAccel *accel = (RD_CfgsExpandAccel *)user_data; + if(id != 0) + { + if(id & (1ull<<63)) + { + num = id; + num &= ~(1ull<<63); + } + else for EachIndex(idx, accel->cfgs.count) + { + if(accel->cfgs.v[idx]->id == id) + { + num = idx + accel->cfgs_idx_range.min + 1; + break; + } + } + } + return num; +} + +//////////////////////////////// +//~ rjf: `call_stack` Type Hooks + +typedef struct RD_CallStackAccel RD_CallStackAccel; +struct RD_CallStackAccel +{ + Arch arch; + CTRL_Handle process; + CTRL_CallStack call_stack; +}; + +E_TYPE_IREXT_FUNCTION_DEF(call_stack) +{ + RD_CallStackAccel *accel = push_array(arena, RD_CallStackAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interp = e_interpret(bytecode); + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(interp.space); + if(entity->kind == CTRL_EntityKind_Thread) + { + B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); + accel->arch = entity->arch; + accel->process = ctrl_process_from_entity(entity)->handle; + accel->call_stack = ctrl_call_stack_from_thread(rd_state->frame_ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + } + scratch_end(scratch); + } + E_IRExt result = {accel}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(call_stack) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_ArrayIndex) + { + RD_CallStackAccel *accel = (RD_CallStackAccel *)lhs_irtree->user_data; + E_Value rhs_value = e_value_from_expr(expr->first->next); + CTRL_CallStack *call_stack = &accel->call_stack; + if(0 <= rhs_value.u64 && rhs_value.u64 < call_stack->frames_count) + { + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, accel->process); + CTRL_CallStackFrame *f = &call_stack->frames[rhs_value.u64]; + result.root = e_irtree_set_space(arena, rd_eval_space_from_ctrl_entity(process, RD_EvalSpaceKind_CtrlEntity), e_irtree_const_u(arena, regs_rip_from_arch_block(accel->arch, f->regs))); + result.type_key = e_type_key_cons(.arch = process->arch, .kind = E_TypeKind_Ptr, .direct_key = e_type_key_basic(E_TypeKind_Function), .count = 1, .depth = f->inline_depth); + result.mode = E_Mode_Value; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack) +{ + RD_CallStackAccel *accel = (RD_CallStackAccel *)eval.irtree.user_data; + E_TypeExpandInfo result = {0}; + result.user_data = accel; + result.expr_count = accel->call_stack.frames_count; + return result; +} + +//////////////////////////////// +//~ rjf: `environment` Type Hooks + +typedef struct RD_EnvironmentAccel RD_EnvironmentAccel; +struct RD_EnvironmentAccel +{ + RD_CfgArray cfgs; +}; + +E_TYPE_IREXT_FUNCTION_DEF(environment) +{ + RD_EnvironmentAccel *accel = push_array(arena, RD_EnvironmentAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + E_Space space = interpret.space; + RD_Cfg *target = rd_cfg_from_eval_space(space); + RD_CfgList env_strings = {0}; + for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("environment"), 0)) + { + rd_cfg_list_push(scratch.arena, &env_strings, child); + } + } + accel->cfgs = rd_cfg_array_from_list(arena, &env_strings); + scratch_end(scratch); + } + E_IRExt result = {accel}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(environment) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_ArrayIndex) + { + RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)lhs_irtree->user_data; + RD_CfgArray *cfgs = &accel->cfgs; + E_Value rhs_value = e_value_from_expr(expr->first->next); + if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count) + { + RD_Cfg *cfg = cfgs->v[rhs_value.u64]; + result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); + result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText); + result.mode = E_Mode_Offset; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(environment) +{ + RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)eval.irtree.user_data; + E_TypeExpandInfo result = {accel, accel->cfgs.count + 1}; + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(environment) +{ + RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)user_data; + Rng1U64 legal_idx_range = r1u64(0, accel->cfgs.count); + Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + U64 cfg_idx = read_range.min + idx; + if(cfg_idx < accel->cfgs.count) + { + evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", cfg_idx); + } + } +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(environment) +{ + U64 id = 0; + RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)user_data; + if(1 <= num && num <= accel->cfgs.count) + { + U64 idx = (num-1); + id = accel->cfgs.v[idx]->id; + } + else if(num == accel->cfgs.count+1) + { + id = max_U64; + } + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment) +{ + U64 num = 0; + RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)user_data; + if(id != 0 && id != max_U64) + { + for EachIndex(idx, accel->cfgs.count) + { + if(accel->cfgs.v[idx]->id == id) + { + num = idx+1; + break; + } + } + } + else if(id == max_U64) + { + num = accel->cfgs.count + 1; + } + return num; +} + +//////////////////////////////// +//~ rjf: `watches` Type Hooks + +typedef struct RD_WatchesAccel RD_WatchesAccel; +struct RD_WatchesAccel +{ + RD_CfgArray cfgs; +}; + +E_TYPE_IREXT_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1); + { + Temp scratch = scratch_begin(&arena, 1); + E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + E_Space space = interpret.space; + RD_Cfg *target = rd_cfg_from_eval_space(space); + RD_CfgList env_strings = {0}; + for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next) + { + if(str8_match(child->string, str8_lit("watch"), 0)) + { + rd_cfg_list_push(scratch.arena, &env_strings, child); + } + } + accel->cfgs = rd_cfg_array_from_list(arena, &env_strings); + scratch_end(scratch); + } + E_IRExt result = {accel}; + return result; +} + +E_TYPE_ACCESS_FUNCTION_DEF(watches) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_ArrayIndex) + { + RD_WatchesAccel *accel = (RD_WatchesAccel *)lhs_irtree->user_data; + RD_CfgArray *cfgs = &accel->cfgs; + E_Value rhs_value = e_value_from_expr(expr->first->next); + if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count) + { + RD_Cfg *cfg = cfgs->v[rhs_value.u64]; + result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0)); + result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText); + result.mode = E_Mode_Offset; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *ext = (RD_WatchesAccel *)eval.irtree.user_data; + RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1); + { + RD_CfgArray cfgs__filtered = ext->cfgs; + if(filter.size != 0) + { + Temp scratch = scratch_begin(&arena, 1); + RD_CfgList cfgs_list__filtered = {0}; + for EachIndex(idx, ext->cfgs.count) + { + RD_Cfg *watch = ext->cfgs.v[idx]; + String8 string = watch->first->string; + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, string); + if(matches.count == matches.needle_part_count) + { + rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, watch); + } + } + cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered); + scratch_end(scratch); + } + accel->cfgs = cfgs__filtered; + } + E_TypeExpandInfo result = {accel, accel->cfgs.count + 1}; + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches) +{ + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + Rng1U64 legal_idx_range = r1u64(0, accel->cfgs.count); + Rng1U64 read_range = intersect_1u64(idx_range, legal_idx_range); + U64 read_range_count = dim_1u64(read_range); + for(U64 idx = 0; idx < read_range_count; idx += 1) + { + U64 cfg_idx = read_range.min + idx; + if(cfg_idx < accel->cfgs.count) + { + RD_Cfg *cfg = accel->cfgs.v[cfg_idx]; + evals_out[idx] = e_eval_from_string(cfg->first->string); + } + } +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches) +{ + U64 id = 0; + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + if(1 <= num && num <= accel->cfgs.count) + { + U64 idx = (num-1); + id = accel->cfgs.v[idx]->id; + } + else if(num == accel->cfgs.count+1) + { + id = max_U64; + } + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches) +{ + U64 num = 0; + RD_WatchesAccel *accel = (RD_WatchesAccel *)user_data; + if(id != 0 && id != max_U64) + { + for EachIndex(idx, accel->cfgs.count) + { + if(accel->cfgs.v[idx]->id == id) + { + num = idx+1; + break; + } + } + } + else if(id == max_U64) + { + num = accel->cfgs.count + 1; + } + return num; +} + +//////////////////////////////// +//~ rjf: `unattached_processes` Type Hooks + +typedef struct RD_UnattachedProcessesAccel RD_UnattachedProcessesAccel; +struct RD_UnattachedProcessesAccel +{ + DMN_ProcessInfo *infos; + CTRL_Entity **machines; + U64 infos_count; +}; + +E_TYPE_ACCESS_FUNCTION_DEF(unattached_processes) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + if(expr->kind == E_ExprKind_MemberAccess) + { + Temp scratch = scratch_begin(&arena, 1); + + // rjf: extract pid / name id from access string + U64 pid = 0; + U64 string_id = 0; + { + String8 pid_string = {0}; + String8 name_id_string = {0}; + U8 split_char = '$'; + String8List parts = str8_split(scratch.arena, expr->first->next->string, &split_char, 1, 0); + if(parts.first != 0 && parts.first->next != 0) + { + pid_string = parts.first->string; + name_id_string = parts.first->next->string; + pid = u64_from_str8(pid_string, 16); + string_id = u64_from_str8(name_id_string, 16); + } + } + + // rjf: get machine entity from space + E_OpList oplist = e_oplist_from_irtree(scratch.arena, lhs_irtree->root); + String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); + E_Interpretation interpret = e_interpret(bytecode); + CTRL_Entity *machine = rd_ctrl_entity_from_eval_space(interpret.space); + + // rjf: build evaluation for this unattached process + if(machine != &ctrl_entity_nil) + { + E_IRNode *value_irnode = e_push_irnode(arena, RDI_EvalOp_ConstU128); + value_irnode->value.u128.u64[0] = pid; + value_irnode->value.u128.u64[1] = string_id; + E_Space space = rd_eval_space_from_ctrl_entity(machine, RD_EvalSpaceKind_MetaUnattachedProcess); + result.root = e_irtree_set_space(arena, space, value_irnode); + result.type_key = e_type_key_basic(E_TypeKind_U128); + result.mode = E_Mode_Value; + } + + scratch_end(scratch); + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(unattached_processes) +{ + E_TypeExpandInfo info = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: evaluate lhs machine, if we have one + CTRL_Entity *lhs_entity = rd_ctrl_entity_from_eval_space(eval.space); + + //- rjf: gather all machines we're searching through + CTRL_EntityArray machines = {0}; + if(lhs_entity->kind == CTRL_EntityKind_Machine) + { + machines.v = &lhs_entity; + machines.count = 1; + } + else + { + machines = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Machine); + } + + //- rjf: gather system processes from this machine + typedef struct Node Node; + struct Node + { + Node *next; + CTRL_Entity *machine; + DMN_ProcessInfo info; + }; + Node *first = 0; + Node *last = 0; + U64 count = 0; + for EachIndex(idx, machines.count) + { + CTRL_Entity *machine = machines.v[idx]; + DMN_ProcessIter iter = {0}; + dmn_process_iter_begin(&iter); + for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &iter, &info);) + { + B32 passes_filter = 1; + if(filter.size != 0) + { + passes_filter = 0; + FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, info.name); + FuzzyMatchRangeList pid_matches = fuzzy_match_find(scratch.arena, filter, push_str8f(scratch.arena, "%I64u", info.pid)); + if(name_matches.count == name_matches.needle_part_count || pid_matches.count == pid_matches.needle_part_count) + { + passes_filter = 1; + } + } + if(passes_filter) + { + Node *node = push_array(scratch.arena, Node, 1); + SLLQueuePush(first, last, node); + node->machine = machine; + node->info = info; + count += 1; + } + } + dmn_process_iter_end(&iter); + } + + //- rjf: list -> array + U64 infos_count = count; + DMN_ProcessInfo *infos = push_array(arena, DMN_ProcessInfo, infos_count); + CTRL_Entity **infos_machines = push_array(arena, CTRL_Entity *, infos_count); + { + U64 idx = 0; + for(Node *n = first; n != 0; n = n->next, idx += 1) + { + infos[idx] = n->info; + infos[idx].name = push_str8_copy(arena, infos[idx].name); + infos_machines[idx] = n->machine; + } + } + + //- rjf: build accelerator + RD_UnattachedProcessesAccel *accel = push_array(arena, RD_UnattachedProcessesAccel, 1); + accel->infos = infos; + accel->infos_count = infos_count; + accel->machines = infos_machines; + info.user_data = accel; + info.expr_count = infos_count; + scratch_end(scratch); + } + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(unattached_processes) +{ + RD_UnattachedProcessesAccel *accel = (RD_UnattachedProcessesAccel *)user_data; + U64 out_idx = 0; + E_TypeKey unattached_process_type = e_type_key_cons(.kind = E_TypeKind_U128, .name = str8_lit("unattached_process")); + for(U64 idx = idx_range.min; idx < idx_range.max; idx += 1, out_idx += 1) + { + CTRL_Entity *machine = accel->machines[idx]; + String8 string = ctrl_string_from_handle(arena, machine->handle); + evals_out[out_idx] = e_eval_wrapf(eval, "query:control.%S.unattached_processes.$%I64x$%I64x", string, accel->infos[idx].pid, e_id_from_string(accel->infos[idx].name)); + } +} + +//////////////////////////////// +//~ rjf: Control Entity List Type Hooks (`processes`, `threads`, etc.) + +E_TYPE_ACCESS_FUNCTION_DEF(ctrl_entities) +{ + E_IRTreeAndType result = {&e_irnode_nil}; + { + CTRL_Entity *entity = &ctrl_entity_nil; + switch(expr->kind) + { + case E_ExprKind_MemberAccess: + { + String8 rhs_name = expr->first->next->string; + CTRL_Handle handle = ctrl_handle_from_string(rhs_name); + entity = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, handle); + }break; + case E_ExprKind_ArrayIndex: + { + E_Type *type = e_type_from_key(lhs_irtree->type_key); + CTRL_EntityKind kind = ctrl_entity_kind_from_string(rd_singular_from_code_name_plural(type->name)); + E_Value rhs_value = e_value_from_expr(expr->first->next); + U64 rhs_idx = rhs_value.u64; + CTRL_EntityArray entities = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, kind); + if(0 <= rhs_idx && rhs_idx < entities.count) + { + entity = entities.v[rhs_idx]; + } + }break; + } + if(entity != &ctrl_entity_nil) + { + E_Space space = rd_eval_space_from_ctrl_entity(entity, RD_EvalSpaceKind_MetaCtrlEntity); + String8 name = ctrl_entity_kind_code_name_table[entity->kind]; + E_TypeKey type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, name); + result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0)); + result.type_key = type_key; + result.mode = E_Mode_Offset; + } + } + return result; +} + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(ctrl_entities) +{ + E_TypeExpandInfo result = {0}; + Temp scratch = scratch_begin(&arena, 1); + { + //- rjf: determine which entity we're looking under + CTRL_Entity *scoping_entity = &ctrl_entity_nil; + if(eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity) + { + scoping_entity = rd_ctrl_entity_from_eval_space(eval.space); + } + + //- rjf: determine which type of child we're gathering + E_TypeKey lhs_type_key = eval.irtree.type_key; + E_Type *lhs_type = e_type_from_key(lhs_type_key); + String8 name = rd_singular_from_code_name_plural(lhs_type->name); + CTRL_EntityKind entity_kind = ctrl_entity_kind_from_string(name); + + //- rjf: gather array of all entities which fit the bill + CTRL_EntityArray array = {0}; + if(scoping_entity == &ctrl_entity_nil) + { + array = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, entity_kind); + } + else + { + CTRL_EntityList list = {0}; + for(CTRL_Entity *child = scoping_entity->first; child != &ctrl_entity_nil; child = child->next) + { + if(child->kind == entity_kind) + { + ctrl_entity_list_push(scratch.arena, &list, child); + } + } + array = ctrl_entity_array_from_list(arena, &list); + } + + //- rjf: filter the array + CTRL_EntityArray array__filtered = array; + if(filter.size != 0) + { + CTRL_EntityList list__filtered = {0}; + for EachIndex(idx, array.count) + { + CTRL_Entity *entity = array.v[idx]; + DR_FStrList fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, entity, 1); + String8 title_string = dr_string_from_fstrs(scratch.arena, &fstrs); + FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, title_string); + if(matches.count == matches.needle_part_count) + { + ctrl_entity_list_push(scratch.arena, &list__filtered, entity); + } + } + array__filtered = ctrl_entity_array_from_list(arena, &list__filtered); + } + + //- rjf: list -> array & fill + CTRL_EntityArray *accel = push_array(arena, CTRL_EntityArray, 1); + *accel = array__filtered; + result.user_data = accel; + result.expr_count = accel->count; + } + scratch_end(scratch); + return result; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities) +{ + CTRL_EntityArray *entities = (CTRL_EntityArray *)user_data; + Rng1U64 legal_range = r1u64(0, entities->count); + Rng1U64 read_range = intersect_1u64(legal_range, idx_range); + U64 read_count = dim_1u64(read_range); + for(U64 out_idx = 0; out_idx < read_count; out_idx += 1) + { + Temp scratch = scratch_begin(&arena, 1); + CTRL_Entity *entity = entities->v[out_idx + read_range.min]; + evals_out[out_idx] = e_eval_from_stringf("query:control.%S", ctrl_string_from_handle(scratch.arena, entity->handle)); + scratch_end(scratch); + } +} + +//////////////////////////////// +//~ rjf: Debug Info Tables Eval Hooks + +typedef struct RD_DebugInfoTableLookupAccel RD_DebugInfoTableLookupAccel; +struct RD_DebugInfoTableLookupAccel +{ + RDI_SectionKind section; + U64 rdis_count; + RDI_Parsed **rdis; + DI_SearchItemArray items; +}; + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table) +{ + Temp scratch = scratch_begin(&arena, 1); + + // rjf: determine which debug info section we're dealing with + RDI_SectionKind section = RDI_SectionKind_NULL; + { + E_TypeKey lhs_type_key = eval.irtree.type_key; + E_Type *lhs_type = e_type_from_key(lhs_type_key); + if(0){} + else if(str8_match(lhs_type->name, str8_lit("procedures"), 0)) {section = RDI_SectionKind_Procedures;} + else if(str8_match(lhs_type->name, str8_lit("globals"), 0)) {section = RDI_SectionKind_GlobalVariables;} + else if(str8_match(lhs_type->name, str8_lit("thread_locals"), 0)) {section = RDI_SectionKind_ThreadVariables;} + else if(str8_match(lhs_type->name, str8_lit("types"), 0)) {section = RDI_SectionKind_UDTs;} + } + + // rjf: gather debug info table items + RD_DebugInfoTableLookupAccel *accel = push_array(arena, RD_DebugInfoTableLookupAccel, 1); + if(section != RDI_SectionKind_NULL) + { + U64 endt_us = rd_state->frame_eval_memread_endt_us; + + //- rjf: unpack context + DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena); + DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); + U64 rdis_count = dbgi_keys.count; + RDI_Parsed **rdis = push_array(arena, RDI_Parsed *, rdis_count); + for(U64 idx = 0; idx < rdis_count; idx += 1) + { + rdis[idx] = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_keys.v[idx], endt_us); + } + + //- rjf: query all filtered items from dbgi searching system + U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section}; + B32 items_stale = 0; + DI_SearchParams params = {section, dbgi_keys}; + accel->section = section; + accel->rdis_count = rdis_count; + accel->rdis = rdis; + accel->items = di_search_items_from_key_params_query(rd_state->frame_di_scope, fuzzy_search_key, ¶ms, filter, endt_us, &items_stale); + if(items_stale) + { + rd_request_frame(); + } + } + E_TypeExpandInfo info = {accel, accel->items.count}; + scratch_end(scratch); + return info; +} + +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table) +{ + Temp scratch = scratch_begin(&arena, 1); + RD_DebugInfoTableLookupAccel *accel = (RD_DebugInfoTableLookupAccel *)user_data; + U64 needed_row_count = dim_1u64(idx_range); + for EachIndex(idx, needed_row_count) + { + // rjf: unpack row + DI_SearchItem *item = &accel->items.v[idx_range.min + idx]; + + // rjf: skip bad elements + if(item->dbgi_idx >= accel->rdis_count) + { + continue; + } + + // rjf: unpack row info + RDI_Parsed *rdi = accel->rdis[item->dbgi_idx]; + E_Module *module = &e_base_ctx->modules[item->dbgi_idx]; + + // rjf: get item's string + String8 item_string = {0}; + { + U64 element_idx = item->idx; + switch(accel->section) + { + default:{}break; + case RDI_SectionKind_Procedures: + { + RDI_Procedure *procedure = rdi_element_from_name_idx(module->rdi, Procedures, element_idx); + RDI_Scope *scope = rdi_element_from_name_idx(module->rdi, Scopes, procedure->root_scope_idx); + U64 voff = *rdi_element_from_name_idx(module->rdi, ScopeVOffData, scope->voff_range_first); + E_OpList oplist = {0}; + e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff)); + String8 bytecode = e_bytecode_from_oplist(arena, &oplist); + U32 type_idx = procedure->type_idx; + RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx); + E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_base_ctx->modules)); + String8 symbol_name = {0}; + symbol_name.str = rdi_string_from_idx(module->rdi, procedure->name_string_idx, &symbol_name.size); + item_string = symbol_name; + }break; + case RDI_SectionKind_GlobalVariables: + { + RDI_GlobalVariable *gvar = rdi_element_from_name_idx(module->rdi, GlobalVariables, element_idx); + String8 symbol_name = {0}; + symbol_name.str = rdi_string_from_idx(module->rdi, gvar->name_string_idx, &symbol_name.size); + item_string = symbol_name; + }break; + case RDI_SectionKind_ThreadVariables: + { + RDI_ThreadVariable *tvar = rdi_element_from_name_idx(module->rdi, ThreadVariables, element_idx); + String8 symbol_name = {0}; + symbol_name.str = rdi_string_from_idx(module->rdi, tvar->name_string_idx, &symbol_name.size); + item_string = symbol_name; + }break; + case RDI_SectionKind_UDTs: + { + RDI_UDT *udt = rdi_element_from_name_idx(module->rdi, UDTs, element_idx); + RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, udt->self_type_idx); + String8 name = {0}; + name.str = rdi_string_from_idx(module->rdi, type_node->user_defined.name_string_idx, &name.size); + item_string = name; + }break; + } + } + + // rjf: build a valid expression string given item string + String8 item_expr = item_string; + { + B32 string_can_be_evalled = 1; + E_TokenArray tokens = e_token_array_from_text(scratch.arena, item_string); + for EachIndex(idx, tokens.count) + { + String8 token_string = str8_substr(item_string, tokens.v[idx].range); + if(tokens.v[idx].kind != E_TokenKind_Identifier && + !str8_match(token_string, str8_lit("."), 0)) + { + string_can_be_evalled = 0; + break; + } + } + if(!string_can_be_evalled) + { + item_expr = push_str8f(scratch.arena, "`%S`", item_string); + } + } + + // rjf: item's eval + E_Eval item_eval = e_eval_from_string(item_expr); + + // rjf: fill + evals_out[idx] = item_eval; + temp_end(scratch); + } + scratch_end(scratch); +} + +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table) +{ + RD_DebugInfoTableLookupAccel *accel = (RD_DebugInfoTableLookupAccel *)user_data; + U64 id = 0; + if(0 < num && num <= accel->items.count) + { + id = accel->items.v[num-1].idx+1; + } + return id; +} + +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(debug_info_table) +{ + RD_DebugInfoTableLookupAccel *accel = (RD_DebugInfoTableLookupAccel *)user_data; + U64 num = di_search_item_num_from_array_element_idx__linear_search(&accel->items, id-1); + return num; +} diff --git a/src/raddbg/raddbg_eval.h b/src/raddbg/raddbg_eval.h new file mode 100644 index 00000000..c866f317 --- /dev/null +++ b/src/raddbg/raddbg_eval.h @@ -0,0 +1,111 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_EVAL_H +#define RADDBG_EVAL_H + +//////////////////////////////// +//~ rjf: `commands` Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(commands); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(commands); + +//////////////////////////////// +//~ rjf: `themes` Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(themes); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(themes); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(themes); + +//////////////////////////////// +//~ rjf: `locals` Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(locals); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(locals); + +//////////////////////////////// +//~ rjf: `registers` Type Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers); + +//////////////////////////////// +//~ rjf: Schema Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(schema); +E_TYPE_ACCESS_FUNCTION_DEF(schema); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(schema); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(schema); + +//////////////////////////////// +//~ rjf: Config Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(cfgs); + +//////////////////////////////// +//~ rjf: Control Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(control); + +//////////////////////////////// +//~ rjf: Config Slice Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query); +E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_slice); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(cfgs_slice); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(cfgs_slice); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(cfgs_slice); + +//////////////////////////////// +//~ rjf: `call_stack` Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(call_stack); +E_TYPE_ACCESS_FUNCTION_DEF(call_stack); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack); + +//////////////////////////////// +//~ rjf: `environment` Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(environment); +E_TYPE_ACCESS_FUNCTION_DEF(environment); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(environment); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(environment); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(environment); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment); + +//////////////////////////////// +//~ rjf: `watches` Type Hooks + +E_TYPE_IREXT_FUNCTION_DEF(watches); +E_TYPE_ACCESS_FUNCTION_DEF(watches); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(watches); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(watches); + +//////////////////////////////// +//~ rjf: `unattached_processes` Type Hooks + +E_TYPE_ACCESS_FUNCTION_DEF(unattached_processes); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(unattached_processes); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(unattached_processes); + +//////////////////////////////// +//~ rjf: Control Entity List Type Hooks (`processes`, `threads`, etc.) + +E_TYPE_ACCESS_FUNCTION_DEF(ctrl_entities); +E_TYPE_EXPAND_INFO_FUNCTION_DEF(ctrl_entities); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(ctrl_entities); + +//////////////////////////////// +//~ rjf: Debug Info Tables Eval Hooks + +E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table); +E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table); +E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table); +E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(debug_info_table); + +#endif // RADDBG_EVAL_H diff --git a/src/raddbg/raddbg_inc.c b/src/raddbg/raddbg_inc.c index 07842d04..ece449df 100644 --- a/src/raddbg/raddbg_inc.c +++ b/src/raddbg/raddbg_inc.c @@ -2,5 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "raddbg_core.c" +#include "raddbg_eval.c" #include "raddbg_widgets.c" #include "raddbg_views.c" +#include "raddbg_legacy_config.c" diff --git a/src/raddbg/raddbg_inc.h b/src/raddbg/raddbg_inc.h index 46cb0ece..deca7cb0 100644 --- a/src/raddbg/raddbg_inc.h +++ b/src/raddbg/raddbg_inc.h @@ -5,7 +5,9 @@ #define RADDBG_INC_H #include "raddbg_core.h" +#include "raddbg_eval.h" #include "raddbg_widgets.h" #include "raddbg_views.h" +#include "raddbg_legacy_config.h" #endif // RADDBG_INC_H diff --git a/src/raddbg/raddbg_legacy_config.c b/src/raddbg/raddbg_legacy_config.c new file mode 100644 index 00000000..119ea215 --- /dev/null +++ b/src/raddbg/raddbg_legacy_config.c @@ -0,0 +1,69 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal RD_CfgList +rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data) +{ + RD_CfgList result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + String8 folder_path = str8_skip_last_slash(file_path); + MD_Node *src_root = md_parse_from_text(scratch.arena, file_path, data).root; + { + for MD_EachNode(tln, src_root->first) + { + //- rjf: targets + if(str8_match(tln->string, str8_lit("target"), 0)) + { + String8 disabled_string = md_child_from_string(tln, str8_lit("disabled"), 0)->first->string; + String8 executable = md_child_from_string(tln, str8_lit("executable"), 0)->first->string; + String8 arguments = md_child_from_string(tln, str8_lit("arguments"), 0)->first->string; + String8 working_directory = md_child_from_string(tln, str8_lit("working_directory"), 0)->first->string; + String8 entry_point = md_child_from_string(tln, str8_lit("entry_point"), 0)->first->string; + String8 stdout_path = md_child_from_string(tln, str8_lit("stdout_path"), 0)->first->string; + String8 stderr_path = md_child_from_string(tln, str8_lit("stderr_path"), 0)->first->string; + String8 stdin_path = md_child_from_string(tln, str8_lit("stdin_path"), 0)->first->string; + String8 debug_subprocesses= md_child_from_string(tln, str8_lit("debug_subprocesses"), 0)->first->string; + RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, str8_lit("target")); + rd_cfg_list_push(arena, &result, dst_root); + { + if(executable.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("executable")), path_absolute_dst_from_relative_dst_src(scratch.arena, executable, folder_path)); } + if(arguments.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("arguments")), raw_from_escaped_str8(scratch.arena, arguments)); } + if(working_directory.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("working_directory")), path_absolute_dst_from_relative_dst_src(scratch.arena, working_directory, folder_path)); } + if(entry_point.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("entry_point")), raw_from_escaped_str8(scratch.arena, entry_point)); } + if(stdout_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdout_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdout_path, folder_path)); } + if(stderr_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stderr_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stderr_path, folder_path)); } + if(stdin_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdin_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdin_path, folder_path)); } + if(debug_subprocesses.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("debug_subprocesses")), raw_from_escaped_str8(scratch.arena, debug_subprocesses)); } + if(!str8_match(disabled_string, str8_lit("1"), 0)) + { + rd_cfg_new(rd_cfg_new(dst_root, str8_lit("enabled")), str8_lit("1")); + } + } + } + + //- rjf: recent files / projects + if(str8_match(tln->string, str8_lit("recent_file"), 0) || + str8_match(tln->string, str8_lit("recent_project"), 0)) + { + RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string); + rd_cfg_list_push(arena, &result, dst_root); + rd_cfg_new(rd_cfg_new(dst_root, str8_lit("path")), path_absolute_dst_from_relative_dst_src(scratch.arena, tln->first->string, folder_path)); + } + + //- rjf: file path maps + if(str8_match(tln->string, str8_lit("file_path_map"), 0)) + { + String8 source = md_child_from_string(tln, str8_lit("source"), 0)->first->string; + String8 dest = md_child_from_string(tln, str8_lit("dest"), 0)->first->string; + RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string); + rd_cfg_list_push(arena, &result, dst_root); + rd_cfg_new(rd_cfg_new(dst_root, str8_lit("source")), path_absolute_dst_from_relative_dst_src(scratch.arena, source, folder_path)); + rd_cfg_new(rd_cfg_new(dst_root, str8_lit("dest")), path_absolute_dst_from_relative_dst_src(scratch.arena, dest, folder_path)); + } + } + } + scratch_end(scratch); + } + return result; +} diff --git a/src/raddbg/raddbg_legacy_config.h b/src/raddbg/raddbg_legacy_config.h new file mode 100644 index 00000000..31d2f8da --- /dev/null +++ b/src/raddbg/raddbg_legacy_config.h @@ -0,0 +1,9 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBG_LEGACY_CONFIG_H +#define RADDBG_LEGACY_CONFIG_H + +internal RD_CfgList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data); + +#endif // RADDBG_LEGACY_CONFIG_H diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index e47ebe6e..9243b825 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -2,95 +2,72 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: feature cleanup, code dedup, code elimination pass: -// -// [ ] frontend config entities, serialization/deserialization, remove hacks, -// etc. - the entity structure should be dramatically simplified & made -// to reflect a more flexible string-tree data structure which can be -// more trivially derived from config, and more flexibly rearranged. -// drag/drop watch rows -> tabs, tabs -> watch rows, etc. -// [ ] frontend entities need to be the "upstream state" for windows, panels, -// tabs, etc. - entities can be mapped to caches of window/panel/view state -// in purely immediate-mode fashion, so the only *state* part of the -// equation only has to do with the string tree. -// [ ] config hot-reloading using the wins from the previous points -// [ ] undo/redo, using the wins from the previous points -// [ ] watch table UI - hidden table boundaries, special-cased control hacks -// [ ] hash store -> need to somehow hold on to hash blobs which are still -// depended upon by usage layers, e.g. extra dependency refcount, e.g. -// text cache can explicitly correllate nodes in its cache to hashes, -// bump their refcount - this would keep the hash correllated to its key -// and it would prevent it from being evicted (output debug string perf) -// [ ] autocompletion lister, file lister, function lister, command lister, -// etc., all need to be merged, and optionally contextualized/filtered. -// right-clicking a tab should be equivalent to spawning a command lister, -// but only with commands that are directly +//~ rjf: 0.9.18 Release Notes +/* +- Adjusted identifier resolution rules in the evaluation language to prefer visualizer names when used in a call expression. For example, even if you have a variable named `bitmap`, if you evaluate `bitmap(...)`, it will prefer resolving `bitmap` to the visualizer. You can still always disambiguate with qualifiers, e.g. `local:bitmap` or `type:bitmap`. +- Adjusted the `only` view to allow arbitrary derivative expressions, rather than only member names. This allows custom expansions to insert rows for arbitrary expressions. These expressions are derivative from the expanded expression, meaning they can refer to the expanded expression via `$`, or implicitly, its member names. +- Renamed the `table` view to `columns`, and the `only` view to `rows`, since these more directly reflect the way these views are used in the evaluation visualization pipeline. +- Added an option to all text views to scroll to the bottom if the textual content changes at all. Can be used with the `Output` tab. +- Improved toggle switches to allow clicking and dragging to toggle many switches in a single operation. +- The debugger now records the last user file which was loaded while it was opened, and reopens that file on startup, if no user is explicitly specified. (#482) + - The debugger now unfocuses query bars (e.g. that opened by `Ctrl + F` in a source view) if the main view content is clicked by the mouse. The query bar can be refocused also by clicking. + - Moved call stack evaluation to occur asynchronously, so that deeper call stacks (which can be expensive to compute) do not block the UI. + - Stopped the debugger from running the default Windows message handling path for most `Alt`-based keybindings, which was causing a Windows beep sound to play. +- Fixed a bug where RDI files would sometimes fail to generate, resulting in no debug info being available on some runs. + - Fixed a bug which was preventing backslashes from working in file system querying interfaces correctly. + - Fixed a bug which was preventing some recursive call stacks from fully displaying in the debugger. + - Fixed a bug which prevented `Space` from being used as a keybinding. Bound `Space` by default to the `Accept` command (to which `Enter` / `Return` is also defaultly bound). + - Fixed a bug which was preventing conditional breakpoints from correctly being placed, if the condition expression did not evaluate when the debuggees were resumed. + - Fixed the debugger applying too much path processing, which was causing relative paths in debug info to be interpreted incorrectly. The debugger should now work much better with relative paths (e.g. produced via `/d1trimfile`). In these cases, the debugger may still not be able to fully compute the correct absolute paths, because this information is not stored within debug information. But once the debugger is redirected to the correct file once through the UI, it should work with relative paths correctly. + - If the debugger crashes, the message box which opens and displays the crash call stack now also allows the creation of crash dump files. Please submit these, if possible, with crash reports; it will help us to debug crashes more effectively. + - Fixed a bug which was causing text rendering to fail both when running the debugger on WINE and also on Windows 7. +- Fixed a bug where exception information inlined in source code would overlap the source code text. +- The debugger now correctly correctly interprets relative per-target `stdout`, `stderr`, and `stdin` paths. +*/ //////////////////////////////// -//~ rjf: post-0.9.12 TODO notes +//~ rjf: post-0.9.16 TODO notes // +//- watch improvements +// [ ] *ALL* expressions in watch windows need to be editable. +// +//- cfg improvements +// [ ] config hot-reloading, using cfg wins +// [ ] undo/redo, using cfg wins +// [ ] back/forward, using cfg wins +// [ ] mouse back button should make view to go back after I double clicked +// on function to open it +// +//- stepping or breakpoint oddness/fixes +// [ ] stepping-onto a line with a conditional breakpoint, which fails, causes a +// single step over the first instruction of that line, even if the thread +// would've stopped at the first instruction due to the step, were that bp not +// there. +// [ ] if a breakpoint matches the entry point's starting address, its hit count +// is not correctly incremented. // [ ] breakpoints in optimized code? maybe early-terminating bp resolution loop? @bpmiss // - actually this seems to be potentially because of incomplete src-line-map info... // [ ] Mohit-reported breakpoint not hitting - may be similar thing to @bpmiss // -// [ ] CLI argument over-mangling? -// -// [ ] OutputDebugString spam, keeping way too much around! -// -// [ ] fix light themes -// [ ] make `array` view rule work with actual array types, to change their -// size dynamically -// -// -// [ ] auto view rule templates (?) -// [ ] single-line visualization busted with auto-view-rules applied, it seems... -// not showing member variables, just commas, check w/ mohit -// [ ] auto-view-rules likely should apply at each level in the expression -// tree -// [ ] `slice` view rule - extend to support begin/end style as well -// [ ] disasm starting address - need to use debug info for more correct -// results... -// -// [ ] linked list view rule -// -// [ ] investigate false exceptions, being reported while stepping through init code -// [ ] output: add option for scroll-to-bottom - ensure this shows up in universal ctx menu -// -// [ ] EVAL LOOKUP RULES -> currently going 0 -> rdis_count, but we need -// to prioritize the primary rdi -// -// [ ] (reported by forrest) 'set-next-statement' -> prioritize current -// module/symbol, in cases where one line maps to many voffs -// -// [ ] collapse upstream state for theme/bindings/settings into entities; use cache accelerators if needed to make up difference -// [ ] collapse upstream state for windows/panels/tabs into entities; use downstream window/view resource cache to make up the difference -// [ ] entity <-> mdesk paths -// -// [ ] universal ctx menu address/watch options; e.g. watch -> memory; watch -> add watch -// [ ] rich hover coverage; bitmap <-> geo <-> memory <-> disassembly <-> text; etc. -// -// [ ] save view column pcts; generalize to being a first-class thing in -// RD_View, e.g. by just having a string -> f32 store -// -// [ ] visualize all breakpoints everywhere - source view should show up in -// disasm, disasm should show up in source view, function should show up in -// both, etc. -// [ ] ** Function breakpoints should show up in the source listing. Without -// them being visible, it is confusing when you run and you stop there, -// because you're like "wait why did it stop" and then you later remember -// that's because there was a function breakpoint there. - -//////////////////////////////// -//~ rjf: Frontend/UI Pass Tasks -// -// [ ] transient view timeout releasing -// [ ] theme lister -> fonts & font sizes +//- ui improvements +// [ ] we probably want to disable pop/pull out for transient things, e.g. theme color cfgs +// (actually, just kill the tabs on load if they refer to transient things) +// [ ] universal ctx menu address/watch options; e.g. watch -> memory; watch -> add watch +// [ ] rich hover coverage; bitmap <-> geo <-> memory <-> disassembly <-> text; etc. +// [ ] tooltip coverage pass (row commands, etc.) +// [ ] visualize all breakpoints everywhere - source view should show up in +// disasm, disasm should show up in source view, function should show up in +// both, etc. +// [ ] ** Function breakpoints should show up in the source listing. Without +// them being visible, it is confusing when you run and you stop there, +// because you're like "wait why did it stop" and then you later remember +// that's because there was a function breakpoint there. +// [ ] (reported by forrest) 'set-next-statement' -> prioritize current +// module/symbol, in cases where one line maps to many voffs // [ ] "Browse..." buttons should adopt a more relevant starting search path, // if possible -// -// [ ] font lister -// [ ] per-panel font size overrides -// +// [ ] (since browse buttons are currently gone i should just add them backin +// while respecting this old todo) // [ ] For the Scheduler window, it would be nice if you could dim or // folderize threads that are not your threads - eg., if a thread doesn't // have any resolved stack pointers in your executable code, then you can @@ -100,98 +77,22 @@ // threads you haven't? Or, there could even be a debugger-specific API // that you use to tag them. Just some way that would make it easier to // focus on your own threads. - -//////////////////////////////// -//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) -// -// [ ] Setting the code_font/main_font values to a font name doesn't work. -// Should probably make note that you have to set it to a path to a TTF, -// since that's not normally how Windows fonts work. -// -// [ ] "root" concept in hash store, which buckets keys & allows usage code to -// jettison a collection of keys in retained mode fashion -// -// [ ] Jeff Notes -// [ ] sort locals by appearance in source code (or maybe just debug info) -// [ ] sum view rule -// [ ] plot view rule -// [ ] histogram view rule -// [ ] max view rule -// [ ] min view rule -// -// [ ] double-click vs. single-click for folder navigation, see if we can infer // [ ] use backslashes on windows by default, forward slashes elsewhere (?) -// -// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not -// support it? -// -// -// [ ] visualize conversion failures -// -// [ ] I was a little confused about what a profile file was. I understood -// what the user file was, but the profile file sounded like it should -// perhaps be per-project, yet it sounded like it was meant to be somewhat -// global? I don't have any feedback here because it probably will make -// sense once I use the debugger more, but I just thought I'd make a note -// to say that I was confused about it after reading the manual, so -// perhaps you could elaborate a little more on it in there. -// [ ] It wasn't clear to me how you save a user or project file. I can see -// how to load them, but not how you save them. Obviously I can just copy -// the files myself in the shell, but it seemed weird that there was no -// "save" option in the menus. -// -// [ ] Right-clicking on a thread in the Scheduler window pops up a context -// menu, but you can't actually see it because the tooltip for the thread -// draws on top of it, so you can't see the menu. -// -// [ ] In a "hover watch" (where you hover over a variable and it shows a pop- -// up watch window), if you expand an item near the bottom of the listing, -// it will be clipped to the bottom of the listing instead of showing the -// actual items (ie., it doesn't resize the listing based on what's -// actually visible) -// -// [ ] ** One very nice feature of RemedyBG that I use all the time is the -// ability to put "$err, hr" into the watch window, which will just show -// the value of GetLastError() as a string. This is super useful for -// debugging, so you don't have to litter your own code with it. -// (NOTE(rjf): NtQueryInformationThread) -// -// [ ] Tooltip Coverage: -// [ ] lock icon -// [ ] "rotation arrow" icon next to executables -// -// [ ] For theme editing, when you hove the mouse over a theme color entry and -// it highlights that entry, it might help to temporarily change that -// color to white (or the inverse of the background color, or whatever) so -// that the user can see what things on the screen use that theme color. -// -// [ ] I had to go into the user file to change the font. That should probably -// be in the theme window? -// -// [ ] It'd be nice to have a "goto byte" option for source views, for jumping -// to error messages that are byte-based instead of line-based. -// -// [ ] @feature debug info overrides (both path-based AND module-based) -// -// [ ] C++ virtual inheritance member visualization in watch window - -//////////////////////////////// -//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup) -// -// [ ] The hex format for color values in the config file was a real -// mindbender. It's prefixed with "0x", so I was assuming it was either -// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To -// my surprise, it was neither - it was actually web format (RRGGBBAA), -// which I was not expecting because that is normally written with a -// number sign (#AARRGGBB) not an 0x. -// +// [ ] For theme editing, when you hove the mouse over a theme color entry and +// it highlights that entry, it might help to temporarily change that +// color to white (or the inverse of the background color, or whatever) so +// that the user can see what things on the screen use that theme color. +// [ ] The hex format for color values in the config file was a real +// mindbender. It's prefixed with "0x", so I was assuming it was either +// Windows Big Endian (0xAARRGGBB) or Mac Little Endian (0xAABBGGRR). To +// my surprise, it was neither - it was actually web format (RRGGBBAA), +// which I was not expecting because that is normally written with a +// number sign (#AARRGGBB) not an 0x. +// [ ] It'd be nice to have a "goto byte" option for source views, for jumping +// to error messages that are byte-based instead of line-based. // [ ] Clicking on either side of a scroll bar is idiosyncratic. Normally, // that is "page up" / "page down", but here it is "smooth scroll upward" // / "smooth scroll downward" for some reason? -// -// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions? -// [ ] mouse back button should make view to go back after I double clicked -// on function to open it // [ ] Alt+8 to switch to disassembly would be nice (regardless on which // panel was previous, don't want to use ctrl+, multiple times) // Alt+8 for disasm and Alt+6 for memory view are shortcuts I often use @@ -199,110 +100,92 @@ // [ ] default font size is too small for me - not only source code, but // menus/tab/watch names (which don't resize). Maybe you could query // Windows for initial font size? -// [ ] Jump table thunks, on code w/o /INCREMENTAL:NO - -//////////////////////////////// -//~ rjf: Hot, Feature Tasks (Not really "low priority" but less urgent than fixes) -// -// [ ] @eval_upgrade -// [ ] new eval system; support strings, many address spaces, many debug -// infos, wide/async transforms (e.g. diff(blob1, blob2)) -// -// [ ] Fancy View Rules -// [ ] table column boundaries should be checked against *AFTER* table -// contents, not before -// [ ] `array:(x, y)` - multidimensional array -// -// [ ] search-in-all-files -// -// [ ] Memory View -// [ ] memory view mutation controls -// [ ] memory view user-made annotations -// -// [ ] undo/redo -// [ ] proper "go back" + "go forward" history navigations -// [ ] undo close tab would be nice. If not for everything, then at least -// just for source files -// // [ ] globally disable/configure default view rule-like things (string // viz for u8s in particular) -// -// [ ] @feature processor/data breakpoints -// [ ] @feature automatically snap to search matches when searching source files -// [ ] automatically start search query with selected text - -//////////////////////////////// -//~ rjf: Cold, Clean-up Tasks That Probably Only Ryan Notices -// (E.G. Because They Are Code-Related Or Because Nobody Cares) -// -// [ ] @bug view-snapping in scroll-lists, accounting for mapping between -// visual positions & logical positions (variably sized rows in watch, -// table headers, etc.) -// [ ] @cleanup straighten out index/number space & types & terminology for -// scroll lists -// [ ] @cleanup eliminate explicit font parameters in the various ui paths (e.g. -// code slice params) - -//////////////////////////////// -//~ rjf: Cold, Unsorted Notes (Deferred Until Existing Lists Mostly Exhausted) -// -// [ ] @feature disasm view improvement features -// [ ] visualize jump destinations in disasm -// -// [ ] @feature eval ui improvement features -// [ ] serializing eval view maps -// [ ] view rule editors in hover-eval -// [ ] view rule hook coverage -// [ ] `each:(expr addition)` - apply some additional expression to all -// elements in an array/linked list would be useful to look at only a -// subset of an array of complex structs -// [ ] `slider:(min max)` view rule -// [ ] `v2f32` view rule -// [ ] `v3` view rule -// [ ] `quat` view rule -// [ ] `matrix` view rule -// [ ] `audio` waveform view rule -// [ ] smart scopes - expression operators for "grab me the first type X" -// [ ] "pinning" watch expressions, to attach it to a particular ctrl_ctx -// -// [ ] @feature header file for target -> debugger communication; printf, log, -// etc. -// [ ] @feature just-in-time debugging -// [ ] @feature step-out-of-loop -// -//-[ ] long-term future notes from martins -// [ ] core dump saving/loading -// [ ] parallel call stacks view -// [ ] parallel watch view -// [ ] mixed native/interpreted/jit debugging -// - it seems python has a top-level linked list of interpreter states, -// which should allow the debugger to map native callstacks to python -// code -// // [ ] fancy string runs can include "weakness" information for text truncation // ... can prioritize certain parts of strings to be truncated before // others. would be good for e.g. the middle of a path +// +//- visualizer improvements +// [ ] disasm starting address - need to use debug info for more correct results... +// [ ] linked list view +// [ ] output: add option for scroll-to-bottom - ensure this shows up in universal ctx menu +// [ ] multidimensional `array` +// [ ] 2-vector, 3-vector, quaternion +// [ ] audio waveform views +// +//- eval improvements +// [ ] maybe add extra caching layer to process memory querying? we pay a pretty +// heavy cost even to just read 8 bytes... +// [ ] evaluate `foo.bar` symbol names without escape hatch? +// [ ] serializing eval view maps (?) +// [ ] EVAL LOOKUP RULES -> currently going 0 -> rdis_count, but we need +// to prioritize the primary rdi +// [ ] wide transforms +// [ ] sum +// [ ] plot +// [ ] max view rule +// [ ] min view rule +// [ ] histogram view rule +// [ ] diffs? +// [ ] ** One very nice feature of RemedyBG that I use all the time is the +// ability to put "$err, hr" into the watch window, which will just show +// the value of GetLastError() as a string. This is super useful for +// debugging, so you don't have to litter your own code with it. +// (NOTE(rjf): NtQueryInformationThread) +// [ ] C++ virtual inheritance member visualization +// [ ] smart scopes - expression operators for "grab me the first type X" +// [ ] "pinning" watch expressions, to attach it to a particular scope/evaluation context +// +//- control improvements +// [ ] debug info overrides (both path-based AND module-based) +// [ ] symbol server +// [ ] can it ignore stepping into _RTC_CheckStackVars generated functions? +// [ ] jump table thunks, on code w/o /INCREMENTAL:NO +// [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not +// support it? +// [ ] just-in-time debugging +// [ ] step-out-of-loop +// +//- late-conversion performance improvements +// [ ] investigate wide-conversion performance +// [ ] oversubscribing cores? +// [ ] conversion crashes? +// [ ] fastpath lookup to determine debug info relevance? +// [ ] live++ investigations - ctrl+alt+f11 in UE? +// +//- memory usage improvements +// [ ] "root" concept in hash store, which buckets keys & allows usage code to +// jettison a collection of keys in retained mode fashion +// +//- short-to-medium term future features +// [ ] search-in-all-files +// [ ] automatically snap to search matches when searching source files +// [ ] memory view +// [ ] memory view mutation controls +// [ ] memory view user-made annotations +// [ ] memory view searching +// [ ] disasm view +// [ ] visualize jump destinations in disasm +// +//- longer-term future features +// [ ] long-term future notes from martins +// [ ] core dump saving/loading +// [ ] parallel call stacks view +// [ ] parallel watch view +// [ ] mixed native/interpreted/jit debugging +// - it seems python has a top-level linked list of interpreter states, +// which should allow the debugger to map native callstacks to python +// code +// +//- code cleanup +// [ ] eliminate explicit font parameters in the various ui paths (e.g. +// code slice params) // [ ] font cache eviction (both for font tags, closing fp handles, and // rasterizations) -// [ ] frontend speedup opportunities -// [ ] tables in UI -> currently building per-row, could probably cut down on -// # of boxes and # of draws by doing per-column in some cases? -// [ ] font cache layer -> can probably cache (string*font*size) -> (run) too -// (not just rasterization)... would save a *lot*, there is a ton of work -// just in looking up & stitching stuff repeatedly -// [ ] convert UI layout pass to not be naive recursive version -// [ ] (big change) parallelize window ui build codepaths per-panel //////////////////////////////// //~ rjf: Recently Completed Task Log -// -// [x] filesystem drag/drop support -// [x] ** Converter performance & heuristics for asynchronously doing it early -// [x] icon fonts glyphs sometimes disappear for specific font size, but they -// reappear if you go +1 higher or -1 lower. Mostly red triangle in watch -// values for "unknown identifier". But also yellow arrow in call stack -// disappears if font size gets too large. -// [x] @cleanup central worker thread pool - eliminate per-layer thread pools //////////////////////////////// //~ rjf: Build Options @@ -324,8 +207,6 @@ //- rjf: [lib] #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" -#include "lib_raddbg_markup/raddbg_markup.h" -#include "lib_raddbg_markup/raddbg_markup.c" //- rjf: [h] #include "base/base_inc.h" @@ -601,106 +482,58 @@ entry_point(CmdLine *cmd_line) String8List args = cmd_line->inputs; if(args.node_count > 0 && args.first->string.size != 0) { - //- TODO(rjf): @cfg setup initial target from command line arguments + Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack command line inputs + String8 executable_name_string = {0}; + String8 arguments_string = {0}; + String8 working_directory_string = {0}; { - Temp scratch = scratch_begin(0, 0); - - //- rjf: unpack command line inputs - String8 executable_name_string = {0}; - String8 arguments_string = {0}; - String8 working_directory_string = {0}; + // rjf: unpack full executable path + if(args.first->string.size != 0) { - // rjf: unpack full executable path - if(args.first->string.size != 0) + String8 exe_name = args.first->string; + PathStyle style = path_style_from_str8(exe_name); + if(style == PathStyle_Relative) { String8 current_path = os_get_current_path(scratch.arena); - String8 exe_name = args.first->string; - PathStyle style = path_style_from_str8(exe_name); - if(style == PathStyle_Relative) - { - exe_name = push_str8f(scratch.arena, "%S/%S", current_path, exe_name); - exe_name = path_normalized_from_string(scratch.arena, exe_name); - } - executable_name_string = exe_name; + exe_name = push_str8f(scratch.arena, "%S/%S", current_path, exe_name); + exe_name = path_normalized_from_string(scratch.arena, exe_name); } - - // rjf: unpack working directory - if(args.first->string.size != 0) - { - String8 path_part_of_arg = str8_chop_last_slash(args.first->string); - if(path_part_of_arg.size != 0) - { - String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); - working_directory_string = path; - } - } - - // rjf: unpack arguments - String8List passthrough_args_list = {0}; - for(String8Node *n = args.first->next; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &passthrough_args_list, n->string); - } - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - arguments_string = str8_list_join(scratch.arena, &passthrough_args_list, &join); + executable_name_string = exe_name; } - //- rjf: build config tree - RD_Cfg *command_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); - RD_Cfg *target = rd_cfg_new(command_line_root, str8_lit("target")); - RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); - RD_Cfg *args = rd_cfg_new(target, str8_lit("arguments")); - RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); - rd_cfg_new(exe, executable_name_string); - rd_cfg_new(args, arguments_string); - rd_cfg_new(wdir, working_directory_string); - - scratch_end(scratch); - } - - Temp scratch = scratch_begin(0, 0); - RD_Entity *target = rd_entity_alloc(rd_entity_root(), RD_EntityKind_Target); - rd_entity_equip_cfg_src(target, RD_CfgSrc_CommandLine); - String8List passthrough_args_list = {0}; - for(String8Node *n = args.first->next; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &passthrough_args_list, n->string); - } - - // rjf: get current path - String8 current_path = os_get_current_path(scratch.arena); - - // rjf: equip exe - if(args.first->string.size != 0) - { - String8 exe_name = args.first->string; - RD_Entity *exe = rd_entity_alloc(target, RD_EntityKind_Executable); - PathStyle style = path_style_from_str8(exe_name); - if(style == PathStyle_Relative) + // rjf: unpack working directory + if(args.first->string.size != 0) { - exe_name = push_str8f(scratch.arena, "%S/%S", current_path, exe_name); - exe_name = path_normalized_from_string(scratch.arena, exe_name); + String8 path_part_of_arg = str8_chop_last_slash(args.first->string); + if(path_part_of_arg.size != 0) + { + String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); + working_directory_string = path; + } } - rd_entity_equip_name(exe, exe_name); + + // rjf: unpack arguments + String8List passthrough_args_list = {0}; + for(String8Node *n = args.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &passthrough_args_list, n->string); + } + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + arguments_string = str8_list_join(scratch.arena, &passthrough_args_list, &join); } - // rjf: equip working directory - String8 path_part_of_arg = str8_chop_last_slash(args.first->string); - if(path_part_of_arg.size != 0) - { - String8 path = push_str8f(scratch.arena, "%S/", path_part_of_arg); - RD_Entity *wdir = rd_entity_alloc(target, RD_EntityKind_WorkingDirectory); - rd_entity_equip_name(wdir, path); - } + //- rjf: build config tree + RD_Cfg *command_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); + RD_Cfg *target = rd_cfg_new(command_line_root, str8_lit("target")); + RD_Cfg *exe = rd_cfg_new(target, str8_lit("executable")); + RD_Cfg *args = rd_cfg_new(target, str8_lit("arguments")); + RD_Cfg *wdir = rd_cfg_new(target, str8_lit("working_directory")); + rd_cfg_new(exe, executable_name_string); + rd_cfg_new(args, arguments_string); + rd_cfg_new(wdir, working_directory_string); - // rjf: equip args - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - String8 args_str = str8_list_join(scratch.arena, &passthrough_args_list, &join); - if(args_str.size != 0) - { - RD_Entity *args_entity = rd_entity_alloc(target, RD_EntityKind_Arguments); - rd_entity_equip_name(args_entity, args_str); - } scratch_end(scratch); } } @@ -719,8 +552,11 @@ entry_point(CmdLine *cmd_line) ipc_s2m_ring_mutex = os_mutex_alloc(); ipc_s2m_ring_cv = os_condition_variable_alloc(); IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - MemoryZeroStruct(ipc_info); - os_thread_launch(ipc_signaler_thread__entry_point, 0, 0); + if(ipc_shared_memory_base != 0) + { + MemoryZeroStruct(ipc_info); + os_thread_launch(ipc_signaler_thread__entry_point, 0, 0); + } scratch_end(scratch); } @@ -752,29 +588,33 @@ entry_point(CmdLine *cmd_line) if(msg.size != 0) { log_infof("ipc_msg: \"%S\"", msg); - RD_Window *dst_window = rd_state->first_window; - for(RD_Window *window = dst_window; window != 0; window = window->next) + RD_WindowState *dst_ws = rd_state->first_window_state; + for(RD_WindowState *ws = dst_ws; ws != &rd_nil_window_state; ws = ws->order_next) { - if(os_window_is_focused(window->os)) + if(os_window_is_focused(ws->os)) { - dst_window = window; + dst_ws = ws; break; } } - if(dst_window != 0) + if(dst_ws != &rd_nil_window_state) { - dst_window->window_temporarily_focused_ipc = 1; + dst_ws->window_temporarily_focused_ipc = 1; U64 first_space_pos = str8_find_needle(msg, 0, str8_lit(" "), 0); String8 cmd_kind_name_string = str8_prefix(msg, first_space_pos); String8 cmd_args_string = str8_skip_chop_whitespace(str8_skip(msg, first_space_pos)); RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(cmd_kind_name_string); if(cmd_kind_info != &rd_nil_cmd_kind_info) RD_RegsScope() { - if(dst_window != rd_window_from_handle(rd_regs()->window)) + if(dst_ws->cfg_id != rd_regs()->window) { - rd_regs()->window = rd_handle_from_window(dst_window); - rd_regs()->panel = rd_handle_from_panel(dst_window->focused_panel); - rd_regs()->view = dst_window->focused_panel->selected_tab_view; + Temp scratch = scratch_begin(0, 0); + RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(dst_ws->cfg_id)); + rd_regs()->window = dst_ws->cfg_id; + rd_regs()->panel = panel_tree.focused->cfg->id; + rd_regs()->tab = panel_tree.focused->selected_tab->id; + rd_regs()->view = panel_tree.focused->selected_tab->id; + scratch_end(scratch); } rd_regs_fill_slot_from_string(cmd_kind_info->query.slot, cmd_args_string); rd_push_cmd(cmd_kind_name_string, rd_regs()); @@ -797,7 +637,7 @@ entry_point(CmdLine *cmd_line) if(auto_run) { auto_run = 0; - rd_cmd(RD_CmdKind_LaunchAndRun); + rd_cmd(RD_CmdKind_Run); } //- rjf: auto step diff --git a/src/raddbg/raddbg_views.c b/src/raddbg/raddbg_views.c index 550e1fd1..80fd780b 100644 --- a/src/raddbg/raddbg_views.c +++ b/src/raddbg/raddbg_views.c @@ -7,6 +7,7 @@ internal void rd_code_view_init(RD_CodeViewState *cv) { + ProfBeginFunction(); if(cv->initialized == 0) { cv->initialized = 1; @@ -15,6 +16,7 @@ rd_code_view_init(RD_CodeViewState *cv) cv->center_cursor = 1; rd_store_view_loading_info(1, 0, 0); } + ProfEnd(); } internal RD_CodeViewBuildResult @@ -31,18 +33,20 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla ////////////////////////////// //- rjf: extract invariants // + F32 main_font_size = ui_bottom_font_size(); FNT_Tag code_font = rd_font_from_slot(RD_FontSlot_Code); - F32 code_font_size = rd_font_size_from_slot(RD_FontSlot_Code); - F32 code_tab_size = fnt_column_size_from_tag_size(code_font, code_font_size)*rd_setting_val_from_code(RD_SettingCode_TabWidth).s32; + F32 code_font_size = ui_top_font_size(); + F32 code_tab_size = fnt_column_size_from_tag_size(code_font, code_font_size)*rd_setting_u64_from_name(str8_lit("tab_width")); FNT_Metrics code_font_metrics = fnt_metrics_from_tag_size(code_font, code_font_size); F32 code_line_height = ceil_f32(fnt_line_height_from_metrics(&code_font_metrics) * 1.5f); F32 big_glyph_advance = fnt_dim_from_tag_size_string(code_font, code_font_size, 0, 0, str8_lit("H")).x; Vec2F32 panel_box_dim = dim_2f32(rect); - F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); + F32 scroll_bar_dim = floor_f32(main_font_size*1.5f); Vec2F32 code_area_dim = v2f32(panel_box_dim.x - scroll_bar_dim, panel_box_dim.y - scroll_bar_dim); S64 num_possible_visible_lines = (S64)(code_area_dim.y/code_line_height)+1; - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); + B32 do_line_numbers = rd_setting_b32_from_name(str8_lit("show_line_numbers")); ////////////////////////////// //- rjf: unpack information about the viewed source file, if any @@ -53,15 +57,8 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla ////////////////////////////// //- rjf: process commands // - for(RD_Cmd *cmd = 0; rd_next_cmd(&cmd);) + for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) { - // rjf: mismatched window/panel => skip - if(!rd_handle_match(rd_regs()->view, cmd->regs->view)) - { - continue; - } - - // rjf: process RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); switch(kind) { @@ -78,16 +75,28 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { cv->contain_cursor = 1; }break; - case RD_CmdKind_FindTextForward: + case RD_CmdKind_Search: { arena_clear(cv->find_text_arena); cv->find_text_fwd = push_str8_copy(cv->find_text_arena, cmd->regs->string); }break; - case RD_CmdKind_FindTextBackward: + case RD_CmdKind_SearchBackwards: { arena_clear(cv->find_text_arena); cv->find_text_bwd = push_str8_copy(cv->find_text_arena, cmd->regs->string); }break; + case RD_CmdKind_FindNext: + { + String8 string = rd_view_query_input(); + arena_clear(cv->find_text_arena); + cv->find_text_fwd = push_str8_copy(cv->find_text_arena, string); + }break; + case RD_CmdKind_FindPrev: + { + String8 string = rd_view_query_input(); + arena_clear(cv->find_text_arena); + cv->find_text_bwd = push_str8_copy(cv->find_text_arena, string); + }break; case RD_CmdKind_ToggleWatchExpressionAtMouse: { cv->watch_expr_at_mouse = 1; @@ -131,41 +140,60 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla ////////////////////////////// //- rjf: calculate line-range-dependent info // - F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); + F32 line_num_width_px = 0; + if(do_line_numbers) + { + line_num_width_px = floor_f32(big_glyph_advance * (log10(visible_line_num_range.max) + 3)); + } F32 priority_margin_width_px = 0; F32 catchall_margin_width_px = 0; if(flags & RD_CodeViewBuildFlag_Margins) { - priority_margin_width_px = big_glyph_advance*3.5f; - catchall_margin_width_px = big_glyph_advance*3.5f; + priority_margin_width_px = floor_f32(big_glyph_advance*3.5f); + catchall_margin_width_px = floor_f32(big_glyph_advance*3.5f); } TXT_LineTokensSlice slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, text_info, text_data, visible_line_num_range); ////////////////////////////// - //- rjf: get active search query + //- rjf: selection on single line, no query? -> set search text // - String8 search_query = {0}; - Side search_query_side = Side_Invalid; - B32 search_query_is_active = 0; + if(rd_regs()->cursor.line == rd_regs()->mark.line) { - RD_Window *window = rd_window_from_handle(rd_regs()->window); - RD_CmdKind query_cmd_kind = rd_cmd_kind_from_string(window->query_cmd_name); - if(query_cmd_kind == RD_CmdKind_FindTextForward || - query_cmd_kind == RD_CmdKind_FindTextBackward) + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_ViewState *vs = rd_view_state_from_cfg(view); + if(!vs->query_is_open) { - search_query = str8(window->query_view_stack_top->query_buffer, window->query_view_stack_top->query_string_size); - search_query_is_active = 1; - search_query_side = (query_cmd_kind == RD_CmdKind_FindTextForward) ? Side_Max : Side_Min; + RD_Cfg *query = rd_cfg_child_from_string_or_alloc(view, str8_lit("query")); + RD_Cfg *input = rd_cfg_child_from_string_or_alloc(query, str8_lit("input")); + String8 text = txt_string_from_info_data_txt_rng(text_info, text_data, txt_rng(rd_regs()->cursor, rd_regs()->mark)); + if(text.size < 256) + { + rd_cfg_new_replace(input, text); + } + else + { + rd_cfg_new_replace(input, str8_zero()); + } } } + ////////////////////////////// + //- rjf: get active search query + // + String8 search_query = rd_view_query_input(); + B32 search_query_is_active = 0; + ////////////////////////////// //- rjf: prepare code slice info bundle, for the viewable region of text // RD_CodeSliceParams code_slice_params = {0}; { // rjf: fill basics - code_slice_params.flags = RD_CodeSliceFlag_LineNums|RD_CodeSliceFlag_Clickable; + code_slice_params.flags = RD_CodeSliceFlag_Clickable; + if(do_line_numbers) + { + code_slice_params.flags |= RD_CodeSliceFlag_LineNums; + } if(flags & RD_CodeViewBuildFlag_Margins) { code_slice_params.flags |= RD_CodeSliceFlag_PriorityMargin|RD_CodeSliceFlag_CatchallMargin; @@ -174,9 +202,9 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla code_slice_params.line_text = push_array(scratch.arena, String8, visible_line_count); code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, visible_line_count); code_slice_params.line_tokens = push_array(scratch.arena, TXT_TokenArray, visible_line_count); - code_slice_params.line_bps = push_array(scratch.arena, RD_EntityList, visible_line_count); + code_slice_params.line_bps = push_array(scratch.arena, RD_CfgList, visible_line_count); code_slice_params.line_ips = push_array(scratch.arena, CTRL_EntityList, visible_line_count); - code_slice_params.line_pins = push_array(scratch.arena, RD_EntityList, visible_line_count); + code_slice_params.line_pins = push_array(scratch.arena, RD_CfgList, visible_line_count); code_slice_params.line_vaddrs = push_array(scratch.arena, U64, visible_line_count); code_slice_params.line_infos = push_array(scratch.arena, D_LineList, visible_line_count); code_slice_params.font = code_font; @@ -188,7 +216,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla code_slice_params.catchall_margin_width_px = catchall_margin_width_px; code_slice_params.line_num_width_px = line_num_width_px; code_slice_params.line_text_max_width_px = (F32)line_size_x; - code_slice_params.margin_float_off_px = scroll_pos.x.idx + scroll_pos.x.off; + code_slice_params.margin_float_off_px = scroll_pos.x.idx + floor_f32(scroll_pos.x.off); // rjf: fill text info { @@ -207,21 +235,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find visible breakpoints for source code if(!dasm_lines) ProfScope("find visible breakpoints for source code") { - RD_EntityList bps = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - for(RD_EntityNode *n = bps.first; n != 0; n = n->next) + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) { - RD_Entity *bp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(bp, RD_EntityKind_Location); - if(visible_line_num_range.min <= loc->text_point.line && loc->text_point.line <= visible_line_num_range.max) + RD_Cfg *bp = n->v; + RD_Location loc = rd_location_from_cfg(bp); + if(visible_line_num_range.min <= loc.pt.line && loc.pt.line <= visible_line_num_range.max) { for(String8Node *override_n = file_path_possible_overrides.first; override_n != 0; override_n = override_n->next) { - if(path_match_normalized(loc->string, override_n->string)) + if(path_match_normalized(loc.file_path, override_n->string)) { - U64 slice_line_idx = (loc->text_point.line-visible_line_num_range.min); - rd_entity_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + U64 slice_line_idx = (U64)(loc.pt.line-visible_line_num_range.min); + rd_cfg_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); break; } } @@ -232,11 +260,11 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find live threads mapping to source code if(!dasm_lines) ProfScope("find live threads mapping to this file") { - CTRL_Entity *selected_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread); - for(CTRL_EntityNode *thread_n = threads.first; thread_n != 0; thread_n = thread_n->next) + CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); + CTRL_EntityArray threads = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Thread); + for EachIndex(idx, threads.count) { - CTRL_Entity *thread = thread_n->v; + CTRL_Entity *thread = threads.v[idx]; CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); U64 unwind_count = (thread == selected_thread) ? rd_regs()->unwind_count : 0; U64 inline_depth = (thread == selected_thread) ? rd_regs()->inline_depth : 0; @@ -269,21 +297,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find visible watch pins for source code if(!dasm_lines) ProfScope("find visible watch pins for source code") { - RD_EntityList wps = rd_query_cached_entity_list_with_kind(RD_EntityKind_WatchPin); - for(RD_EntityNode *n = wps.first; n != 0; n = n->next) + RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(RD_CfgNode *n = wps.first; n != 0; n = n->next) { - RD_Entity *wp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(wp, RD_EntityKind_Location); - if(visible_line_num_range.min <= loc->text_point.line && loc->text_point.line <= visible_line_num_range.max) + RD_Cfg *wp = n->v; + RD_Location loc = rd_location_from_cfg(wp); + if(visible_line_num_range.min <= loc.pt.line && loc.pt.line <= visible_line_num_range.max) { for(String8Node *override_n = file_path_possible_overrides.first; override_n != 0; override_n = override_n->next) { - if(path_match_normalized(loc->string, override_n->string)) + if(path_match_normalized(loc.file_path, override_n->string)) { - U64 slice_line_idx = (loc->text_point.line-visible_line_num_range.min); - rd_entity_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); + U64 slice_line_idx = (loc.pt.line-visible_line_num_range.min); + rd_cfg_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); break; } } @@ -295,7 +323,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla if(!dasm_lines) ProfScope("find all src -> dasm info for source code") { String8 file_path = rd_regs()->file_path; - CTRL_Entity *module = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->module); + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); D_LineListArray lines_array = d_lines_array_from_dbgi_key_file_path_line_range(scratch.arena, dbgi_key, file_path, visible_line_num_range); if(lines_array.count != 0) @@ -308,11 +336,11 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find live threads mapping to disasm if(dasm_lines) ProfScope("find live threads mapping to this disassembly") { - CTRL_Entity *selected_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); - CTRL_EntityList threads = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Thread); - for(CTRL_EntityNode *thread_n = threads.first; thread_n != 0; thread_n = thread_n->next) + CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); + CTRL_EntityArray threads = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Thread); + for EachIndex(idx, threads.count) { - CTRL_Entity *thread = thread_n->v; + CTRL_Entity *thread = threads.v[idx]; U64 unwind_count = (thread == selected_thread) ? rd_regs()->unwind_count : 0; U64 rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, unwind_count); if(ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process) == process && contains_1u64(dasm_vaddr_range, rip_vaddr)) @@ -331,20 +359,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find breakpoints mapping to this disasm if(dasm_lines) ProfScope("find breakpoints mapping to this disassembly") { - RD_EntityList bps = rd_query_cached_entity_list_with_kind(RD_EntityKind_Breakpoint); - for(RD_EntityNode *n = bps.first; n != 0; n = n->next) + RD_CfgList bps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("breakpoint")); + for(RD_CfgNode *n = bps.first; n != 0; n = n->next) { - RD_Entity *bp = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(bp, RD_EntityKind_Location); - if(loc->flags & RD_EntityFlag_HasVAddr && contains_1u64(dasm_vaddr_range, loc->vaddr)) + RD_Cfg *bp = n->v; + RD_Location loc = rd_location_from_cfg(bp); + E_Value loc_value = e_value_from_string(loc.expr); + if(contains_1u64(dasm_vaddr_range, loc_value.u64)) { - U64 off = loc->vaddr-dasm_vaddr_range.min; + U64 off = loc_value.u64 - dasm_vaddr_range.min; U64 idx = dasm_line_array_idx_from_code_off__linear_scan(dasm_lines, off); - S64 line_num = (S64)(idx+1); + S64 line_num = (S64)idx+1; if(contains_1s64(visible_line_num_range, line_num)) { U64 slice_line_idx = (line_num-visible_line_num_range.min); - rd_entity_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); + rd_cfg_list_push(scratch.arena, &code_slice_params.line_bps[slice_line_idx], bp); } } } @@ -353,20 +382,21 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla // rjf: find watch pins mapping to this disasm if(dasm_lines) ProfScope("find watch pins mapping to this disassembly") { - RD_EntityList pins = rd_query_cached_entity_list_with_kind(RD_EntityKind_WatchPin); - for(RD_EntityNode *n = pins.first; n != 0; n = n->next) + RD_CfgList wps = rd_cfg_top_level_list_from_string(scratch.arena, str8_lit("watch_pin")); + for(RD_CfgNode *n = wps.first; n != 0; n = n->next) { - RD_Entity *pin = n->entity; - RD_Entity *loc = rd_entity_child_from_kind(pin, RD_EntityKind_Location); - if(loc->flags & RD_EntityFlag_HasVAddr && contains_1u64(dasm_vaddr_range, loc->vaddr)) + RD_Cfg *wp = n->v; + RD_Location loc = rd_location_from_cfg(wp); + E_Value loc_value = e_value_from_string(loc.expr); + if(contains_1u64(dasm_vaddr_range, loc_value.u64)) { - U64 off = loc->vaddr-dasm_vaddr_range.min; + U64 off = loc_value.u64 - dasm_vaddr_range.min; U64 idx = dasm_line_array_idx_from_code_off__linear_scan(dasm_lines, off); - S64 line_num = (S64)(idx+1); + S64 line_num = (S64)idx+1; if(contains_1s64(visible_line_num_range, line_num)) { U64 slice_line_idx = (line_num-visible_line_num_range.min); - rd_entity_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], pin); + rd_cfg_list_push(scratch.arena, &code_slice_params.line_pins[slice_line_idx], wp); } } } @@ -443,9 +473,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla U64 needle_pos = str8_find_needle(line_string, search_start, cv->find_text_fwd, StringMatchFlag_CaseInsensitive); if(needle_pos < line_string.size) { - rd_regs()->cursor.line = line_num; - rd_regs()->cursor.column = needle_pos+1; - rd_regs()->mark = rd_regs()->cursor; + rd_regs()->mark.line = line_num; + rd_regs()->mark.column = needle_pos+1; + rd_regs()->cursor = rd_regs()->mark; + rd_regs()->cursor.column += cv->find_text_fwd.size; found = 1; break; } @@ -466,7 +497,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla cv->center_cursor = found; if(found == 0) { - log_user_errorf("Could not find \"%S\"", cv->find_text_fwd); + log_user_errorf("Could not find `%S`", cv->find_text_fwd); } } @@ -475,15 +506,16 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { B32 found = 0; B32 first = 1; - S64 line_num_start = rd_regs()->cursor.line; + TxtRng rng = txt_rng(rd_regs()->cursor, rd_regs()->mark); + S64 line_num_start = rng.min.line; S64 line_num_last = (S64)text_info->lines_count; for(S64 line_num = line_num_start; 1 <= line_num && line_num <= line_num_last; first = 0) { // rjf: gather line info String8 line_string = str8_substr(text_data, text_info->lines_ranges[line_num-1]); - if(rd_regs()->cursor.line == line_num && first) + if(rng.min.line == line_num && first) { - line_string = str8_prefix(line_string, rd_regs()->cursor.column-1); + line_string = str8_prefix(line_string, rng.min.column-1); } // rjf: search string @@ -499,9 +531,10 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla } if(next_needle_pos < line_string.size) { - rd_regs()->cursor.line = line_num; - rd_regs()->cursor.column = next_needle_pos+1; - rd_regs()->mark = rd_regs()->cursor; + rd_regs()->mark.line = line_num; + rd_regs()->mark.column = next_needle_pos+1; + rd_regs()->cursor = rd_regs()->mark; + rd_regs()->cursor.column += cv->find_text_bwd.size; found = 1; break; } @@ -522,7 +555,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla cv->center_cursor = found; if(found == 0) { - log_user_errorf("Could not find \"%S\"", cv->find_text_bwd); + log_user_errorf("Could not find `%S`", cv->find_text_bwd); } } @@ -540,7 +573,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla cv->goto_line_num = 0; line_num = Clamp(1, line_num, text_info->lines_count); rd_regs()->cursor = rd_regs()->mark = txt_pt(line_num, 1); - cv->center_cursor = !cv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num); + cv->center_cursor = !cv->force_contain_only && (!cv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num)); } ////////////////////////////// @@ -603,13 +636,6 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla cv->watch_expr_at_mouse = 0; rd_cmd(RD_CmdKind_ToggleWatchExpression, .string = txt_string_from_info_data_txt_rng(text_info, text_data, sig.mouse_expr_rng)); } - - //- rjf: selected text on single line, no query? -> set search text - if(!txt_pt_match(rd_regs()->cursor, rd_regs()->mark) && rd_regs()->cursor.line == rd_regs()->mark.line && search_query.size == 0) - { - String8 text = txt_string_from_info_data_txt_rng(text_info, text_data, txt_rng(rd_regs()->cursor, rd_regs()->mark)); - rd_set_search_string(text); - } } ////////////////////////////// @@ -749,16 +775,16 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla { for(UI_Event *evt = 0; ui_next_event(&evt);) { - if(evt->kind == UI_EventKind_Scroll && evt->modifiers & OS_Modifier_Ctrl) + if(evt->kind == UI_EventKind_Scroll && evt->modifiers & OS_Modifier_Ctrl && evt->modifiers & OS_Modifier_Shift) { ui_eat_event(evt); if(evt->delta_2f32.y < 0) { - rd_cmd(RD_CmdKind_IncCodeFontScale); + rd_cmd(RD_CmdKind_IncViewFontSize); } else if(evt->delta_2f32.y > 0) { - rd_cmd(RD_CmdKind_DecCodeFontScale); + rd_cmd(RD_CmdKind_DecViewFontSize); } } } @@ -781,6 +807,7 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla //- rjf: store state // rd_store_view_scroll_pos(scroll_pos); + cv->force_contain_only = 0; scratch_end(scratch); ProfEnd(); @@ -790,406 +817,1145 @@ rd_code_view_build(Arena *arena, RD_CodeViewState *cv, RD_CodeViewBuildFlags fla //////////////////////////////// //~ rjf: Watch Views -//- rjf: index -> column +//- rjf: cell list building -internal RD_WatchViewColumn * -rd_watch_view_column_from_x(RD_WatchViewState *wv, S64 index) +internal U64 +rd_id_from_watch_cell(RD_WatchCell *cell) { - RD_WatchViewColumn *result = wv->first_column; - S64 idx = 0; - for(RD_WatchViewColumn *c = wv->first_column; c != 0; c = c->next, idx += 1) + U64 result = 5381; + result = e_hash_from_string(result, str8_struct(&cell->kind)); + result = e_hash_from_string(result, str8_struct(&cell->index)); + if(cell->index != 0) { - result = c; - if(idx == index) - { - break; - } + result = e_hash_from_string(result, str8_struct(&cell->default_pct)); } return result; } +internal RD_WatchCell * +rd_watch_cell_list_push(Arena *arena, RD_WatchCellList *list) +{ + RD_WatchCell *cell = push_array(arena, RD_WatchCell, 1); + cell->index = list->count; + SLLQueuePush(list->first, list->last, cell); + list->count += 1; + return cell; +} + +internal RD_WatchCell * +rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell *params) +{ + RD_WatchCell *cell = rd_watch_cell_list_push(arena, list); + U64 index = cell->index; + MemoryCopyStruct(cell, params); + cell->index = index; + if(cell->pct == 0) + { + cell->pct = cell->default_pct; + } + cell->next = 0; + return cell; +} + //- rjf: watch view points <-> table coordinates internal B32 -rd_watch_view_point_match(RD_WatchViewPoint a, RD_WatchViewPoint b) +rd_watch_pt_match(RD_WatchPt a, RD_WatchPt b) { - return (a.x == b.x && - ev_key_match(a.parent_key, b.parent_key) && - ev_key_match(a.key, b.key)); + return (ev_key_match(a.parent_key, b.parent_key) && + ev_key_match(a.key, b.key) && + a.cell_id == b.cell_id); } -internal RD_WatchViewPoint -rd_watch_view_point_from_tbl(EV_BlockRangeList *block_ranges, Vec2S64 tbl) +internal RD_WatchPt +rd_watch_pt_from_tbl(EV_BlockRangeList *block_ranges, Vec2S64 tbl) { - RD_WatchViewPoint pt = zero_struct; - pt.x = tbl.x; - pt.key = ev_key_from_num(block_ranges, (U64)tbl.y); - pt.parent_key = ev_block_range_from_num(block_ranges, (U64)tbl.y).block->key; + RD_WatchPt pt = zero_struct; + { + Temp scratch = scratch_begin(0, 0); + EV_Row *row = ev_row_from_num(scratch.arena, rd_view_eval_view(), block_ranges, (U64)tbl.y); + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + { + S64 x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, x += 1) + { + if(x == tbl.x) + { + pt.cell_id = rd_id_from_watch_cell(cell); + break; + } + } + } + pt.key = row->key; + pt.parent_key = row->block->key; + scratch_end(scratch); + } return pt; } internal Vec2S64 -rd_tbl_from_watch_view_point(EV_BlockRangeList *block_ranges, RD_WatchViewPoint pt) +rd_tbl_from_watch_pt(EV_BlockRangeList *block_ranges, RD_WatchPt pt) { Vec2S64 tbl = {0}; - tbl.x = pt.x; - tbl.y = (S64)ev_num_from_key(block_ranges, pt.key); + { + Temp scratch = scratch_begin(0, 0); + U64 num = ev_num_from_key(block_ranges, pt.key); + EV_Row *row = ev_row_from_num(scratch.arena, rd_view_eval_view(), block_ranges, num); + RD_WatchRowInfo row_info = rd_watch_row_info_from_row(scratch.arena, row); + tbl.x = 0; + { + S64 x = 0; + for(RD_WatchCell *cell = row_info.cells.first; cell != 0; cell = cell->next, x += 1) + { + U64 cell_id = rd_id_from_watch_cell(cell); + if(cell_id == pt.cell_id) + { + tbl.x = x; + break; + } + } + } + tbl.y = (S64)num; + scratch_end(scratch); + } return tbl; } -//- rjf: row -> context info +//- rjf: row -> info -internal RD_WatchViewRowInfo -rd_watch_view_row_info_from_row(EV_Row *row) +internal RD_WatchRowInfo +rd_watch_row_info_from_row(Arena *arena, EV_Row *row) { - RD_WatchViewRowInfo info = {0}; + RD_WatchRowInfo info = { - Temp scratch = scratch_begin(0, 0); - DI_Scope *di_scope = di_scope_open(); + .module = &ctrl_entity_nil, + .can_expand = ev_row_is_expandable(row), + .group_cfg_parent = &rd_nil_cfg, + .group_cfg_child = &rd_nil_cfg, + .group_entity = &ctrl_entity_nil, + .callstack_thread = &ctrl_entity_nil, + .view_ui_rule = &rd_nil_view_ui_rule, + }; + { + Temp scratch = scratch_begin(&arena, 1); - // rjf: unpack block/key coordinates - EV_Block *block = row->block; + //////////////////////////// + //- rjf: unpack row's evaluation, key, & block info + // + E_Type *row_type = e_type_from_key(row->eval.irtree.type_key); EV_Key key = row->key; + EV_Block *block = row->block; + E_Eval block_eval = e_eval_from_key(row->block->eval.key); + E_TypeKey block_type_key = e_type_key_unwrap(block_eval.irtree.type_key, E_TypeUnwrapFlag_Meta); + E_TypeKind block_type_kind = e_type_kind_from_key(block_type_key); + E_Type *block_type = e_type_from_key(block_type_key); + RD_Cfg *evalled_cfg = rd_cfg_from_eval_space(row->eval.space); + CTRL_Entity *evalled_entity = (row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity ? rd_ctrl_entity_from_eval_space(row->eval.space) : &ctrl_entity_nil); - // rjf: unpack parent block's expression - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, block->expr); - E_Type *type = e_type_from_key(scratch.arena, irtree.type_key); - - // rjf: evaluate row - E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - - // rjf: determine collection entity kind, if any - RD_EntityKind collection_entity_kind = RD_EntityKind_Nil; - CTRL_EntityKind collection_ctrl_entity_kind = CTRL_EntityKind_Null; - for EachElement(idx, rd_collection_name_table) + //////////////////////////// + //- rjf: determine if this cfg/entity evaluation is top-level - e.g. if we + // are evaluating a cfg tree, or some descendant of it + // + B32 is_top_level = 0; + if(evalled_cfg != &rd_nil_cfg) { - if(str8_match(type->name, rd_collection_name_table[idx], 0)) + E_TypeKey top_level_type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, evalled_cfg->string); + is_top_level = (row->eval.value.u64 == 0 && e_type_key_match(top_level_type_key, row->eval.irtree.type_key)); + } + if(evalled_entity != &ctrl_entity_nil) + { + String8 top_level_name = ctrl_entity_kind_code_name_table[evalled_entity->kind]; + E_TypeKey top_level_type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, top_level_name); + is_top_level = (row->eval.value.u64 == 0 && e_type_key_match(top_level_type_key, row->eval.irtree.type_key)); + } + + //////////////////////////// + //- rjf: fill if row's expression is editable + // + if(block_type->flags & E_TypeFlag_EditableChildren || (e_key_match(row->eval.key, e_key_zero()) && row->eval.expr == &e_expr_nil)) + { + info.expr_is_editable = 1; + } + + //////////////////////////// + //- rjf: fill row's module + // + if(row->eval.space.kind == RD_EvalSpaceKind_CtrlEntity) + { + CTRL_Entity *row_ctrl_entity = rd_ctrl_entity_from_eval_space(row->eval.space); + switch(row_ctrl_entity->kind) + { + default: + case CTRL_EntityKind_Process: + if(row->eval.irtree.mode == E_Mode_Offset) + { + info.module = ctrl_module_from_process_vaddr(row_ctrl_entity, row->eval.value.u64); + }break; + case CTRL_EntityKind_Thread: + if(row->eval.irtree.mode == E_Mode_Value) + { + CTRL_Entity *process = ctrl_process_from_entity(row_ctrl_entity); + info.module = ctrl_module_from_process_vaddr(process, d_query_cached_rip_from_thread(row_ctrl_entity)); + }break; + } + } + + //////////////////////////// + //- rjf: fill row's call stack info + // + if(block_eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity && str8_match(str8_lit("call_stack"), block_type->name, 0)) + { + CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(block_eval.space); + if(entity->kind == CTRL_EntityKind_Thread) + { + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + info.callstack_thread = entity; + U64 frame_num = ev_block_num_from_id(block, key.child_id); + B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + if(1 <= frame_num && frame_num <= call_stack.frames_count) + { + CTRL_CallStackFrame *f = &call_stack.frames[frame_num-1]; + info.callstack_unwind_index = f->unwind_count; + info.callstack_inline_depth = f->inline_depth; + info.callstack_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); + } + ctrl_scope_close(ctrl_scope); + } + } + + //////////////////////////// + //- rjf: fill row's ctrl entity + // + if(block_type_kind == E_TypeKind_Set && (block_eval.space.kind == RD_EvalSpaceKind_MetaQuery || + block_eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity)) + { + info.group_entity = rd_ctrl_entity_from_eval_space(row->eval.space); + } + + //////////////////////////// + //- rjf: fill row's cfg group name / parent + // + if(block_type_kind == E_TypeKind_Set && (block_eval.space.kind == RD_EvalSpaceKind_MetaQuery || + block_eval.space.kind == RD_EvalSpaceKind_MetaCfg)) + { + info.group_cfg_parent = rd_cfg_from_eval_space(block_eval.space); + } + + //////////////////////////// + //- rjf: fill row's group cfg name + // + if(block_type_kind == E_TypeKind_Set) + { + String8 singular_name = rd_singular_from_code_name_plural(block_type->name); + if(singular_name.size != 0) + { + info.group_cfg_name = singular_name; + } + else + { + info.group_cfg_name = block_type->name; + } + } + + //////////////////////////// + //- rjf: fill row's group cfg + // + if(info.group_cfg_name.size != 0 && (block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(cfgs_slice) || + block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(watches) || + block_type->expand.id_from_num == E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_NAME(environment))) + { + RD_CfgID id = row->key.child_id; + info.group_cfg_child = rd_cfg_from_id(id); + } + + //////////////////////////// + //- rjf: fill row's view ui rule + // + info.view_ui_rule = rd_view_ui_rule_from_string(row->block->viz_expand_rule->string); + + //////////////////////////// + //- rjf: find possible "columns" type + // + E_Type *maybe_table_type = block_type; + for(;;) + { + if(maybe_table_type->kind == E_TypeKind_Lens && + str8_match(maybe_table_type->name, str8_lit("columns"), 0)) + { + break; + } + else if(maybe_table_type->kind == E_TypeKind_Lens) + { + maybe_table_type = e_type_from_key(maybe_table_type->direct_type_key); + continue; + } + else { - collection_entity_kind = rd_collection_entity_kind_table[idx]; - collection_ctrl_entity_kind = rd_collection_ctrl_entity_kind_table[idx]; break; } } - // rjf: extract frontend entity, if any - RD_Entity *entity = &rd_nil_entity; - if(collection_entity_kind != RD_EntityKind_Nil) + //////////////////////////// + //- rjf: @watch_row_build_cells table rows + // + if(0){} + else if(block->parent != &ev_nil_block && maybe_table_type->kind == E_TypeKind_Lens && str8_match(maybe_table_type->name, str8_lit("columns"), 0) && maybe_table_type->count >= 1) { - entity = rd_entity_from_id(key.child_id); - } - - // rjf: extract control entity, if any - CTRL_Entity *ctrl_entity = &ctrl_entity_nil; - if(collection_ctrl_entity_kind != CTRL_EntityKind_Null && block->expand_view_rule_info_user_data != 0) - { - U64 block_relative_num = block->expand_view_rule_info->expr_expand_num_from_id(key.child_id, block->expand_view_rule_info_user_data); - RD_CtrlEntityExpandAccel *accel = block->expand_view_rule_info_user_data; - if(1 <= block_relative_num && block_relative_num <= accel->entities.count) + U64 column_count = maybe_table_type->count; + info.cell_style_key = push_str8f(arena, "table_%I64u_cols", column_count); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + E_ParentKey(row->eval.key) { - ctrl_entity = accel->entities.v[block_relative_num-1]; - } - } - else if(row_eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity) - { - ctrl_entity = rd_ctrl_entity_from_eval_space(row_eval.space); - } - - // rjf: extract callstack thread, if any - CTRL_Entity *thread = &ctrl_entity_nil; - for(E_Expr *expr = block->expr, *next = &e_expr_nil; expr != &e_expr_nil; expr = next) - { - next = &e_expr_nil; - switch(expr->kind) - { - default:{}break; - case E_ExprKind_Ref:{next = expr->ref;}break; - case E_ExprKind_Cast:{next = expr->last;}break; - case E_ExprKind_MemberAccess:{next = expr->first;}break; - case E_ExprKind_ArrayIndex:{next = expr->first;}break; - case E_ExprKind_LeafIdent: + for(U64 idx = 0; idx < maybe_table_type->count; idx += 1) { - E_Eval eval = e_eval_from_expr(scratch.arena, expr); - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); - if(entity->kind == CTRL_EntityKind_Thread) - { - thread = entity; - goto done; - } - }break; - } - } - done:; - - // rjf: extract callstack row information, if any - U64 unwind_count = 0; - U64 inline_depth = 0; - if(thread != &ctrl_entity_nil) - { - U64 block_relative_num = block->expand_view_rule_info->expr_expand_num_from_id(key.child_id, block->expand_view_rule_info_user_data); - CTRL_Unwind base_unwind = d_query_cached_unwind_from_thread(thread); - CTRL_CallStack rich_unwind = ctrl_call_stack_from_unwind(scratch.arena, di_scope, ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process), &base_unwind); - U64 frame_num = 1; - for(U64 base_frame_idx = 0; base_frame_idx < rich_unwind.concrete_frame_count; base_frame_idx += 1, frame_num += 1) - { - if(frame_num <= block_relative_num && block_relative_num < frame_num+1+rich_unwind.frames[base_frame_idx].inline_frame_count) - { - unwind_count = base_frame_idx; - inline_depth = block_relative_num - frame_num; - break; + E_Eval cell_eval = e_eval_from_expr(maybe_table_type->args[idx]); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, cell_eval, .default_pct = 1.f/maybe_table_type->count, .pct = take_pct()); } - frame_num += rich_unwind.frames[base_frame_idx].inline_frame_count; + } + info.can_expand = 0; +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells files / folders + // + else if(row->eval.space.kind == E_SpaceKind_FileSystem) + { + E_Type *type = e_type_from_key(row->eval.irtree.type_key); + if(type->kind == E_TypeKind_Set) + { + String8 file_path = e_string_from_id(row->eval.value.u64); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented|RD_WatchCellFlag_Button|RD_WatchCellFlag_IsNonCode, .pct = 1.f); + if(str8_match(type->name, str8_lit("file"), 0)) + { + info.can_expand = 0; + } + } + else + { + info.cell_style_key = str8_lit("expr_and_eval"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .default_pct = 0.35f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.65f, .pct = take_pct()); +#undef take_pct } } - // rjf: fill - info.collection_entity_kind = collection_entity_kind; - info.collection_entity = entity; - info.collection_ctrl_entity_kind = collection_ctrl_entity_kind; - info.collection_ctrl_entity = ctrl_entity; - info.callstack_thread = thread; - info.callstack_unwind_index = unwind_count; - info.callstack_inline_depth = inline_depth; + //////////////////////////// + //- rjf: @watch_row_build_cells unattached processes + // + else if(row->eval.space.kind == RD_EvalSpaceKind_MetaUnattachedProcess && + str8_match(row_type->name, str8_lit("unattached_process"), 0)) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, + .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells autocomplete rows + // + else if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("autocomplete")) != &rd_nil_cfg) + { + info.can_expand = 0; + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells lister rows + // + else if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) != &rd_nil_cfg) + { + info.can_expand = 0; + RD_WatchCellFlags extra_flags = RD_WatchCellFlag_Expr; + if(e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)) == E_TypeKind_Function) + { + extra_flags &= ~RD_WatchCellFlag_Expr; + } + if(row->eval.msgs.max_kind != E_MsgKind_Null) + { + extra_flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval; + } + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = extra_flags|RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells top-level cfg evaluations + // + else if(is_top_level && evalled_cfg != &rd_nil_cfg) + { + RD_Cfg *cfg = evalled_cfg; + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Button|RD_WatchCellFlag_Indented, .pct = 1.f); + MD_NodePtrList schemas = rd_schemas_from_name(cfg->string); + for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next) + { + MD_Node *schema = n->v; + MD_Node *cmds_root = md_tag_from_string(schema, str8_lit("row_commands"), 0); + for MD_EachNode(cmd, cmds_root->first) + { + B32 is_file_only = md_node_has_tag(cmd, str8_lit("file"), 0); + B32 is_cmd_line_only = md_node_has_tag(cmd, str8_lit("cmd_line"), 0); + if(is_file_only && e_eval_from_string(rd_expr_from_cfg(evalled_cfg)).space.kind != E_SpaceKind_File) + { + continue; + } + if(is_cmd_line_only) + { + B32 is_cmd_line = 0; + RD_Cfg *cmd_line = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); + for(RD_Cfg *p = evalled_cfg->parent; p != &rd_nil_cfg; p = p->parent) + { + if(p == cmd_line) + { + is_cmd_line = 1; + break; + } + } + if(!is_cmd_line) + { + continue; + } + } + String8 cmd_name = cmd->string; + RD_CmdKind cmd_kind = rd_cmd_kind_from_string(cmd_name); + switch(cmd_kind) + { + default:{}break; + case RD_CmdKind_EnableCfg: + { + B32 is_disabled = rd_disabled_from_cfg(cfg); + if(!is_disabled) + { + cmd_kind = RD_CmdKind_DisableCfg; + } + }break; + case RD_CmdKind_DisableCfg: + { + B32 is_disabled = rd_disabled_from_cfg(cfg); + if(is_disabled) + { + cmd_kind = RD_CmdKind_EnableCfg; + } + }break; + case RD_CmdKind_SelectCfg: + { + B32 is_disabled = rd_disabled_from_cfg(cfg); + if(!is_disabled) + { + cmd_kind = RD_CmdKind_DeselectCfg; + } + }break; + case RD_CmdKind_DeselectCfg: + { + B32 is_disabled = rd_disabled_from_cfg(cfg); + if(is_disabled) + { + cmd_kind = RD_CmdKind_SelectCfg; + } + }break; + } + if(cmd_kind == RD_CmdKind_EnableCfg || cmd_kind == RD_CmdKind_DisableCfg) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "enabled"), + .flags = RD_WatchCellFlag_Background, + .px = floor_f32(ui_top_font_size()*5.5f)); + } + else if(cmd_kind != RD_CmdKind_Null) + { + String8 cmd_name = rd_cmd_kind_info_table[cmd_kind].string; + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, + e_eval_from_stringf("query:commands.%S", cmd_name), + .flags = RD_WatchCellFlag_ActivateWithSingleClick|RD_WatchCellFlag_Button, + .px = floor_f32(ui_top_font_size()*3.f)); + } + } + } + } + + //////////////////////////// + //- rjf: @watch_row_build_cells ctrl entity evaluations + // + else if(is_top_level && evalled_entity != &ctrl_entity_nil) + { + CTRL_Entity *entity = evalled_entity; + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented|RD_WatchCellFlag_Button, + .pct = 1.f); + if(entity->kind == CTRL_EntityKind_Machine || + entity->kind == CTRL_EntityKind_Process || + entity->kind == CTRL_EntityKind_Thread) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "active"), + .px = floor_f32(ui_top_font_size()*5.5f)); + } + if(entity->kind == CTRL_EntityKind_Thread) + { + RD_CmdKind cmd_kind = RD_CmdKind_SelectEntity; + if(ctrl_handle_match(entity->handle, rd_base_regs()->thread)) + { + cmd_kind = RD_CmdKind_DeselectEntity; + } + String8 cmd_name = rd_cmd_kind_info_table[cmd_kind].string; + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_from_stringf("query:commands.%S", cmd_name), + .flags = RD_WatchCellFlag_ActivateWithSingleClick|RD_WatchCellFlag_Button, + .px = floor_f32(ui_top_font_size()*3.f)); + } + } + + //////////////////////////// + //- rjf: @watch_row_build_cells queries + // + else if(row->eval.space.kind == RD_EvalSpaceKind_MetaQuery || + (row->eval.space.kind == RD_EvalSpaceKind_MetaCfg && + e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_Meta)) == E_TypeKind_Set)) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells commands + // + else if(row->eval.space.kind == RD_EvalSpaceKind_MetaCmd) + { + E_Type *type = e_type_from_key(row->eval.irtree.type_key); + if(type->kind == E_TypeKind_Set) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .pct = 1.f); + } + else + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented|RD_WatchCellFlag_Button|RD_WatchCellFlag_ActivateWithSingleClick, + .pct = 1.f); + } + } + + //////////////////////////// + //- rjf: @watch_row_build_cells view UI escape hatch + // + else if(info.view_ui_rule != &rd_nil_view_ui_rule) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_ViewUI, row->eval, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells "add new" expression rows + // + else if(row->eval.expr == &e_expr_nil && info.group_cfg_name.size != 0 && info.group_cfg_child == &rd_nil_cfg) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells meta-evaluation booleans + // + else if(info.group_cfg_child == &rd_nil_cfg && + e_type_kind_from_key(e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)) == E_TypeKind_Bool && + (row->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + row->eval.space.kind == RD_EvalSpaceKind_MetaCmd || + row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity)) + { + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_Indented, .pct = 1.f); + } + + //////////////////////////// + //- rjf: @watch_row_build_cells meta-evaluation catch-all: expression / value + // + else if(row->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + row->eval.space.kind == RD_EvalSpaceKind_MetaCmd || + row->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + row->eval.space.kind == E_SpaceKind_File) + { + E_TypeKey substantive_row_eval_type = e_type_key_unwrap(row->eval.irtree.type_key, E_TypeUnwrapFlag_Meta); + if(e_type_kind_from_key(substantive_row_eval_type) == E_TypeKind_Array && + e_type_kind_from_key(e_type_key_direct(substantive_row_eval_type)) == E_TypeKind_U8) + { + info.can_expand = 0; + } + info.cell_style_key = str8_lit("expr_and_eval"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, .default_pct = 0.35f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .default_pct = 0.65f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells procedures (expr & eval, mostly expr) + // + else if(block_type->kind == E_TypeKind_Set && str8_match(block_type->name, str8_lit("procedures"), 0)) + { + info.cell_style_key = str8_lit("procedure_expr_eval"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, + .default_pct = 0.75f, + .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "lens:hex((uint64)$)"), .default_pct = 0.25f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells call stack frames + // + else if(info.callstack_thread != &ctrl_entity_nil) + { + info.cell_style_key = str8_lit("call_stack_frame"); + CTRL_Entity *process = ctrl_process_from_entity(info.callstack_thread); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, info.callstack_vaddr); + E_Eval module_eval = e_eval_from_stringf("query:control.%S", ctrl_string_from_handle(scratch.arena, module->handle)); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_CallStackFrame, row->eval, .default_pct = 0.05f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.55f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "hex((uint64)$)"), .default_pct = 0.20f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, (module == &ctrl_entity_nil ? (E_Eval)zero_struct : module_eval), + .default_pct = 0.20f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells error rows + // + else if(row->eval.irtree.mode == E_Mode_Null && row->eval.msgs.max_kind > E_MsgKind_Null) + { + info.cell_style_key = str8_lit("expr_and_error"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, + .default_pct = 0.60f, + .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.40f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells root-level type rows + // + else if(row->eval.irtree.mode == E_Mode_Null && (row->block->eval.irtree.mode != E_Mode_Null || row->block->parent == &ev_nil_block)) + { + info.cell_style_key = str8_lit("root_type"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, + .default_pct = 0.50f, + .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.35f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "sizeof($)"), .default_pct = 0.15f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells sub-type rows + // + else if(row->eval.irtree.mode == E_Mode_Null) + { + info.cell_style_key = str8_lit("sub_type"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, + .default_pct = 0.35f, + .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.35f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "sizeof($)"), .default_pct = 0.15f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "(uint64)(&$)"), .default_pct = 0.15f, .pct = take_pct()); +#undef take_pct + } + + //////////////////////////// + //- rjf: @watch_row_build_cells catchall (normal rows) + // + else + { + info.cell_style_key = str8_lit("normal"); + RD_Cfg *view = rd_cfg_from_id(rd_regs()->view); + RD_Cfg *style = rd_cfg_child_from_string(view, info.cell_style_key); + RD_Cfg *w_cfg = style->first; + F32 next_pct = 0; +#define take_pct() (next_pct = (F32)f64_from_str8(w_cfg->string), w_cfg = w_cfg->next, next_pct) + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, + .flags = RD_WatchCellFlag_Expr|RD_WatchCellFlag_NoEval|RD_WatchCellFlag_Indented, + .default_pct = 0.35f, + .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, row->eval, .default_pct = 0.40f, .pct = take_pct()); + rd_watch_cell_list_push_new(arena, &info.cells, RD_WatchCellKind_Eval, e_eval_wrapf(row->eval, "typeof($)"), .default_pct = 0.25f, .pct = take_pct()); +#undef take_pct + } - di_scope_close(di_scope); scratch_end(scratch); } return info; } -//- rjf: watch view flags & row info -> row kind +//- rjf: row * cell -> string -internal RD_WatchViewRowKind -rd_watch_view_row_kind_from_flags_row_info(RD_WatchViewFlags flags, EV_Row *row, RD_WatchViewRowInfo *info) +internal RD_WatchRowCellInfo +rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_flags, RD_WatchRowInfo *row_info, RD_WatchCell *cell, FNT_Tag font, F32 font_size, F32 max_size_px) { - Temp scratch = scratch_begin(0, 0); - RD_ViewRuleInfo *ui_view_rule_info = rd_view_rule_info_from_string(row->block->expand_view_rule_info->string); - MD_Node *ui_view_rule_params_root = row->block->expand_view_rule_params; - if(ui_view_rule_info->ui == 0 || !(ui_view_rule_info->flags & RD_ViewRuleInfoFlag_CanUseInWatchTable)) + Temp scratch = scratch_begin(&arena ,1); + RD_WatchRowCellInfo result = { - ui_view_rule_info = &rd_nil_view_rule_info; - ui_view_rule_params_root = &md_nil_node; + .flags = cell->flags, + .view_ui_rule = &rd_nil_view_ui_rule, + .cfg = &rd_nil_cfg, + .entity = &ctrl_entity_nil, + }; + + ////////////////////////////// + //- rjf: unpack evaluation + // + E_Type *block_type = e_type_from_key(row->block->eval.irtree.type_key); + E_Type *cell_type = e_type_from_key(cell->eval.irtree.type_key); + MD_NodePtrList cell_schemas = rd_schemas_from_name(cell_type->name); + if(cell->eval.space.u64s[1] == 0 && cell_schemas.count != 0) + { + result.cfg = rd_cfg_from_eval_space(cell->eval.space); } - RD_WatchViewRowKind row_kind = RD_WatchViewRowKind_Normal; - E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - E_TypeKey row_type_key = row_eval.type_key; - E_TypeKind row_type_kind = e_type_kind_from_key(row_type_key); - if(ev_key_match(row->block->key, ev_key_root())) + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity && cell->eval.space.u64s[2] == 0) { - row_kind = RD_WatchViewRowKind_Header; + result.entity = rd_ctrl_entity_from_eval_space(cell->eval.space); } - else if(ui_view_rule_info != &rd_nil_view_rule_info && ui_view_rule_info->ui != 0) + result.cmd_name = rd_cmd_name_from_eval(cell->eval); + result.file_path = rd_file_path_from_eval(arena, cell->eval); + for(E_Type *type = cell_type; + type->kind == E_TypeKind_Lens; + type = e_type_from_key(type->direct_type_key)) { - row_kind = RD_WatchViewRowKind_Canvas; - } - else if(flags & RD_WatchViewFlag_PrettyEntityRows && - ((row_eval.value.u64 == 0 && row_type_kind == E_TypeKind_Struct) || - info->collection_entity_kind != RD_EntityKind_Nil || - info->collection_ctrl_entity_kind != CTRL_EntityKind_Null)) - { - row_kind = RD_WatchViewRowKind_PrettyEntityControls; - } - scratch_end(scratch); - return row_kind; -} - -//- rjf: row/column -> strings - -internal E_Expr * -rd_expr_from_watch_view_row_column(Arena *arena, EV_View *ev_view, EV_Row *row, RD_WatchViewColumn *col) -{ - E_Expr *expr = row->expr; - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Member: + RD_ViewUIRule *view_ui_rule = rd_view_ui_rule_from_string(type->name); + if(view_ui_rule != &rd_nil_view_ui_rule) { - Temp scratch = scratch_begin(&arena, 1); - String8 access_string = str8(col->string_buffer, col->string_size); - String8List accesses = str8_split(scratch.arena, access_string, (U8 *)".", 1, 0); - for(String8Node *n = accesses.first; n != 0; n = n->next) + result.view_ui_rule = view_ui_rule; + break; + } + } + + ////////////////////////////// + //- rjf: determine cell description + // + for(E_Type *type = cell_type; + type->kind != E_TypeKind_Null; + type = e_type_from_key(type->direct_type_key)) + { + if(type->kind == E_TypeKind_MetaDescription) + { + result.description = type->name; + break; + } + } + + ////////////////////////////// + //- rjf: determine cell editability + // + if(cell->kind == RD_WatchCellKind_Eval) + { + if(cell->flags & RD_WatchCellFlag_Expr && cell->flags & RD_WatchCellFlag_NoEval) + { + if(row_info->expr_is_editable) { - expr = e_expr_ref_member_access(arena, expr, n->string); + result.flags |= RD_WatchCellFlag_CanEdit; } - scratch_end(scratch); - }break; - } - if(col->view_rule_size != 0) - { - EV_ViewRuleList *view_rules = ev_view_rule_list_from_string(arena, str8(col->view_rule_buffer, col->view_rule_size)); - expr = ev_resolved_from_expr(arena, expr, view_rules); - } - return expr; -} - -internal String8 -rd_string_from_eval_viz_row_column(Arena *arena, EV_View *ev, EV_Row *row, RD_WatchViewColumn *col, EV_StringFlags string_flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size_px) -{ - ProfBeginFunction(); - String8 result = {0}; - E_Expr *row_col_expr = rd_expr_from_watch_view_row_column(arena, ev, row, col); - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: - ProfScope("expr cell string") + } + else { - result = ev_expr_string_from_row(arena, row, string_flags); - }break; - case RD_WatchViewColumnKind_Value: - case RD_WatchViewColumnKind_Member: - ProfScope("value/member cell string") - { - EV_ViewRuleList *view_rules = row->view_rules; - if(col->view_rule_size != 0) + if(ev_type_key_is_editable(cell->eval.irtree.type_key) && cell->eval.irtree.mode == E_Mode_Offset) { - view_rules = ev_view_rule_list_copy(arena, row->view_rules); - ev_view_rule_list_push_string(arena, view_rules, str8(col->view_rule_buffer, col->view_rule_size)); + result.flags |= RD_WatchCellFlag_CanEdit; } - E_Eval eval = e_eval_from_expr(arena, row_col_expr); - result = rd_value_string_from_eval(arena, string_flags, default_radix, font, font_size, max_size_px, eval, row->member, view_rules); - }break; - case RD_WatchViewColumnKind_Type: - ProfScope("type cell string") + } + } + + ////////////////////////////// + //- rjf: build cell's visual appearance info + // + switch(cell->eval.space.kind) + { + //- rjf: default case: depending on cell info, generate string + default: { - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(arena, row_col_expr); - E_TypeKey type_key = irtree.type_key; - result = !e_type_key_match(type_key, e_type_key_zero()) ? e_type_string_from_key(arena, type_key) : str8_zero(); - result = str8_skip_chop_whitespace(result); - }break; - case RD_WatchViewColumnKind_ViewRule: - ProfScope("view rule cell string") - { - result = ev_view_rule_from_key(ev, row->key); - }break; - case RD_WatchViewColumnKind_Module: - ProfScope("module cell string") - { - E_Eval eval = e_eval_from_expr(arena, row_col_expr); - E_Eval value_eval = e_value_eval_from_eval(eval); - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); - CTRL_Entity *process = ctrl_process_from_entity(entity); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, value_eval.value.u64); - result = push_str8_copy(arena, str8_skip_last_slash(module->string)); - }break; - case RD_WatchViewColumnKind_CallStackFrame: - ProfScope("call stack frame cell string") - { - Temp scratch = scratch_begin(&arena, 1); - DI_Scope *di_scope = di_scope_open(); - E_Eval eval = e_eval_from_expr(arena, row_col_expr); - E_Expr *vaddr_expr = e_expr_ref_member_access(scratch.arena, row_col_expr, str8_lit("vaddr")); - E_Expr *depth_expr = e_expr_ref_member_access(scratch.arena, row_col_expr, str8_lit("inline_depth")); - E_Eval vaddr_eval = e_eval_from_expr(scratch.arena, vaddr_expr); - E_Eval depth_eval = e_eval_from_expr(scratch.arena, depth_expr); - E_Eval vaddr_value_eval = e_value_eval_from_eval(vaddr_eval); - E_Eval depth_value_eval = e_value_eval_from_eval(depth_eval); - U64 vaddr = vaddr_value_eval.value.u64; - U64 depth = depth_value_eval.value.u64; - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(eval.space); - CTRL_Entity *process = ctrl_process_from_entity(entity); - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi = ctrl_dbgi_key_from_module(module); - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi, 0); - if(rdi != &di_rdi_parsed_nil) + if(0){} + + //- rjf: errors + else if(cell->eval.msgs.max_kind > E_MsgKind_Null && !(cell->flags & RD_WatchCellFlag_NoEval)) { - typedef struct ScopeTask ScopeTask; - struct ScopeTask + RD_Font(RD_FontSlot_Main) { - ScopeTask *next; - RDI_Scope *scope; - }; - U64 voff = ctrl_voff_from_vaddr(module, vaddr); - RDI_Scope *root_scope = rdi_scope_from_voff(rdi, voff); - ScopeTask start_task = {0, root_scope}; - ScopeTask *first_task = &start_task; - ScopeTask *last_task = &start_task; - for(;root_scope->parent_scope_idx != 0;) - { - root_scope = rdi_parent_from_scope(rdi, root_scope); - ScopeTask *t = push_array(scratch.arena, ScopeTask, 1); - SLLQueuePushFront(first_task, last_task, t); - t->scope = root_scope; - } - RDI_Scope *scope = root_scope; - U64 idx = 0; - for(ScopeTask *t = first_task; t != 0; t = t->next, idx += 1) - { - if(idx == depth) + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + DR_FStrList fstrs = {0}; + UI_TagF("weak") { - scope = t->scope; - break; + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[RD_IconKind_WarningBig], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + for(E_Msg *msg = cell->eval.msgs.first; msg != 0; msg = msg->next) + { + DR_FStrList msg_fstrs = rd_fstrs_from_rich_string(arena, msg->text); + dr_fstrs_concat_in_place(&fstrs, &msg_fstrs); + if(msg->next) + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + } + } } + result.expr_fstrs = fstrs; } - RDI_Procedure *procedure = rdi_procedure_from_scope(rdi, scope); - RDI_InlineSite *inline_site = rdi_inline_site_from_scope(rdi, scope); - if(inline_site->name_string_idx != 0 || inline_site->type_idx != 0) + } + + //- rjf: cfg evaluation -> button for cfg + else if(result.cfg != &rd_nil_cfg) + { + result.expr_fstrs = rd_title_fstrs_from_cfg(arena, result.cfg); + result.flags |= RD_WatchCellFlag_Button; + } + + //- rjf: entity evaluation -> button for entity + else if(result.entity != &ctrl_entity_nil) + { + result.expr_fstrs = rd_title_fstrs_from_ctrl_entity(arena, result.entity, 1); + result.flags |= RD_WatchCellFlag_Button; + } + + //- rjf: buttons -> button for command + else if(result.cmd_name.size != 0) + { + if(cell->px != 0) { - String8List parts = {0}; - E_TypeKey type = e_type_key_ext(E_TypeKind_Function, inline_site->type_idx, e_parse_ctx_module_idx_from_rdi(rdi)); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size); - String8List type_lhs_parts = {0}; - e_type_lhs_string_from_key(scratch.arena, type, &type_lhs_parts, 0, 0); - String8List type_rhs_parts = {0}; - e_type_rhs_string_from_key(scratch.arena, type, &type_rhs_parts, 0); - str8_list_pushf(scratch.arena, &parts, "[inlined] "); - str8_list_concat_in_place(&parts, &type_lhs_parts); - str8_list_push(scratch.arena, &parts, name); - str8_list_concat_in_place(&parts, &type_rhs_parts); - result = str8_list_join(arena, &parts, 0); - } - else if(procedure->name_string_idx != 0 || procedure->type_idx != 0) - { - String8List parts = {0}; - E_TypeKey type = e_type_key_ext(E_TypeKind_Function, procedure->type_idx, e_parse_ctx_module_idx_from_rdi(rdi)); - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); - String8List type_lhs_parts = {0}; - e_type_lhs_string_from_key(scratch.arena, type, &type_lhs_parts, 0, 0); - String8List type_rhs_parts = {0}; - e_type_rhs_string_from_key(scratch.arena, type, &type_rhs_parts, 0); - str8_list_concat_in_place(&parts, &type_lhs_parts); - str8_list_push(scratch.arena, &parts, name); - str8_list_concat_in_place(&parts, &type_rhs_parts); - result = str8_list_join(arena, &parts, 0); + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + DR_FStrList fstrs = {0}; + UI_TagF("weak") + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[rd_icon_kind_from_code_name(result.cmd_name)], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + } + result.expr_fstrs = fstrs; } else { - result = str8_lit("???"); + result.expr_fstrs = rd_title_fstrs_from_code_name(arena, result.cmd_name); } + result.flags |= RD_WatchCellFlag_Button; } + + //- rjf: files -> button for file + else if(result.file_path.size != 0) + { + result.expr_fstrs = rd_title_fstrs_from_file_path(arena, result.file_path); + result.flags |= RD_WatchCellFlag_Button; + } + + //- rjf: catchall cell -> need to form "left-hand-side", or "meta" string, for expression, and/or value string else { - result = str8_lit("???"); + //- rjf: build left-hand-side strings + DR_FStrList expr_fstrs = {0}; + if(cell->flags & RD_WatchCellFlag_Expr) + { + B32 is_non_code = 0; + String8 expr_string = {0}; + + // rjf: if this cell has a meta-display-name, then use that + if(expr_string.size == 0) + { + for(E_Type *t = e_type_from_key(cell->eval.irtree.type_key); + t != &e_type_nil; + t = e_type_from_key(t->direct_type_key)) + { + if(t->kind == E_TypeKind_MetaDisplayName) + { + is_non_code = 1; + expr_string = t->name; + break; + } + } + } + + // rjf: if this cell has no string specified, then we need to synthesize one from the evaluation + if(expr_string.size == 0) + { + // rjf: defaultly fill the cell's expression string, before trying other things + expr_string = cell->eval.string; + + // rjf: try to form a simpler expression string out of the expression tree itself, *if* this + // is not an editable expression, and if this evaluation was successful, and if this evaluation + // has a parent + if(!e_key_match(cell->eval.parent_key, e_key_zero()) && + !(block_type->flags & E_TypeFlag_EditableChildren) && + cell->eval.msgs.max_kind == E_MsgKind_Null) + { + // rjf: first, locate a notable expression - we special-case things like member accesses + // or array indices, so we should grab those if possible + E_Expr *notable_expr = cell->eval.expr; + for(B32 good = 0; !good;) + { + switch(notable_expr->kind) + { + default:{good = 1;}break; + case E_ExprKind_Address: + case E_ExprKind_Deref: + case E_ExprKind_Cast: + { + notable_expr = notable_expr->last; + }break; + case E_ExprKind_Ref: + { + notable_expr = notable_expr->ref; + }break; + } + } + + // rjf: generate expression extension string based on our notable expression + switch(notable_expr->kind) + { + // rjf: default case -> just take whatever string was directly passed via the evaluation + default:{}break; + + // rjf: array indices -> fast path to [index] + case E_ExprKind_ArrayIndex: + { + expr_string = push_str8f(arena, "[%S]", e_string_from_expr(arena, notable_expr->last, str8_zero())); + }break; + + // rjf: member accesses -> fast-path to .name + case E_ExprKind_MemberAccess: + { + Temp scratch = scratch_begin(&arena, 1); + + // TODO(rjf): @cfg need to build inheritance tooltips +#if 0 + if(member.inheritance_key_chain.count != 0) + { + String8List strings = {0}; + for(E_TypeKeyNode *n = member.inheritance_key_chain.first; n != 0; n = n->next) + { + String8 base_class_name = e_type_string_from_key(scratch.arena, n->v); + str8_list_push(scratch.arena, &strings, base_class_name); + } + result.inheritance_tooltip = str8_list_join(arena, &strings, &(StringJoin){.sep = str8_lit_comp("::")}); + } +#endif + + // rjf: in meta-evaluation spaces, we will try to look up into our vocabulary map + // to see if we have a fancy display string for this member. otherwise, we will just + // do a code-string of ".member_name" + String8 member_name = notable_expr->first->next->string; + String8 fancy_name = {0}; + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity || + cell->eval.space.kind == E_SpaceKind_File || + cell->eval.space.kind == E_SpaceKind_FileSystem) + { + fancy_name = rd_display_from_code_name(member_name); + } + if(fancy_name.size != 0) + { + is_non_code = 1; + expr_string = fancy_name; + } + else if(member_name.size != 0) + { + expr_string = push_str8f(arena, ".%S", member_name); + } + scratch_end(scratch); + }break; + } + } + } + + // rjf: use expression string / params to generate fancy strings + if(is_non_code) + { + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), font_size, 0, 0}; + dr_fstrs_push_new(arena, &expr_fstrs, ¶ms, expr_string); + } + else + { + expr_fstrs = rd_fstrs_from_code_string(arena, 1, 0, ui_color_from_name(str8_lit("text")), expr_string); + } + } + + //- rjf: evaluation -> need to form value string + DR_FStrList eval_fstrs = {0}; + if(!(cell->flags & RD_WatchCellFlag_NoEval)) + { + // rjf: determine string generation parameters based on evaluation + EV_StringParams string_params = {string_flags, 10}; + { + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCfg || + cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity) + { + string_params.flags |= EV_StringFlag_DisableStringQuotes|EV_StringFlag_DisableAddresses; + } + if(cell->eval.space.kind == RD_EvalSpaceKind_MetaCtrlEntity && + rd_ctrl_entity_from_eval_space(cell->eval.space)->kind == CTRL_EntityKind_Module) + { + string_params.radix = 16; + } + if(cell->eval.space.kind == RD_EvalSpaceKind_CtrlEntity && + rd_ctrl_entity_from_eval_space(cell->eval.space)->kind == CTRL_EntityKind_Thread) + { + string_params.radix = 16; + } + } + + // rjf: determine if code + B32 is_code = 1; + { + E_Type *type = e_type_from_key(e_type_key_unwrap(cell->eval.irtree.type_key, E_TypeUnwrapFlag_Meta)); + if(type->flags & (E_TypeFlag_IsPlainText|E_TypeFlag_IsPathText)) + { + is_code = 0; + } + } + + // rjf: generate string based on that expression & fill + String8 string = rd_value_string_from_eval(arena, rd_view_query_input(), &string_params, font, font_size, max_size_px, cell->eval); + if(is_code) + { + eval_fstrs = rd_fstrs_from_code_string(arena, 1, 0, ui_color_from_name(str8_lit("text")), string); + } + else UI_TagF("weak") + { + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), font_size, 0, 0}; + dr_fstrs_push_new(arena, &eval_fstrs, ¶ms, string); + result.flags |= RD_WatchCellFlag_IsNonCode; + } + } + + //- rjf: if we have only the expression, then use the expression as the value + if(cell->flags & RD_WatchCellFlag_NoEval) + { + result.eval_fstrs = expr_fstrs; + } + else + { + result.expr_fstrs = expr_fstrs; + result.eval_fstrs = eval_fstrs; + } } - di_scope_close(di_scope); - scratch_end(scratch); + }break; + + //- rjf: unattached processes + case RD_EvalSpaceKind_MetaUnattachedProcess: + { + U64 pid = cell->eval.value.u128.u64[0]; + String8 name = e_string_from_id(cell->eval.value.u128.u64[1]); + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + DR_FStrList fstrs = {0}; + UI_TagF("weak") + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[RD_IconKind_Scheduler], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + } + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, push_str8f(arena, "(PID: %I64u)", pid)); + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, name); + result.expr_fstrs = fstrs; + }break; + + //- rjf: unattached processes + case RD_EvalSpaceKind_MetaTheme: + { + String8 name = e_string_from_id(cell->eval.value.u64); + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + DR_FStrList fstrs = {0}; + UI_TagF("weak") + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[RD_IconKind_Palette], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + } + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, name); + { + HS_Scope *hs_scope = hs_scope_open(); + MD_Node *theme_tree = rd_theme_tree_from_name(scratch.arena, hs_scope, name); + U64 color_idx = 0; + for(MD_Node *n = theme_tree; color_idx < 4 && !md_node_is_nil(n); n = md_node_rec_depth_first_pre(n, theme_tree).next) + { + if(str8_match(n->string, str8_lit("theme_color"), 0)) + { + String8 tags = md_child_from_string(n, str8_lit("tags"), 0)->first->string; + if(str8_match(tags, str8_lit("background"), 0) || + str8_match(tags, str8_lit("text"), 0) || + str8_match(tags, str8_lit("focus border"), 0) || + str8_match(tags, str8_lit("menu_bar background"), 0) || + str8_match(tags, str8_lit("tab background"), 0) || + str8_match(tags, str8_lit("code_default"), 0)) + { + U64 color = 0; + if(try_u64_from_str8_c_rules(md_child_from_string(n, str8_lit("value"), 0)->first->string, &color)) + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[RD_IconKind_CircleFilled], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = linear_from_srgba(rgba_from_u32((U32)color))); + color_idx += 1; + } + } + } + } + hs_scope_close(hs_scope); + } + result.eval_fstrs = fstrs; }break; } - if(col->dequote_string && - result.size >= 2 && - result.str[0] == '"' && - result.str[result.size-1] == '"') - { - result = str8_skip(str8_chop(result, 1), 1); - result = raw_from_escaped_str8(arena, result); - } - if(col->rangify_braces && result.size >= 2 && - result.str[0] == '{' && - result.str[result.size-1] == '}') - { - result = push_str8_copy(arena, result); - result.str[0] = '['; - result.str[result.size-1] = ')'; - } - ProfEnd(); + scratch_end(scratch); return result; } //- rjf: table coordinates -> text edit state internal RD_WatchViewTextEditState * -rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchViewPoint pt) +rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchPt pt) { RD_WatchViewTextEditState *result = &wv->dummy_text_edit_state; if(wv->text_edit_state_slots_count != 0 && wv->text_editing != 0) @@ -1198,7 +1964,7 @@ rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchViewPoint p U64 slot_idx = hash%wv->text_edit_state_slots_count; for(RD_WatchViewTextEditState *s = wv->text_edit_state_slots[slot_idx]; s != 0; s = s->pt_hash_next) { - if(rd_watch_view_point_match(pt, s->pt)) + if(rd_watch_pt_match(pt, s->pt)) { result = s; break; @@ -1208,4595 +1974,15 @@ rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchViewPoint p return result; } -//- rjf: watch view column state mutation - -internal RD_WatchViewColumn * -rd_watch_view_column_alloc_(RD_WatchViewState *wv, RD_WatchViewColumnKind kind, F32 pct, RD_WatchViewColumnParams *params) -{ - if(!wv->free_column) - { - RD_WatchViewColumn *col = push_array(wv->column_arena, RD_WatchViewColumn, 1); - SLLStackPush(wv->free_column, col); - } - RD_WatchViewColumn *col = wv->free_column; - SLLStackPop(wv->free_column); - DLLPushBack(wv->first_column, wv->last_column, col); - wv->column_count += 1; - col->kind = kind; - col->pct = pct; - col->string_size = Min(sizeof(col->string_buffer), params->string.size); - MemoryCopy(col->string_buffer, params->string.str, col->string_size); - col->display_string_size = Min(sizeof(col->display_string_buffer), params->display_string.size); - MemoryCopy(col->display_string_buffer, params->display_string.str, col->display_string_size); - col->view_rule_size = Min(sizeof(col->view_rule_buffer), params->view_rule.size); - MemoryCopy(col->view_rule_buffer, params->view_rule.str, col->view_rule_size); - col->is_non_code = params->is_non_code; - col->dequote_string = params->dequote_string; - col->rangify_braces = params->rangify_braces; - return col; -} - -internal void -rd_watch_view_column_release(RD_WatchViewState *wv, RD_WatchViewColumn *col) -{ - DLLRemove(wv->first_column, wv->last_column, col); - SLLStackPush(wv->free_column, col); - wv->column_count -= 1; -} - -//- rjf: watch view main hooks - -internal void -rd_watch_view_init(RD_WatchViewState *ewv) -{ - if(ewv->initialized == 0) - { - ewv->initialized = 1; - ewv->column_arena = rd_push_view_arena(); - ewv->text_edit_arena = rd_push_view_arena(); - } -} - -internal void -rd_watch_view_build(RD_WatchViewState *ewv, RD_WatchViewFlags flags, String8 root_expr, String8 root_view_rule, B32 modifiable, U32 default_radix, Rng2F32 rect) -{ - ProfBeginFunction(); - DI_Scope *di_scope = di_scope_open(); - Temp scratch = scratch_begin(0, 0); - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - F32 entity_hover_t_rate = rd_setting_val_from_code(RD_SettingCode_HoverAnimations).s32 ? (1 - pow_f32(2, (-20.f * rd_state->frame_dt))) : 1.f; - - ////////////////////////////// - //- rjf: unpack arguments - // - EV_ViewRuleList *top_level_view_rules = ev_view_rule_list_from_string(scratch.arena, root_view_rule); - String8 eval_view_key_string = push_str8f(scratch.arena, "eval_view_watch_%p", ewv); - EV_View *eval_view = rd_ev_view_from_key(d_hash_from_string(eval_view_key_string)); - String8 filter = rd_view_filter(); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - S64 num_possible_visible_rows = (S64)(dim_2f32(rect).y/row_height_px); - F32 row_string_max_size_px = dim_2f32(rect).x; - EV_StringFlags string_flags = 0; - if(flags & RD_WatchViewFlag_PrettyNameMembers) - { - string_flags |= EV_StringFlag_PrettyNames; - } - RD_WatchViewRowCtrl row_ctrls_[] = - { - {RD_EntityKind_Target, CTRL_EntityKind_Null, RD_CmdKind_LaunchAndRun }, - {RD_EntityKind_Target, CTRL_EntityKind_Null, RD_CmdKind_LaunchAndInit }, - {RD_EntityKind_Target, CTRL_EntityKind_Null, RD_CmdKind_SelectEntity }, - {RD_EntityKind_Target, CTRL_EntityKind_Null, RD_CmdKind_RemoveEntity }, - {RD_EntityKind_Breakpoint, CTRL_EntityKind_Null, RD_CmdKind_EnableEntity }, - {RD_EntityKind_Breakpoint, CTRL_EntityKind_Null, RD_CmdKind_RemoveEntity }, - {RD_EntityKind_FilePathMap, CTRL_EntityKind_Null, RD_CmdKind_RemoveEntity }, - {RD_EntityKind_AutoViewRule,CTRL_EntityKind_Null, RD_CmdKind_RemoveEntity }, - {RD_EntityKind_Nil, CTRL_EntityKind_Machine, RD_CmdKind_FreezeEntity }, - {RD_EntityKind_Nil, CTRL_EntityKind_Process, RD_CmdKind_Kill }, - {RD_EntityKind_Nil, CTRL_EntityKind_Process, RD_CmdKind_FreezeEntity }, - {RD_EntityKind_Nil, CTRL_EntityKind_Thread, RD_CmdKind_SelectThread }, - {RD_EntityKind_Nil, CTRL_EntityKind_Thread, RD_CmdKind_FreezeEntity }, - }; - RD_WatchViewRowCtrl *row_ctrls = row_ctrls_; - U64 row_ctrls_count = ArrayCount(row_ctrls_); - - ////////////////////////////// - //- rjf: root-level view rule which has a ui hook? call into that to build the UI - // - B32 is_top_level_hook = 0; - { - RD_ViewRuleInfo *hook_rule_info = 0; - MD_Node *hook_rule_root = &md_nil_node; - for(EV_ViewRuleNode *n = top_level_view_rules->first; n != 0; n = n->next) - { - RD_ViewRuleInfo *rule_info = rd_view_rule_info_from_string(n->v.root->string); - if(rule_info != &rd_nil_view_rule_info && rule_info->ui != 0) - { - hook_rule_info = rule_info; - hook_rule_root = n->v.root; - break; - } - } - if(hook_rule_info) - { - hook_rule_info->ui(root_expr, hook_rule_root, rect); - is_top_level_hook = 1; - } - } - - ////////////////////////////// - //- rjf: determine autocompletion string - // - String8 autocomplete_hint_string = {0}; - if(!is_top_level_hook) - { - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->kind == UI_EventKind_AutocompleteHint) - { - autocomplete_hint_string = evt->string; - break; - } - } - } - - ////////////////////////////// - //- rjf: consume events & perform navigations/edits - calculate state - // - EV_BlockTree block_tree = {0}; - EV_BlockRangeList block_ranges = {0}; - UI_ScrollListRowBlockArray row_blocks = {0}; - Vec2S64 cursor_tbl = {0}; - Vec2S64 mark_tbl = {0}; - Rng2S64 selection_tbl = {0}; - if(!is_top_level_hook) ProfScope("consume events & perform navigations/edits - calculate state") UI_Focus(UI_FocusKind_On) - { - B32 state_dirty = 1; - B32 snap_to_cursor = 0; - B32 cursor_dirty__tbl = 0; - B32 take_autocomplete = 0; - for(UI_Event *event = 0;;) - { - ////////////////////////// - //- rjf: state -> viz blocks - // - if(state_dirty) ProfScope("state -> viz blocks") - { - MemoryZeroStruct(&block_tree); - MemoryZeroStruct(&block_ranges); - ev_key_set_expansion(eval_view, ev_key_root(), ev_key_make(ev_hash_from_key(ev_key_root()), 1), 1); - block_tree = ev_block_tree_from_string(scratch.arena, eval_view, filter, root_expr, top_level_view_rules); - block_ranges = ev_block_range_list_from_tree(scratch.arena, &block_tree); - } - - ////////////////////////// - //- rjf: block ranges -> ui row blocks - // - ProfScope("block ranges -> ui row blocks") - { - UI_ScrollListRowBlockChunkList row_block_chunks = {0}; - for(EV_BlockRangeNode *n = block_ranges.first; n != 0; n = n->next) - { - UI_ScrollListRowBlock block = {0}; - block.row_count = dim_1u64(n->v.range); - block.item_count = n->v.block->single_item ? 1 : dim_1u64(n->v.range); - ui_scroll_list_row_block_chunk_list_push(scratch.arena, &row_block_chunks, 256, &block); - } - row_blocks = ui_scroll_list_row_block_array_from_chunk_list(scratch.arena, &row_block_chunks); - } - - ////////////////////////// - //- rjf: conclude state update - // - if(state_dirty) - { - state_dirty = 0; - } - - ////////////////////////////// - //- rjf: 2D table coordinates * blocks -> stable cursor state - // - if(cursor_dirty__tbl) - { - cursor_dirty__tbl = 0; - struct - { - RD_WatchViewPoint *pt_state; - Vec2S64 pt_tbl; - } - points[] = - { - {&ewv->cursor, cursor_tbl}, - {&ewv->mark, mark_tbl}, - }; - for(U64 point_idx = 0; point_idx < ArrayCount(points); point_idx += 1) - { - EV_Key last_key = points[point_idx].pt_state->key; - EV_Key last_parent_key = points[point_idx].pt_state->parent_key; - points[point_idx].pt_state[0] = rd_watch_view_point_from_tbl(&block_ranges, points[point_idx].pt_tbl); - if(ev_key_match(ev_key_zero(), points[point_idx].pt_state->key)) - { - points[point_idx].pt_state->key = last_parent_key; - EV_ExpandNode *node = ev_expand_node_from_key(eval_view, last_parent_key); - for(EV_ExpandNode *n = node; n != 0; n = n->parent) - { - points[point_idx].pt_state->key = n->key; - if(n->expanded == 0) - { - break; - } - } - } - if(point_idx == 0 && - (!ev_key_match(ewv->cursor.key, last_key) || - !ev_key_match(ewv->cursor.parent_key, last_parent_key))) - { - ewv->text_editing = 0; - } - } - ewv->next_cursor = ewv->cursor; - ewv->next_mark = ewv->mark; - } - - ////////////////////////// - //- rjf: stable cursor state * blocks -> 2D table coordinates - // - EV_WindowedRowList mark_rows = {0}; - Rng2S64 cursor_tbl_range = {0}; - { - // rjf: compute 2d table coordinates - cursor_tbl = rd_tbl_from_watch_view_point(&block_ranges, ewv->cursor); - mark_tbl = rd_tbl_from_watch_view_point(&block_ranges, ewv->mark); - - // rjf: compute row at initial selection point (or just cursor point) - mark_rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, mark_tbl.y), - ui_scroll_list_row_from_item(&row_blocks, mark_tbl.y)+1)); - - // rjf: compute legal coordinate range, given selection-defining row - Rng1S64 cursor_x_range = r1s64(0, ewv->column_count-1); - if(mark_rows.first != 0) - { - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(mark_rows.first); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, mark_rows.first, &row_info); - if(row_kind == RD_WatchViewRowKind_PrettyEntityControls) - { - U64 row_ctrl_count = 0; - for EachIndex(idx, row_ctrls_count) - { - if(row_ctrls[idx].entity_kind == row_info.collection_entity->kind && - row_ctrls[idx].ctrl_entity_kind == row_info.collection_ctrl_entity->kind) - { - row_ctrl_count += 1; - } - } - cursor_x_range = r1s64(1, 1+row_ctrl_count); - } - } - cursor_tbl_range = r2s64(v2s64(cursor_x_range.min, 0), v2s64(cursor_x_range.max, block_tree.total_item_count-1)); - - // rjf: clamp x positions of cursor/mark tbl - for EachEnumVal(Axis2, axis) - { - cursor_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), cursor_tbl.v[axis]); - mark_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), mark_tbl.v[axis]); - } - - // rjf: form selection range table coordinates - selection_tbl = r2s64p(Min(cursor_tbl.x, mark_tbl.x), Min(cursor_tbl.y, mark_tbl.y), - Max(cursor_tbl.x, mark_tbl.x), Max(cursor_tbl.y, mark_tbl.y)); - } - - ////////////////////////// - //- rjf: [table] snap to cursor - // - if(snap_to_cursor) - { - Rng1S64 item_range = r1s64(0, block_tree.total_item_count); - Rng1S64 row_range = r1s64(0, block_tree.total_row_count); - Rng1S64 scroll_row_idx_range = r1s64(row_range.min, ClampBot(row_range.min, row_range.max-1)); - S64 cursor_item_idx = cursor_tbl.y; - if(item_range.min <= cursor_item_idx && cursor_item_idx <= item_range.max) - { - UI_ScrollPt *scroll_pt = &scroll_pos.y; - - //- rjf: compute visible row range - Rng1S64 visible_row_range = r1s64(scroll_pt->idx + 0 - !!(scroll_pt->off < 0), - scroll_pt->idx + 0 + num_possible_visible_rows); - - //- rjf: compute cursor row range from cursor item - Rng1S64 cursor_visibility_row_range = {0}; - if(row_blocks.count == 0) - { - cursor_visibility_row_range = r1s64(cursor_item_idx-2, cursor_item_idx+3); - } - else - { - cursor_visibility_row_range.min = (S64)ui_scroll_list_row_from_item(&row_blocks, (U64)cursor_item_idx) - 1; - cursor_visibility_row_range.max = cursor_visibility_row_range.min + 3; - } - - //- rjf: compute deltas & apply - S64 min_delta = Min(0, cursor_visibility_row_range.min-visible_row_range.min); - S64 max_delta = Max(0, cursor_visibility_row_range.max-visible_row_range.max); - S64 new_idx = scroll_pt->idx+min_delta+max_delta; - new_idx = clamp_1s64(scroll_row_idx_range, new_idx); - ui_scroll_pt_target_idx(scroll_pt, new_idx); - } - } - - ////////////////////////////// - //- rjf: apply cursor/mark rugpull change - // - B32 cursor_rugpull = 0; - if(!rd_watch_view_point_match(ewv->cursor, ewv->next_cursor)) - { - cursor_rugpull = 1; - ewv->cursor = ewv->next_cursor; - ewv->mark = ewv->next_mark; - } - - ////////////////////////// - //- rjf: grab next event, if any - otherwise exit the loop, as we now have - // the most up-to-date state - // - B32 next_event_good = ui_next_event(&event); - if(!cursor_rugpull && (!next_event_good || !ui_is_focus_active())) - { - break; - } - UI_Event dummy_evt = zero_struct; - UI_Event *evt = &dummy_evt; - if(next_event_good) - { - evt = event; - } - B32 taken = 0; - - ////////////////////////// - //- rjf: begin editing on some operations - // - if(!ewv->text_editing && - (evt->kind == UI_EventKind_Text || - evt->flags & UI_EventFlag_Paste || - (evt->kind == UI_EventKind_Press && evt->slot == UI_EventActionSlot_Edit)) && - selection_tbl.min.x == selection_tbl.max.x && - (selection_tbl.min.y != 0 || selection_tbl.min.y != 0)) - { - Vec2S64 selection_dim = dim_2s64(selection_tbl); - arena_clear(ewv->text_edit_arena); - ewv->text_edit_state_slots_count = u64_up_to_pow2(selection_dim.y+1); - ewv->text_edit_state_slots_count = Max(ewv->text_edit_state_slots_count, 64); - ewv->text_edit_state_slots = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState*, ewv->text_edit_state_slots_count); - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y), - ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y)+1)); - EV_Row *row = rows.first; - for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1, row = row->next) - { - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(row); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, row, &row_info); - if(row_kind == RD_WatchViewRowKind_Normal) - { - ewv->text_editing = 1; - for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) - { - RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); - String8 string = rd_string_from_eval_viz_row_column(scratch.arena, eval_view, row, col, string_flags, default_radix, ui_top_font(), ui_top_font_size(), row_string_max_size_px); - string.size = Min(string.size, sizeof(ewv->dummy_text_edit_state.input_buffer)); - RD_WatchViewPoint pt = {x, row->block->key, row->key}; - U64 hash = ev_hash_from_key(pt.key); - U64 slot_idx = hash%ewv->text_edit_state_slots_count; - RD_WatchViewTextEditState *edit_state = push_array(ewv->text_edit_arena, RD_WatchViewTextEditState, 1); - SLLStackPush_N(ewv->text_edit_state_slots[slot_idx], edit_state, pt_hash_next); - edit_state->pt = pt; - edit_state->cursor = txt_pt(1, string.size+1); - edit_state->mark = txt_pt(1, 1); - edit_state->input_size = string.size; - MemoryCopy(edit_state->input_buffer, string.str, string.size); - edit_state->initial_size = string.size; - MemoryCopy(edit_state->initial_buffer, string.str, string.size); - } - } - } - } - - ////////////////////////// - //- rjf: [table] do cell-granularity multi-cursor 'accept' operations (expansions / etc.); if - // cannot apply to multi-cursor, then just don't take the event - // - if(!ewv->text_editing && evt->slot == UI_EventActionSlot_Accept) - { - taken = 1; - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y), - ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y)+1)); - EV_Row *row = rows.first; - for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row != 0; y += 1, row = row->next) - { - // rjf: unpack row info - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(row); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, row, &row_info); - - // rjf: loop through X selections and perform operations for each - for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) - { - //- rjf: determine operation for this cell - typedef enum OpKind - { - OpKind_Null, - OpKind_DoExpand, - } - OpKind; - OpKind kind = OpKind_Null; - switch(row_kind) - { - default:{}break; - case RD_WatchViewRowKind_Normal: - { - RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: {kind = OpKind_DoExpand;}break; - } - }break; - case RD_WatchViewRowKind_PrettyEntityControls: - if((!rd_entity_is_nil(row_info.collection_entity) || row_info.collection_ctrl_entity != &ctrl_entity_nil) && selection_tbl.min.x == 1 && selection_tbl.max.x == 1) - { - kind = OpKind_DoExpand; - }break; - } - - //- rjf: perform operation - switch(kind) - { - default:{taken = 0;}break; - case OpKind_DoExpand: - if(ev_row_is_expandable(row)) - { - B32 is_expanded = ev_expansion_from_key(eval_view, row->key); - ev_key_set_expansion(eval_view, row->block->key, row->key, !is_expanded); - }break; - } - } - } - } - - ////////////////////////// - //- rjf: [text] apply textual edits - // - if(ewv->text_editing) - { - B32 editing_complete = ((evt->kind == UI_EventKind_Press && (evt->slot == UI_EventActionSlot_Cancel || evt->slot == UI_EventActionSlot_Accept)) || - (evt->kind == UI_EventKind_Navigate && evt->delta_2s32.y != 0) || - cursor_rugpull); - rd_state->text_edit_mode = 1; - if(editing_complete || - ((evt->kind == UI_EventKind_Edit || - evt->kind == UI_EventKind_Navigate || - evt->kind == UI_EventKind_Text) && - evt->delta_2s32.y == 0)) - { - taken = 1; - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y), - ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y)+1)); - EV_Row *row = rows.first; - for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1, row = row->next) - { - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(row); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, row, &row_info); - for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) - { - RD_WatchViewPoint pt = rd_watch_view_point_from_tbl(&block_ranges, v2s64(x, y)); - RD_WatchViewTextEditState *edit_state = rd_watch_view_text_edit_state_from_pt(ewv, pt); - String8 string = str8(edit_state->input_buffer, edit_state->input_size); - UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); - - // rjf: copy - if(op.flags & UI_TxtOpFlag_Copy && selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y) - { - os_set_clipboard_text(op.copy); - } - - // rjf: any valid op & autocomplete hint? -> perform autocomplete first, then re-compute op - if(autocomplete_hint_string.size != 0) - { - take_autocomplete = 1; - String8 word_query = rd_autocomp_query_word_from_input_string_off(string, edit_state->cursor.column-1); - U64 word_off = (U64)(word_query.str - string.str); - String8 new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); - new_string.size = Min(sizeof(edit_state->input_buffer), new_string.size); - MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); - edit_state->input_size = new_string.size; - edit_state->cursor = edit_state->mark = txt_pt(1, word_off+1+autocomplete_hint_string.size); - string = str8(edit_state->input_buffer, edit_state->input_size); - op = ui_single_line_txt_op_from_event(scratch.arena, evt, string, edit_state->cursor, edit_state->mark); - } - - // rjf: cancel? -> revert to initial string - if(editing_complete && evt->slot == UI_EventActionSlot_Cancel) - { - string = str8(edit_state->initial_buffer, edit_state->initial_size); - } - - // rjf: obtain edited string - String8 new_string = string; - if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) - { - new_string = ui_push_string_replace_range(scratch.arena, string, r1s64(op.range.min.column, op.range.max.column), op.replace); - } - - // rjf: commit to edit state - new_string.size = Min(new_string.size, sizeof(edit_state->input_buffer)); - MemoryCopy(edit_state->input_buffer, new_string.str, new_string.size); - edit_state->input_size = new_string.size; - edit_state->cursor = op.cursor; - edit_state->mark = op.mark; - - // rjf: commit edited cell string - Vec2S64 tbl = v2s64(x, y); - RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); - { - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: - if(modifiable) - { - if(row_info.collection_entity_kind != RD_EntityKind_Nil) - { - RD_Entity *entity = row_info.collection_entity; - if(!rd_entity_is_nil(entity) || editing_complete) - { - if(rd_entity_is_nil(entity) && new_string.size != 0) - { - entity = rd_entity_alloc(rd_entity_root(), row_info.collection_entity_kind); - rd_entity_equip_cfg_src(entity, RD_CfgSrc_Project); - } - if(!rd_entity_is_nil(entity)) - { - rd_entity_equip_name(entity, new_string); - } - state_dirty = 1; - snap_to_cursor = 1; - } - } - }break; - case RD_WatchViewColumnKind_Member: - case RD_WatchViewColumnKind_Value: - { - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, y), - ui_scroll_list_row_from_item(&row_blocks, y)+1)); - if(rows.first != 0) - { - B32 should_commit_asap = editing_complete; - E_Expr *expr = rd_expr_from_watch_view_row_column(scratch.arena, eval_view, row, col); - E_Eval dst_eval = e_eval_from_expr(scratch.arena, expr); - if(dst_eval.space.kind == RD_EvalSpaceKind_MetaEntity) - { - should_commit_asap = 1; - } - else if(evt->slot != UI_EventActionSlot_Cancel) - { - should_commit_asap = editing_complete; - } - if(should_commit_asap) - { - B32 success = 0; - success = rd_commit_eval_value_string(dst_eval, new_string, !col->dequote_string); - if(!success) - { - log_user_error(str8_lit("Could not commit value successfully.")); - } - } - } - }break; - case RD_WatchViewColumnKind_Type:{}break; - case RD_WatchViewColumnKind_ViewRule: - if(editing_complete) - { - RD_WatchViewPoint pt = rd_watch_view_point_from_tbl(&block_ranges, tbl); - ev_key_set_view_rule(eval_view, pt.key, new_string); - if(row_info.collection_entity_kind != RD_EntityKind_Nil) - { - RD_Entity *entity = row_info.collection_entity; - RD_Entity *view_rule = rd_entity_child_from_kind(entity, RD_EntityKind_ViewRule); - if(rd_entity_is_nil(view_rule) && new_string.size != 0) - { - view_rule = rd_entity_alloc(entity, RD_EntityKind_ViewRule); - } - else if(!rd_entity_is_nil(view_rule) && new_string.size == 0) - { - rd_entity_mark_for_deletion(view_rule); - } - if(new_string.size != 0) - { - rd_entity_equip_name(view_rule, new_string); - } - state_dirty = 1; - snap_to_cursor = 1; - } - }break; - } - } - } - } - } - if(editing_complete) - { - ewv->text_editing = 0; - } - } - - ////////////////////////// - //- rjf: [table] do cell-granularity copies - // - if(!ewv->text_editing && evt->flags & UI_EventFlag_Copy) - { - taken = 1; - String8List strs = {0}; - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y), - ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y)+1)); - EV_Row *row = rows.first; - for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y && row != 0; y += 1, row = row->next) - { - for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) - { - RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); - String8 cell_string = rd_string_from_eval_viz_row_column(scratch.arena, eval_view, row, col, string_flags|EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), row_string_max_size_px); - cell_string = str8_skip_chop_whitespace(cell_string); - U64 comma_pos = str8_find_needle(cell_string, 0, str8_lit(","), 0); - if(selection_tbl.min.x != selection_tbl.max.x || selection_tbl.min.y != selection_tbl.max.y) - { - str8_list_pushf(scratch.arena, &strs, "%s%S%s%s", - comma_pos < cell_string.size ? "\"" : "", - cell_string, - comma_pos < cell_string.size ? "\"" : "", - x+1 <= selection_tbl.max.x ? "," : ""); - } - else - { - str8_list_push(scratch.arena, &strs, cell_string); - } - } - if(y+1 <= selection_tbl.max.y) - { - str8_list_push(scratch.arena, &strs, str8_lit("\n")); - } - } - String8 string = str8_list_join(scratch.arena, &strs, 0); - os_set_clipboard_text(string); - } - - ////////////////////////// - //- rjf: [table] do cell-granularity deletions - // - if(!ewv->text_editing && evt->flags & UI_EventFlag_Delete) - { - taken = 1; - state_dirty = 1; - snap_to_cursor = 1; - RD_EntityList entities_to_remove = {0}; - RD_WatchViewPoint next_cursor_pt = {0}; - B32 next_cursor_set = 0; - EV_WindowedRowList rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y), - ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y)+1)); - EV_Row *row = rows.first; - for(S64 y = selection_tbl.min.y; y <= selection_tbl.max.y; y += 1, row = row->next) - { - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(row); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, row, &row_info); - for(S64 x = selection_tbl.min.x; x <= selection_tbl.max.x; x += 1) - { - Vec2S64 tbl = v2s64(x, y); - RD_WatchViewPoint pt = rd_watch_view_point_from_tbl(&block_ranges, tbl); - RD_WatchViewColumn *col = rd_watch_view_column_from_x(ewv, x); - if(tbl.y != 0 && (col->kind == RD_WatchViewColumnKind_Expr || row_kind == RD_WatchViewRowKind_PrettyEntityControls) && - row_info.collection_entity_kind != RD_EntityKind_Nil) - { - RD_Entity *entity = row_info.collection_entity; - if(!rd_entity_is_nil(entity)) - { - rd_entity_list_push(scratch.arena, &entities_to_remove, entity); - U64 deleted_id = row->key.child_id; - U64 deleted_num = row->block->expand_view_rule_info->expr_expand_num_from_id(deleted_id, row->block->expand_view_rule_info_user_data); - if(deleted_num != 0) - { - U64 fallback_id_next = row->block->expand_view_rule_info->expr_expand_id_from_num(deleted_num+1, row->block->expand_view_rule_info_user_data); - U64 fallback_id_prev = row->block->expand_view_rule_info->expr_expand_id_from_num(deleted_num-1, row->block->expand_view_rule_info_user_data); - EV_Key parent_key = row->block->key; - EV_Key key = ev_key_make(row->key.parent_hash, fallback_id_next ? fallback_id_next : fallback_id_prev); - if(key.child_id == 0) - { - key = row->block->key; - parent_key = row->block->parent->key; - } - RD_WatchViewPoint new_pt = {0, parent_key, key}; - next_cursor_pt = new_pt; - next_cursor_set = 1; - } - } - } - else if(tbl.y != 0 && col->kind == RD_WatchViewColumnKind_ViewRule && row_kind == RD_WatchViewRowKind_Normal) - { - if(row_info.collection_entity_kind != RD_EntityKind_Nil) - { - RD_Entity *entity = row_info.collection_entity; - RD_Entity *view_rule = rd_entity_child_from_kind(entity, RD_EntityKind_ViewRule); - rd_entity_mark_for_deletion(view_rule); - } - ev_key_set_view_rule(eval_view, row->key, str8_zero()); - } - else if(tbl.y != 0 && (col->kind == RD_WatchViewColumnKind_Value || col->kind == RD_WatchViewColumnKind_Member) && row_kind == RD_WatchViewRowKind_Normal) - { - E_Expr *expr = rd_expr_from_watch_view_row_column(scratch.arena, eval_view, row, col); - E_Eval dst_eval = e_eval_from_expr(scratch.arena, expr); - rd_commit_eval_value_string(dst_eval, str8_zero(), 0); - } - } - } - for(RD_EntityNode *n = entities_to_remove.first; n != 0; n = n->next) - { - rd_entity_mark_for_deletion(n->entity); - } - if(next_cursor_set) - { - ewv->cursor = ewv->mark = ewv->next_cursor = ewv->next_mark = next_cursor_pt; - } - } - - ////////////////////////// - //- rjf: [table] apply deltas to cursor & mark - // - if(!ewv->text_editing && !(evt->flags & UI_EventFlag_Delete) && !(evt->flags & UI_EventFlag_Reorder)) - { - B32 cursor_tbl_min_is_empty_selection[Axis2_COUNT] = {0, 1}; - Vec2S32 delta = evt->delta_2s32; - if(evt->flags & UI_EventFlag_PickSelectSide && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) - { - if(delta.x > 0 || delta.y > 0) - { - cursor_tbl.x = selection_tbl.max.x; - cursor_tbl.y = selection_tbl.max.y; - } - else if(delta.x < 0 || delta.y < 0) - { - cursor_tbl.x = selection_tbl.min.x; - cursor_tbl.y = selection_tbl.min.y; - } - } - if(evt->flags & UI_EventFlag_ZeroDeltaOnSelect && !MemoryMatchStruct(&selection_tbl.min, &selection_tbl.max)) - { - MemoryZeroStruct(&delta); - } - B32 moved = 1; - switch(evt->delta_unit) - { - default:{moved = 0;}break; - case UI_EventDeltaUnit_Char: - { - for EachEnumVal(Axis2, axis) - { - cursor_tbl.v[axis] += delta.v[axis]; - if(cursor_tbl.v[axis] < cursor_tbl_range.min.v[axis]) - { - cursor_tbl.v[axis] = cursor_tbl_range.max.v[axis]; - } - if(cursor_tbl.v[axis] > cursor_tbl_range.max.v[axis]) - { - cursor_tbl.v[axis] = cursor_tbl_range.min.v[axis]; - } - cursor_tbl.v[axis] = clamp_1s64(r1s64(cursor_tbl_range.min.v[axis], cursor_tbl_range.max.v[axis]), cursor_tbl.v[axis]); - } - }break; - case UI_EventDeltaUnit_Word: - case UI_EventDeltaUnit_Line: - case UI_EventDeltaUnit_Page: - { - cursor_tbl.x = (delta.x>0 ? (cursor_tbl_range.max.x) : - delta.x<0 ? (cursor_tbl_range.min.x + !!cursor_tbl_min_is_empty_selection[Axis2_X]) : - cursor_tbl.x); - cursor_tbl.y += ((delta.y>0 ? +(num_possible_visible_rows-3) : - delta.y<0 ? -(num_possible_visible_rows-3) : - 0)); - cursor_tbl.y = clamp_1s64(r1s64(cursor_tbl_range.min.y + !!cursor_tbl_min_is_empty_selection[Axis2_Y], - cursor_tbl_range.max.y), - cursor_tbl.y); - }break; - case UI_EventDeltaUnit_Whole: - { - for EachEnumVal(Axis2, axis) - { - cursor_tbl.v[axis] = (delta.v[axis]>0 ? cursor_tbl_range.max.v[axis] : delta.v[axis]<0 ? cursor_tbl_range.min.v[axis] + !!cursor_tbl_min_is_empty_selection[axis] : cursor_tbl.v[axis]); - } - }break; - } - if(moved) - { - taken = 1; - cursor_dirty__tbl = 1; - snap_to_cursor = 1; - } - } - - ////////////////////////// - //- rjf: [table] stick table mark to cursor if needed - // - if(!ewv->text_editing) - { - if(taken && !(evt->flags & UI_EventFlag_KeepMark)) - { - mark_tbl = cursor_tbl; - } - } - - ////////////////////////// - //- rjf: [table] do cell-granularity reorders - // - if(!ewv->text_editing && evt->flags & UI_EventFlag_Reorder) - { - taken = 1; - if(filter.size == 0) - { - // rjf: determine blocks of each endpoint of the table selection - EV_Block *selection_endpoint_blocks[2] = - { - ev_block_range_from_num(&block_ranges, selection_tbl.min.y).block, - ev_block_range_from_num(&block_ranges, selection_tbl.max.y).block, - }; - - // rjf: pick shallowest block within which we can do reordering - U64 selection_depths[2] = - { - ev_depth_from_block(selection_endpoint_blocks[0]), - ev_depth_from_block(selection_endpoint_blocks[1]), - }; - EV_Block *selection_block = (selection_depths[1] < selection_depths[0] - ? selection_endpoint_blocks[1] - : selection_endpoint_blocks[0]); - - // rjf: find selection keys within the block in which we are doing reordering - EV_Key selection_keys_in_block[2] = {0}; - { - for EachElement(idx, selection_endpoint_blocks) - { - EV_Block *endpoint_block = selection_endpoint_blocks[idx]; - if(endpoint_block == selection_block) - { - selection_keys_in_block[idx] = ev_key_from_num(&block_ranges, selection_tbl.v[idx].y); - } - else - { - for(;endpoint_block->parent != selection_block && endpoint_block != &ev_nil_block;) - { - endpoint_block = endpoint_block->parent; - } - if(endpoint_block->parent == selection_block) - { - selection_keys_in_block[idx] = endpoint_block->key; - } - } - } - EV_Key fallback_key = {0}; - for EachElement(idx, selection_endpoint_blocks) - { - if(!ev_key_match(selection_keys_in_block[idx], ev_key_zero())) - { - fallback_key = selection_keys_in_block[idx]; - } - } - for EachElement(idx, selection_endpoint_blocks) - { - if(ev_key_match(selection_keys_in_block[idx], ev_key_zero())) - { - selection_keys_in_block[idx] = fallback_key; - } - } - } - - // rjf: determine collection info for the block - RD_EntityKind collection_entity_kind = RD_EntityKind_Nil; - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, selection_block->expr); - E_Type *type = e_type_from_key(scratch.arena, irtree.type_key); - for EachElement(idx, rd_collection_name_table) - { - if(str8_match(type->name, rd_collection_name_table[idx], 0)) - { - collection_entity_kind = rd_collection_entity_kind_table[idx]; - break; - } - } - - // rjf: map selection endpoints to entities - RD_Entity *first_entity = &rd_nil_entity; - RD_Entity *last_entity = &rd_nil_entity; - if(collection_entity_kind != RD_EntityKind_Nil) - { - first_entity = rd_entity_from_id(selection_keys_in_block[0].child_id); - last_entity = rd_entity_from_id(selection_keys_in_block[1].child_id); - } - - // rjf: reorder - if(!rd_entity_is_nil(first_entity) && !rd_entity_is_nil(last_entity)) - { - RD_Entity *first_entity_prev = &rd_nil_entity; - RD_Entity *last_entity_next = &rd_nil_entity; - for(RD_Entity *prev = first_entity->prev; !rd_entity_is_nil(prev); prev = prev->prev) - { - if(prev->kind == collection_entity_kind) - { - first_entity_prev = prev; - break; - } - } - for(RD_Entity *next = last_entity->next; !rd_entity_is_nil(next); next = next->next) - { - if(next->kind == collection_entity_kind) - { - last_entity_next = next; - break; - } - } - if(evt->delta_2s32.y < 0 && !rd_entity_is_nil(first_entity) && !rd_entity_is_nil(first_entity_prev)) - { - state_dirty = 1; - snap_to_cursor = 1; - rd_entity_change_parent(first_entity_prev, first_entity_prev->parent, first_entity_prev->parent, last_entity); - } - if(evt->delta_2s32.y > 0 && !rd_entity_is_nil(last_entity) && !rd_entity_is_nil(last_entity_next)) - { - state_dirty = 1; - snap_to_cursor = 1; - rd_entity_change_parent(last_entity_next, last_entity_next->parent, last_entity_next->parent, first_entity_prev); - } - } - } - } - - ////////////////////////// - //- rjf: consume event, if taken - // - if(taken && evt != &dummy_evt) - { - ui_eat_event(evt); - } - } - if(take_autocomplete) - { - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->kind == UI_EventKind_AutocompleteHint) - { - ui_eat_event(evt); - break; - } - } - } - } - - ////////////////////////////// - //- rjf: build ui - // - B32 pressed = 0; - if(!is_top_level_hook) ProfScope("build ui") - { - F32 **col_pcts = push_array(scratch.arena, F32*, ewv->column_count); - { - S64 x = 0; - for(RD_WatchViewColumn *c = ewv->first_column; c != 0; c = c->next, x += 1) - { - col_pcts[x] = &c->pct; - } - } - Rng1S64 visible_row_rng = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); - scroll_list_params.dim_px = dim_2f32(rect); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(ewv->column_count-1, block_tree.total_item_count)); - scroll_list_params.item_range = r1s64(0, block_tree.total_row_count - !!(flags & RD_WatchViewFlag_NoHeader)); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 0; - scroll_list_params.row_blocks = row_blocks; - } - UI_BoxFlags disabled_flags = ui_top_flags(); - if(d_ctrl_targets_running()) - { - disabled_flags |= UI_BoxFlag_Disabled; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &scroll_pos.y, - 0, - 0, - &visible_row_rng, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - UI_TableF(ewv->column_count, col_pcts, "table") - { - Vec2F32 scroll_list_view_off_px = ui_top_parent()->parent->view_off; - - //////////////////////////// - //- rjf: viz blocks -> rows - // - EV_WindowedRowList rows = {0}; - { - rows = ev_windowed_row_list_from_block_range_list(scratch.arena, eval_view, filter, &block_ranges, r1u64(visible_row_rng.min + !!(flags & RD_WatchViewFlag_NoHeader), visible_row_rng.max + 1 + !!(flags & RD_WatchViewFlag_NoHeader))); - } - - //////////////////////////// - //- rjf: build table - // - ProfScope("build table") - { - U64 global_row_idx = rows.count_before_semantic; - for(EV_Row *row = rows.first; row != 0; row = row->next, global_row_idx += 1) - { - //////////////////////// - //- rjf: skip header - // - if(global_row_idx == 0 && flags & RD_WatchViewFlag_NoHeader) - { - continue; - } - - //////////////////////// - //- rjf: unpack row info - // - ProfBegin("unpack row info"); - U64 row_hash = ev_hash_from_key(row->key); - U64 row_depth = ev_depth_from_block(row->block); - if(row_depth > 0) - { - row_depth -= 1; - } - B32 row_selected = (selection_tbl.min.y <= global_row_idx && global_row_idx <= selection_tbl.max.y); - B32 row_expanded = ev_expansion_from_key(eval_view, row->key); - E_Eval row_eval = e_eval_from_expr(scratch.arena, row->expr); - CTRL_Entity *row_ctrl_entity = rd_ctrl_entity_from_eval_space(row_eval.space); - CTRL_Entity *row_module = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->module); - if(row_eval.space.kind == RD_EvalSpaceKind_CtrlEntity) - { - switch(row_ctrl_entity->kind) - { - default: - case CTRL_EntityKind_Process: - if(row_eval.mode == E_Mode_Offset) - { - row_module = ctrl_module_from_process_vaddr(row_ctrl_entity, row_eval.value.u64); - }break; - case CTRL_EntityKind_Thread: - if(row_eval.mode == E_Mode_Value) - { - CTRL_Entity *process = ctrl_process_from_entity(row_ctrl_entity); - row_module = ctrl_module_from_process_vaddr(process, d_query_cached_rip_from_thread(row_ctrl_entity)); - }break; - } - } - E_Type *row_type = e_type_from_key(scratch.arena, row_eval.type_key); - B32 row_is_expandable = ev_row_is_expandable(row); - B32 next_row_expanded = row_expanded; - RD_ViewRuleInfo *ui_view_rule_info = rd_view_rule_info_from_string(row->block->expand_view_rule_info->string); - MD_Node *ui_view_rule_params_root = row->block->expand_view_rule_params; - if(ui_view_rule_info->ui == 0 || !(ui_view_rule_info->flags & RD_ViewRuleInfoFlag_CanUseInWatchTable)) - { - ui_view_rule_info = &rd_nil_view_rule_info; - ui_view_rule_params_root = &md_nil_node; - } - RD_WatchViewRowInfo row_info = rd_watch_view_row_info_from_row(row); - RD_WatchViewRowKind row_kind = rd_watch_view_row_kind_from_flags_row_info(flags, row, &row_info); - ProfEnd(); - - //////////////////////// - //- rjf: determine if row's data is fresh and/or bad - // - ProfBegin("determine if row's data is fresh and/or bad"); - B32 row_is_fresh = 0; - B32 row_is_bad = 0; - switch(row_eval.mode) - { - default:{}break; - case E_Mode_Offset: - { - CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(row_eval.space); - if(row_eval.space.kind == RD_EvalSpaceKind_CtrlEntity && space_entity->kind == CTRL_EntityKind_Process) - { - U64 size = e_type_byte_size_from_key(row_eval.type_key); - size = Min(size, 64); - Rng1U64 vaddr_rng = r1u64(row_eval.value.u64, row_eval.value.u64+size); - CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, space_entity->handle, vaddr_rng, 0); - for(U64 idx = 0; idx < (slice.data.size+63)/64; idx += 1) - { - if(slice.byte_changed_flags[idx] != 0) - { - row_is_fresh = 1; - } - if(slice.byte_bad_flags[idx] != 0) - {row_is_bad = 1; - } - } - } - }break; - } - ProfEnd(); - - //////////////////////// - //- rjf: determine row's flags & color palette - // - ProfBegin("determine row's flags & color palette"); - UI_BoxFlags row_flags = 0; - UI_Palette *palette = ui_top_palette(); - { - if(row_is_fresh) - { - palette = ui_build_palette(ui_top_palette(), .background = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay)); - row_flags |= UI_BoxFlag_DrawBackground; - } - else if(global_row_idx & 1) - { - palette = ui_build_palette(ui_top_palette(), .background = rd_rgba_from_theme_color(RD_ThemeColor_BaseBackgroundAlt)); - row_flags |= UI_BoxFlag_DrawBackground; - } - switch(row_kind) - { - default:{}break; - case RD_WatchViewRowKind_Normal:{row_flags |= UI_BoxFlag_DisableFocusOverlay;}break; - case RD_WatchViewRowKind_Header:{row_flags |= UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DisableFocusOverlay;}break; - case RD_WatchViewRowKind_Canvas:{row_flags |= UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder;}break; - case RD_WatchViewRowKind_PrettyEntityControls:{row_flags |= UI_BoxFlag_DisableFocusOverlay;}break; - } - } - ProfEnd(); - - //////////////////////// - //- rjf: build row box - // - ui_set_next_palette(palette); - ui_set_next_flags(disabled_flags); - ui_set_next_pref_width(ui_pct(1, 0)); - ui_set_next_pref_height(ui_px(scroll_list_params.row_height_px*row->visual_size, 1.f)); - ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); - UI_Box *row_box = ui_build_box_from_stringf(row_flags|(!row->next)*UI_BoxFlag_DrawSideBottom|UI_BoxFlag_Clickable, "row_%I64x", row_hash); - ui_ts_vector_idx += 1; - ui_ts_cell_idx = 0; - - ////////////////////// - //- rjf: build row contents - // - RD_RegsScope(.module = row_module->handle) UI_Parent(row_box) switch(row_kind) - { - //////////////////// - //- rjf: header row - // - case RD_WatchViewRowKind_Header: - ProfScope("header row") - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - { - for(RD_WatchViewColumn *col = ewv->first_column; col != 0; col = col->next) - UI_TableCell - { - String8 name = str8(col->display_string_buffer, col->display_string_size); - if(name.size == 0) - { - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: {name = str8_lit("Expression");}break; - case RD_WatchViewColumnKind_Value: {name = str8_lit("Value");}break; - case RD_WatchViewColumnKind_Type: {name = str8_lit("Type");}break; - case RD_WatchViewColumnKind_ViewRule:{name = str8_lit("View Rule");}break; - case RD_WatchViewColumnKind_Member: - { - name = str8(col->string_buffer, col->string_size); - }break; - } - } - switch(col->kind) - { - default: - { - ui_label(name); - }break; - case RD_WatchViewColumnKind_ViewRule: - { - if(rd_help_label(name)) UI_Tooltip - { - F32 max_width = ui_top_font_size()*35; - ui_label_multiline(max_width, str8_lit("View rules are used to tweak the way evaluated expressions are visualized. Multiple rules can be specified on each row. They are specified in a key:(value) form. Some examples follow:")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("array:(N)"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that a pointer points to N elements, rather than only 1.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("omit:(member_1 ... member_n)"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Omits a list of member names from appearing in struct, union, or class evaluations.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("only:(member_1 ... member_n)"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that only the specified members should appear in struct, union, or class evaluations.")); - ui_spacer(ui_em(1.5f, 1)); -#if 0 // TODO(rjf): disabling until post-0.9.12 - RD_Font(RD_FontSlot_Code) ui_labelf("list:(next_link_member_name)"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that some struct, union, or class forms the top of a linked list, with next_link_member_name being the member which points at the next element in the list.")); - ui_spacer(ui_em(1.5f, 1)); -#endif - RD_Font(RD_FontSlot_Code) ui_labelf("dec"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-10 form.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("hex"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-16 form.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("oct"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-8 form.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("bin"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Specifies that all integral evaluations should appear in base-2 form.")); - ui_spacer(ui_em(1.5f, 1)); - RD_Font(RD_FontSlot_Code) ui_labelf("no_addr"); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label_multiline(max_width, str8_lit("Displays only what pointers point to, if possible, without the pointer's address value.")); - ui_spacer(ui_em(1.5f, 1)); - } - }break; - } - } - } - }break; - - //////////////////// - //- rjf: canvas row - // - case RD_WatchViewRowKind_Canvas: - ProfScope("canvas row") UI_FocusHot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off) - { - //- rjf: unpack - RD_WatchViewPoint pt = {0, row->block->key, row->key}; - RD_View *view = rd_view_from_handle(rd_regs()->view); - RD_TransientViewNode *canvas_view_node = rd_transient_view_node_from_ev_key(view, row->key); - RD_View *canvas_view = canvas_view_node->view; - String8 canvas_view_expr = e_string_from_expr(scratch.arena, row->expr); - B32 need_new_spec = (!str8_match(str8(canvas_view->query_buffer, canvas_view->query_string_size), canvas_view_expr, 0) || - !md_tree_match(canvas_view_node->initial_params, ui_view_rule_params_root, 0)); - if(need_new_spec) - { - arena_clear(canvas_view_node->initial_params_arena); - canvas_view_node->initial_params = md_tree_copy(canvas_view_node->initial_params_arena, ui_view_rule_params_root); - rd_view_equip_spec(canvas_view, ui_view_rule_info, canvas_view_expr, ui_view_rule_params_root); - } - Vec2F32 canvas_dim = v2f32(scroll_list_params.dim_px.x - ui_top_font_size()*1.5f, - (row->visual_size_skipped+row->visual_size+row->visual_size_chopped)*scroll_list_params.row_height_px); - Rng2F32 canvas_rect = r2f32p(rect.x0, - rect.y0 + ui_top_fixed_y(), - rect.x0 + canvas_dim.x, - rect.y0 + ui_top_fixed_y() + canvas_dim.y); - - //- rjf: peek clicks in canvas region, mark clicked - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->kind == UI_EventKind_Press && evt->key == OS_Key_LeftMouseButton && contains_2f32(canvas_rect, evt->pos) && - contains_2f32(rect, evt->pos)) - { - pressed = 1; - break; - } - } - - //- rjf: build meta controls - ui_set_next_fixed_x(ui_top_font_size()*1.f); - ui_set_next_fixed_y(ui_top_font_size()*1.f + scroll_list_view_off_px.y*(row == rows.first)); - ui_set_next_pref_width(ui_em(3, 1)); - ui_set_next_pref_height(ui_em(3, 1)); - UI_Flags(UI_BoxFlag_DrawDropShadow) UI_CornerRadius(ui_top_font_size()*0.5f) - { - UI_Signal sig = rd_icon_buttonf(RD_IconKind_Window, 0, "###pop_out"); - if(ui_hovering(sig)) UI_Tooltip - { - ui_labelf("Pop out"); - } - if(ui_pressed(sig)) - { - pressed = 1; - } - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_OpenTab, - .string = e_string_from_expr(scratch.arena, row->expr), - .params_tree = ui_view_rule_params_root); - } - } - - //- rjf: build main column for canvas - ui_set_next_fixed_y(-1.f * (row->visual_size_skipped) * scroll_list_params.row_height_px); - ui_set_next_fixed_height((row->visual_size_skipped + row->visual_size + row->visual_size_chopped) * scroll_list_params.row_height_px); - ui_set_next_child_layout_axis(Axis2_X); - UI_Box *canvas_box = ui_build_box_from_stringf(UI_BoxFlag_FloatingY, "###canvas_%I64x", row_hash); - UI_Parent(canvas_box) UI_WidthFill UI_HeightFill - { - //- rjf: loading animation container - UI_Box *loading_overlay_container = &ui_nil_box; - UI_Parent(canvas_box) UI_WidthFill UI_HeightFill - { - loading_overlay_container = ui_build_box_from_key(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); - } - - //- rjf: push interaction registers, fill with per-view states - rd_push_regs(); - { - rd_regs()->view = rd_handle_from_view(canvas_view); - rd_regs()->file_path = rd_file_path_from_eval_string(rd_frame_arena(), str8(canvas_view->query_buffer, canvas_view->query_string_size)); - } - - //- rjf: build - UI_PermissionFlags(UI_PermissionFlag_Clicks|UI_PermissionFlag_ScrollX) - { - ui_view_rule_info->ui(str8(canvas_view->query_buffer, canvas_view->query_string_size), canvas_view->params_roots[canvas_view->params_read_gen%ArrayCount(canvas_view->params_roots)], canvas_rect); - } - - //- rjf: loading overlay fill - UI_Parent(loading_overlay_container) - { - rd_loading_overlay(canvas_rect, canvas_view->loading_t, canvas_view->loading_progress_v, canvas_view->loading_progress_v_target); - } - - //- rjf: pop interaction registers - rd_pop_regs(); - } - }break; - - //////////////////// - //- rjf: pretty entity controls row - // - case RD_WatchViewRowKind_PrettyEntityControls: - ProfScope("pretty entity controls row") - { - //- rjf: unpack - RD_EntityKind collection_entity_kind = row_info.collection_entity_kind; - CTRL_EntityKind collection_ctrl_entity_kind = row_info.collection_ctrl_entity_kind; - RD_Entity *entity = row_info.collection_entity; - CTRL_Entity *ctrl_entity = row_info.collection_ctrl_entity; - B32 entity_box_selected = (row_selected && selection_tbl.min.x <= 1 && 1 <= selection_tbl.max.x); - B32 is_hovering = ((rd_handle_match(rd_state->hover_regs->entity, rd_handle_from_entity(entity)) && - rd_state->hover_regs_slot == RD_RegSlot_Entity) || - (ctrl_handle_match(rd_state->hover_regs->thread, ctrl_entity->handle) && rd_state->hover_regs_slot == RD_RegSlot_Thread) || - (ctrl_handle_match(rd_state->hover_regs->module, ctrl_entity->handle) && rd_state->hover_regs_slot == RD_RegSlot_Module) || - (ctrl_handle_match(rd_state->hover_regs->process, ctrl_entity->handle) && rd_state->hover_regs_slot == RD_RegSlot_Process)); - - //- rjf: pick palette - UI_Palette *palette = ui_build_palette(ui_top_palette()); - if(entity->kind == RD_EntityKind_Target && !entity->disabled) - { - palette = ui_build_palette(rd_palette_from_code(RD_PaletteCode_NeutralPopButton)); - } - else if(ctrl_entity->kind == CTRL_EntityKind_Thread && ctrl_handle_match(ctrl_entity->handle, rd_regs()->thread)) - { - palette = ui_build_palette(rd_palette_from_code(RD_PaletteCode_NeutralPopButton)); - } - else - { - palette->background = v4f32(0, 0, 0, 0); - } - - //- rjf: build indentation - for(U64 idx = 0; idx < row_depth; idx += 1) - { - ui_set_next_flags(UI_BoxFlag_DrawSideLeft); - ui_spacer(ui_em(1.f, 1.f)); - } - - //- rjf: build add-new buttons - if(rd_entity_is_nil(entity) && collection_entity_kind == RD_EntityKind_Target) - UI_Palette(palette) - { - ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string))) - { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string); - } - } - if(rd_entity_is_nil(entity) && collection_entity_kind == RD_EntityKind_Breakpoint) - UI_Palette(palette) - { - ui_set_next_focus_hot(row_selected && selection_tbl.min.x == 1 ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_AddAddressBreakpoint].string))) - { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddAddressBreakpoint].string); - } - ui_set_next_focus_hot(row_selected && selection_tbl.min.x == 2 ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_AddFunctionBreakpoint].string))) - { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddFunctionBreakpoint].string); - } - } - if(rd_entity_is_nil(entity) && collection_entity_kind == RD_EntityKind_WatchPin) - UI_Palette(palette) - { - ui_set_next_focus_hot(row_selected && selection_tbl.min.x == 1 ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_cmd_spec_button(rd_cmd_kind_info_table[RD_CmdKind_AddWatchPin].string))) - { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddWatchPin].string); - } - } - if(rd_entity_is_nil(entity) && collection_entity_kind == RD_EntityKind_FilePathMap) - UI_Palette(palette) - { - ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_icon_buttonf(RD_IconKind_FileOutline, 0, "Add File Path Map"))) - { - rd_entity_alloc(rd_entity_root(), RD_EntityKind_FilePathMap); - } - } - if(rd_entity_is_nil(entity) && collection_entity_kind == RD_EntityKind_AutoViewRule) - UI_Palette(palette) - { - ui_set_next_focus_hot(row_selected ? UI_FocusKind_On : UI_FocusKind_Off); - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Binoculars, 0, "Add Auto View Rule"))) - { - rd_entity_alloc(rd_entity_root(), RD_EntityKind_AutoViewRule); - } - } - - //- rjf: build entity box - if(!rd_entity_is_nil(entity) || ctrl_entity != &ctrl_entity_nil) - { - //- rjf: unpack entity info - DR_FancyStringList fstrs = {0}; - if(!rd_entity_is_nil(entity)) - { - fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, ui_top_palette()->text_weak, ui_top_font_size()); - } - else if(ctrl_entity != &ctrl_entity_nil) - { - fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ctrl_entity, ui_top_palette()->text_weak, ui_top_font_size(), 1); - } - String8 fstrs_string = dr_string_from_fancy_string_list(scratch.arena, &fstrs); - FuzzyMatchRangeList fstrs_matches = fuzzy_match_find(scratch.arena, filter, fstrs_string); - UI_Key hover_t_key = ui_key_from_stringf(ui_key_zero(), "entity_hover_t_%p_%p", entity, ctrl_entity); - F32 hover_t = ui_anim(hover_t_key, (F32)!!is_hovering, .rate = entity_hover_t_rate); - if(!rd_entity_is_nil(entity)) - { - palette->overlay = rd_rgba_from_entity(entity); - palette->overlay.w *= 0.3f; - } - else if(ctrl_entity != &ctrl_entity_nil) - { - palette->overlay = rd_rgba_from_ctrl_entity(ctrl_entity); - palette->overlay.w *= 0.3f; - } - if(palette->overlay.x == 0 && palette->overlay.y == 0 && palette->overlay.z == 0 && palette->overlay.w == 0) - { - palette->overlay = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); - } - palette->overlay.w *= hover_t; - - //- rjf: build - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Box *entity_box = &ui_nil_box; - UI_FocusHot(entity_box_selected ? UI_FocusKind_On : UI_FocusKind_Off) UI_Palette(palette) - { - entity_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawOverlay| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawSideLeft| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawHotEffects, - "###entity_%p_%p", entity, ctrl_entity); - } - { - UI_Parent(entity_box) RD_RegsScope(.entity = rd_handle_from_entity(entity)) - { - RD_RegSlot slot = RD_RegSlot_Entity; - switch(ctrl_entity->kind) - { - default:{}break; - case CTRL_EntityKind_Machine:{slot = RD_RegSlot_Machine; rd_regs()->machine = ctrl_entity->handle;}break; - case CTRL_EntityKind_Thread: {slot = RD_RegSlot_Thread; rd_regs()->thread = ctrl_entity->handle;}break; - case CTRL_EntityKind_Process:{slot = RD_RegSlot_Process; rd_regs()->process = ctrl_entity->handle;}break; - case CTRL_EntityKind_Module: {slot = RD_RegSlot_Module; rd_regs()->module = ctrl_entity->handle;}break; - } - UI_PrefWidth(ui_em(2.f, 1.f)) if(ui_pressed(ui_expander(row->block->rows_default_expanded ? !row_expanded : row_expanded, str8_lit("###expanded")))) - { - next_row_expanded = !row_expanded; - } - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTruncatedHover, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &fstrs); - ui_box_equip_fuzzy_match_ranges(title_box, &fstrs_matches); - UI_Signal sig = ui_signal_from_box(entity_box); - if(ui_hovering(sig)) - { - rd_set_hover_regs(slot); - } - if(ui_right_clicked(sig)) - { - rd_open_ctx_menu(entity_box->key, v2f32(0, dim_2f32(entity_box->rect).y), slot); - } - if(ui_dragging(sig) && !contains_2f32(sig.box->rect, ui_mouse())) - { - rd_drag_begin(slot); - } - if(ui_pressed(sig)) - { - RD_WatchViewPoint cell_pt = {1, row->block->key, row->key}; - ewv->next_cursor = ewv->next_mark = cell_pt; - pressed = 1; - } - if(ui_double_clicked(sig)) - { - if(entity->kind == RD_EntityKind_Target) - { - rd_cmd(sig.event_flags & OS_Modifier_Ctrl && entity->disabled ? RD_CmdKind_EnableEntity : - sig.event_flags & OS_Modifier_Ctrl && !entity->disabled ? RD_CmdKind_DisableEntity : - RD_CmdKind_SelectEntity, .entity = rd_handle_from_entity(entity)); - } - if(ctrl_entity->kind == CTRL_EntityKind_Thread) - { - rd_cmd(RD_CmdKind_SelectThread, .thread = ctrl_entity->handle); - } - if(entity->kind == RD_EntityKind_Breakpoint || - entity->kind == RD_EntityKind_WatchPin) - { - RD_Entity *loc = rd_entity_child_from_kind(entity, RD_EntityKind_Location); - rd_cmd(RD_CmdKind_FindCodeLocation, - .file_path = (loc->flags & RD_EntityFlag_HasTextPoint) ? loc->string : str8_zero(), - .cursor = loc->text_point, - .vaddr = loc->vaddr); - } - } - } - } - - //- rjf: build extra entity controls - UI_PrefWidth(ui_em(3.f, 1.f)) - { - U64 ctrl_idx = 1; - for EachIndex(idx, row_ctrls_count) - { - RD_WatchViewRowCtrl *ctrl = &row_ctrls[idx]; - if(ctrl->entity_kind == entity->kind && - ctrl->ctrl_entity_kind == ctrl_entity->kind) - { - UI_FocusHot(row_selected && selection_tbl.min.x <= ctrl_idx+1 && ctrl_idx+1 <= selection_tbl.max.x ? UI_FocusKind_On : UI_FocusKind_Off) - { - B32 is_frozen = ctrl_entity_tree_is_frozen(ctrl_entity); - RD_IconKind icon_kind = rd_cmd_kind_info_table[ctrl->kind].icon_kind; - UI_Palette *palette = ui_top_palette(); - if(ctrl->kind == RD_CmdKind_SelectEntity) - { - icon_kind = entity->disabled ? RD_IconKind_RadioHollow : RD_IconKind_RadioFilled; - } - if(ctrl->kind == RD_CmdKind_EnableEntity) - { - icon_kind = entity->disabled ? RD_IconKind_CheckHollow : RD_IconKind_CheckFilled; - } - if(ctrl->kind == RD_CmdKind_SelectThread) - { - icon_kind = (ctrl_handle_match(ctrl_entity->handle, rd_base_regs()->thread) ? RD_IconKind_RadioFilled : RD_IconKind_RadioHollow); - } - if(ctrl->kind == RD_CmdKind_FreezeEntity) - { - icon_kind = is_frozen ? RD_IconKind_Locked : RD_IconKind_Unlocked; - palette = rd_palette_from_code(is_frozen ? RD_PaletteCode_NegativePopButton : RD_PaletteCode_PositivePopButton); - } - UI_Palette(palette) - { - UI_Signal sig = rd_icon_buttonf(icon_kind, 0, "###row_ctrl_%I64x", idx); - if(ui_clicked(sig)) - { - if(ctrl->kind == RD_CmdKind_SelectEntity) - { - rd_cmd(sig.event_flags & OS_Modifier_Ctrl && entity->disabled ? RD_CmdKind_EnableEntity : - sig.event_flags & OS_Modifier_Ctrl && !entity->disabled ? RD_CmdKind_DisableEntity : - RD_CmdKind_SelectEntity, .entity = rd_handle_from_entity(entity)); - } - else if(ctrl->kind == RD_CmdKind_EnableEntity) - { - rd_cmd(entity->disabled ? RD_CmdKind_EnableEntity : RD_CmdKind_DisableEntity, .entity = rd_handle_from_entity(entity)); - } - else if(ctrl->kind == RD_CmdKind_SelectThread) - { - rd_cmd(RD_CmdKind_SelectThread, .thread = ctrl_entity->handle); - } - else if(ctrl->kind == RD_CmdKind_FreezeEntity) - { - rd_cmd(is_frozen ? RD_CmdKind_ThawEntity : RD_CmdKind_FreezeEntity, - .ctrl_entity = ctrl_entity->handle); - } - else if(ctrl->kind == RD_CmdKind_Kill) - { - rd_cmd(RD_CmdKind_Kill, .process = ctrl_entity->handle); - } - else - { - rd_cmd(ctrl->kind, .entity = rd_handle_from_entity(entity)); - } - } - } - } - ctrl_idx += 1; - } - } - } - } - }break; - - //////////////////// - //- rjf: normal row - // - default: - case RD_WatchViewRowKind_Normal: - ProfScope("normal row") UI_HeightFill - { - ////////////////////// - //- rjf: draw start of cache lines in expansions - // - if(!(flags & RD_WatchViewFlag_DisableCacheLines)) - { - U64 row_offset = row_eval.value.u64; - if((row_eval.mode == E_Mode_Offset || row_eval.mode == E_Mode_Null) && - row_offset%64 == 0 && row_depth > 0) - { - ui_set_next_fixed_x(0); - ui_set_next_fixed_y(0); - ui_set_next_fixed_height(ui_top_font_size()*0.2f); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = rd_rgba_from_theme_color(RD_ThemeColor_CacheLineBoundary))); - ui_build_box_from_key(UI_BoxFlag_Floating|UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } - - ////////////////////// - //- rjf: draw mid-row cache line boundaries in expansions - // - if(!(flags & RD_WatchViewFlag_DisableCacheLines)) - { - if((row_eval.mode == E_Mode_Offset || row_eval.mode == E_Mode_Null) && - row_eval.value.u64%64 != 0 && - row_depth > 0 && - !row_expanded) - { - U64 next_off = (row_eval.value.u64 + e_type_byte_size_from_key(row_eval.type_key)); - if(next_off%64 != 0 && row_eval.value.u64/64 < next_off/64) - { - ui_set_next_fixed_x(0); - ui_set_next_fixed_y(scroll_list_params.row_height_px - ui_top_font_size()*0.5f); - ui_set_next_fixed_height(ui_top_font_size()*1.f); - Vec4F32 boundary_color = rd_rgba_from_theme_color(RD_ThemeColor_CacheLineBoundary); - boundary_color.w *= 0.5f; - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = boundary_color)); - ui_build_box_from_key(UI_BoxFlag_Floating|UI_BoxFlag_DrawBackground, ui_key_zero()); - } - } - } - - ////////////////////// - //- rjf: build all columns - // - ProfScope("build all columns") - { - S64 x = 0; - F32 x_px = 0; - for(RD_WatchViewColumn *col = ewv->first_column; col != 0; col = col->next, x += 1) - { - //- rjf: unpack cell info - RD_WatchViewPoint cell_pt = {x, row->block->key, row->key}; - RD_WatchViewTextEditState *cell_edit_state = rd_watch_view_text_edit_state_from_pt(ewv, cell_pt); - B32 cell_selected = (row_selected && selection_tbl.min.x <= cell_pt.x && cell_pt.x <= selection_tbl.max.x); - String8 cell_pre_edit_string = rd_string_from_eval_viz_row_column(scratch.arena, eval_view, row, col, string_flags|EV_StringFlag_ReadOnlyDisplayRules, default_radix, ui_top_font(), ui_top_font_size(), row_string_max_size_px); - - //- rjf: unpack column-kind-specific info - ProfBegin("unpack column-kind-specific info"); - E_Eval cell_eval = row_eval; - E_Type *cell_type = row_type; - B32 cell_can_edit = 0; - FuzzyMatchRangeList cell_matches = {0}; - String8 cell_inheritance_string = {0}; - String8 cell_error_string = {0}; - String8 cell_error_tooltip_string = {0}; - RD_AutoCompListerFlags cell_autocomp_flags = 0; - RD_ViewRuleUIFunctionType *cell_ui_hook = 0; - MD_Node *cell_ui_params = &md_nil_node; - Vec4F32 cell_base_color = ui_top_palette()->text; - RD_IconKind cell_icon = RD_IconKind_Null; - String8 cell_ghost_text = {0}; - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: - { - cell_can_edit = (row_depth == 0 && modifiable && filter.size == 0); - if(filter.size != 0) - { - cell_matches = fuzzy_match_find(scratch.arena, filter, ev_expr_string_from_row(scratch.arena, row, string_flags)); - } - cell_autocomp_flags = (RD_AutoCompListerFlag_Locals| - RD_AutoCompListerFlag_Procedures| - RD_AutoCompListerFlag_Globals| - RD_AutoCompListerFlag_ThreadLocals| - RD_AutoCompListerFlag_Types); - if(row->member != 0 && row->member->inheritance_key_chain.first != 0) - { - String8List inheritance_chain_type_names = {0}; - for(E_TypeKeyNode *n = row->member->inheritance_key_chain.first; n != 0; n = n->next) - { - String8 inherited_type_name = e_type_string_from_key(scratch.arena, n->v); - inherited_type_name = str8_skip_chop_whitespace(inherited_type_name); - str8_list_push(scratch.arena, &inheritance_chain_type_names, inherited_type_name); - } - if(inheritance_chain_type_names.node_count != 0) - { - StringJoin join = {0}; - join.sep = str8_lit("::"); - String8 inheritance_type = str8_list_join(scratch.arena, &inheritance_chain_type_names, &join); - cell_inheritance_string = inheritance_type; - } - } - }break; - case RD_WatchViewColumnKind_Value: - { - }goto value_cell; - case RD_WatchViewColumnKind_Member: - { - E_Expr *expr = rd_expr_from_watch_view_row_column(scratch.arena, eval_view, row, col); - cell_eval = e_eval_from_expr(scratch.arena, expr); - cell_type = e_type_from_key(scratch.arena, cell_eval.type_key); - }goto value_cell; - value_cell:; - { - E_MsgList msgs = cell_eval.msgs; - if(row_depth == 0 && row->string.size != 0) - { - E_TokenArray tokens = e_token_array_from_text(scratch.arena, row->string); - E_Parse parse = e_parse_expr_from_text_tokens(scratch.arena, row->string, &tokens); - e_msg_list_concat_in_place(&parse.msgs, &msgs); - msgs = parse.msgs; - } - if(msgs.max_kind > E_MsgKind_Null) - { - String8List strings = {0}; - for(E_Msg *msg = msgs.first; msg != 0; msg = msg->next) - { - str8_list_push(scratch.arena, &strings, msg->text); - } - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - cell_error_string = str8_list_join(scratch.arena, &strings, &join); - } - if(row_is_bad) - { - cell_error_tooltip_string = str8_lit("Could not read memory successfully."); - } - cell_autocomp_flags = (RD_AutoCompListerFlag_Locals| - RD_AutoCompListerFlag_Procedures| - RD_AutoCompListerFlag_Globals| - RD_AutoCompListerFlag_ThreadLocals| - RD_AutoCompListerFlag_Types); - if(cell_type->flags & E_TypeFlag_IsPathText) - { - cell_autocomp_flags = RD_AutoCompListerFlag_Files; - } - if(ui_view_rule_info->flags & RD_ViewRuleInfoFlag_CanFillValueCell) - { - cell_ui_hook = ui_view_rule_info->ui; - cell_ui_params = ui_view_rule_params_root; - } - for(EV_ViewRuleNode *n = row->view_rules->first; n != 0; n = n->next) - { - EV_ViewRule *vr = &n->v; - RD_ViewRuleInfo *info = rd_view_rule_info_from_string(vr->root->string); - if(info->flags & RD_ViewRuleInfoFlag_CanFillValueCell && info->ui != 0) - { - cell_ui_hook = info->ui; - cell_ui_params = vr->root; - } - } - cell_can_edit = ev_type_key_is_editable(cell_eval.type_key); - }break; - case RD_WatchViewColumnKind_Type: - { - cell_can_edit = 0; - }break; - case RD_WatchViewColumnKind_ViewRule: - { - cell_can_edit = 1; - cell_autocomp_flags = RD_AutoCompListerFlag_ViewRules; - if(cell_pre_edit_string.size == 0) - { - EV_ViewRuleList *auto_view_rules = ev_auto_view_rules_from_type_key(scratch.arena, row_eval.type_key, 0, 1); - String8List strings = {0}; - for(EV_ViewRuleNode *n = auto_view_rules->first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &strings, n->v.root->string); - } - cell_ghost_text = str8_list_join(scratch.arena, &strings, &(StringJoin){.sep = str8_lit(", ")}); - } - }break; - case RD_WatchViewColumnKind_CallStackFrameSelection: - { - if(ctrl_handle_match(row_info.callstack_thread->handle, rd_regs()->thread) && - row_info.callstack_unwind_index == rd_regs()->unwind_count && - row_info.callstack_inline_depth == rd_regs()->inline_depth) - { - cell_icon = RD_IconKind_RightArrow; - cell_base_color = rd_rgba_from_ctrl_entity(row_info.callstack_thread); - } - }break; - } - ProfEnd(); - - //- rjf: apply column-specified view rules - ProfBegin("apply column-specified view rules"); - if(col->view_rule_size != 0) - { - String8 col_view_rule = str8(col->view_rule_buffer, col->view_rule_size); - EV_ViewRuleList *view_rules = ev_view_rule_list_from_string(scratch.arena, col_view_rule); - for(EV_ViewRuleNode *n = view_rules->first; n != 0; n = n->next) - { - EV_ViewRule *vr = &n->v; - RD_ViewRuleInfo *info = rd_view_rule_info_from_string(vr->root->string); - if(info->flags & RD_ViewRuleInfoFlag_CanFillValueCell && info->ui != 0) - { - cell_ui_hook = info->ui; - cell_ui_params = vr->root; - } - } - } - ProfEnd(); - - //- rjf: determine cell's palette - ProfBegin("determine cell's palette"); - UI_BoxFlags cell_flags = 0; - UI_Palette *palette = ui_top_palette(); - { - if(cell_error_tooltip_string.size != 0 || - cell_error_string.size != 0) - { - palette = ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative), .text_weak = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative), .background = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlayError)); - cell_flags |= UI_BoxFlag_DrawBackground; - } - else if(cell_inheritance_string.size != 0) - { - palette = ui_build_palette(ui_top_palette(), .background = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay)); - cell_flags |= UI_BoxFlag_DrawBackground; - } - else - { - palette = ui_build_palette(ui_top_palette(), .text = cell_base_color); - } - } - ProfEnd(); - - //- rjf: determine if cell needs code styling - B32 cell_is_code = !col->is_non_code; - switch(col->kind) - { - default:{}break; - case RD_WatchViewColumnKind_Expr: - { - cell_is_code = 1; - if(row->member != 0 && row->member->pretty_name.size != 0 && flags & RD_WatchViewFlag_PrettyNameMembers) - { - cell_is_code = 0; - } - }break; - case RD_WatchViewColumnKind_Value: - case RD_WatchViewColumnKind_Member: - { - if(cell_type->flags & E_TypeFlag_IsCodeText) - { - cell_is_code = 1; - } - else if(cell_type->flags & E_TypeFlag_IsPathText || - cell_type->flags & E_TypeFlag_IsPlainText) - { - cell_is_code = 0; - } - }break; - } - - //- rjf: build cell - UI_Signal sig = {0}; - ProfScope("build cell") - UI_Palette(palette) - UI_TableCell - UI_FocusHot(cell_selected ? UI_FocusKind_On : UI_FocusKind_Off) - UI_FocusActive((cell_selected && ewv->text_editing) ? UI_FocusKind_On : UI_FocusKind_Off) - RD_Font(cell_is_code ? RD_FontSlot_Code : RD_FontSlot_Main) - UI_FlagsAdd(row_depth > 0 ? UI_BoxFlag_DrawTextWeak : 0) - { - ui_set_next_flags(ui_top_flags() | cell_flags); - - // rjf: cell has errors? -> build error box - if(cell_error_string.size != 0) RD_Font(RD_FontSlot_Main) - { - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###%I64x_row_%I64x", x, row_hash); - sig = ui_signal_from_box(box); - UI_Parent(box) UI_Flags(0) - { - rd_error_label(cell_error_string); - } - } - - // rjf: cell has hook? -> build ui by calling hook - else if(cell_ui_hook != 0) - { - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); - UI_Parent(box) - { - String8 row_expr = e_string_from_expr(scratch.arena, row->expr); - cell_ui_hook(row_expr, cell_ui_params, r2f32p(x_px, 0, x_px + col->pct*dim_2f32(rect).x, row_height_px)); - } - sig = ui_signal_from_box(box); - } - - // rjf: cell has icon? build icon - else if(cell_icon != RD_IconKind_Null) - { - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "###cell_%I64x", row_hash); - UI_Parent(box) RD_Font(RD_FontSlot_Icons) UI_WidthFill UI_TextAlignment(UI_TextAlign_Center) - { - ui_label(rd_icon_kind_text_table[cell_icon]); - } - sig = ui_signal_from_box(box); - } - - // rjf: build cell line edit - else - { - sig = rd_line_editf((RD_LineEditFlag_CodeContents*(!!cell_is_code)| - RD_LineEditFlag_NoBackground| - RD_LineEditFlag_KeyboardClickable| - RD_LineEditFlag_DisableEdit*(!cell_can_edit)| - RD_LineEditFlag_Expander*!!(x == 0 && row_is_expandable && col->kind == RD_WatchViewColumnKind_Expr)| - RD_LineEditFlag_ExpanderPlaceholder*(x == 0 && row_depth==0 && col->kind == RD_WatchViewColumnKind_Expr)| - RD_LineEditFlag_ExpanderSpace*(x == 0 && row_depth!=0 && col->kind == RD_WatchViewColumnKind_Expr)), - x == 0 ? row_depth : 0, - &cell_matches, - &cell_edit_state->cursor, &cell_edit_state->mark, cell_edit_state->input_buffer, sizeof(cell_edit_state->input_buffer), &cell_edit_state->input_size, &next_row_expanded, - cell_pre_edit_string, - "%S###%I64x_row_%I64x", cell_ghost_text, x, row_hash); - if(ui_is_focus_active() && - selection_tbl.min.x == selection_tbl.max.x && selection_tbl.min.y == selection_tbl.max.y && - txt_pt_match(cell_edit_state->cursor, cell_edit_state->mark)) - { - String8 input = str8(cell_edit_state->input_buffer, cell_edit_state->input_size); - RD_AutoCompListerParams params = {cell_autocomp_flags}; - if(col->kind == RD_WatchViewColumnKind_ViewRule) - { - params = rd_view_rule_autocomp_lister_params_from_input_cursor(scratch.arena, input, cell_edit_state->cursor.column-1); - if(params.flags == 0) - { - params.flags = cell_autocomp_flags; - } - } - rd_set_autocomp_lister_query(sig.box->key, ¶ms, input, cell_edit_state->cursor.column-1); - } - } - } - - //- rjf: handle interactions - { - // rjf: single-click -> move selection here - if(ui_pressed(sig)) - { - ewv->next_cursor = ewv->next_mark = cell_pt; - pressed = 1; - } - - // rjf: double-click actions - if(ui_double_clicked(sig) || sig.f & UI_SignalFlag_KeyboardPressed) - { - ui_kill_action(); - - // rjf: has callstack info? -> select unwind - if(row_info.callstack_thread != &ctrl_entity_nil) - { - rd_cmd(RD_CmdKind_SelectThread, .thread = row_info.callstack_thread->handle); - rd_cmd(RD_CmdKind_SelectUnwind, - .unwind_count = row_info.callstack_unwind_index, - .inline_depth = row_info.callstack_inline_depth); - } - - // rjf: can edit? -> begin editing - else if(cell_can_edit) - { - rd_cmd(RD_CmdKind_Edit); - } - - // rjf: cannot edit, has addr info? -> go to address - else if(row_kind == RD_WatchViewRowKind_Normal && - (col->kind == RD_WatchViewColumnKind_Value || - col->kind == RD_WatchViewColumnKind_Member) && - cell_eval.space.kind == RD_EvalSpaceKind_CtrlEntity) - { - CTRL_Entity *entity = rd_ctrl_entity_from_eval_space(cell_eval.space); - CTRL_Entity *process = ctrl_process_from_entity(entity); - if(process != &ctrl_entity_nil) - { - U64 vaddr = cell_eval.value.u64; - CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); - DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - U64 voff = ctrl_voff_from_vaddr(module, vaddr); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); - String8 file_path = {0}; - TxtPt pt = {0}; - if(lines.first != 0) - { - file_path = lines.first->v.file_path; - pt = lines.first->v.pt; - } - rd_cmd(RD_CmdKind_FindCodeLocation, - .process = process->handle, - .vaddr = vaddr, - .file_path = file_path, - .cursor = pt); - } - } - } - - // rjf: hovering with inheritance string -> show tooltip - if(ui_hovering(sig) && cell_inheritance_string.size != 0) UI_Tooltip - { - UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) UI_TextPadding(0) - { - ui_labelf("Inherited from "); - RD_Font(RD_FontSlot_Code) rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), cell_inheritance_string); - } - } - - // rjf: hovering with error tooltip -> show tooltip - if(ui_hovering(sig) && cell_error_tooltip_string.size != 0) UI_Tooltip - { - UI_PrefWidth(ui_children_sum(1)) rd_error_label(cell_error_tooltip_string); - } - } - - //- rjf: bump x pixel coordinate - x_px += col->pct*dim_2f32(rect).x; - - //- rjf: [DEV] hovering -> watch key tooltips - if(DEV_eval_watch_key_tooltips && ui_hovering(sig)) UI_Tooltip RD_Font(RD_FontSlot_Code) - { - ui_labelf("Block Key: {0x%I64x, %I64u}", row->block->key.parent_hash, row->block->key.child_id); - ui_labelf("Row Key: {0x%I64x, %I64u}", row->key.parent_hash, row->key.child_id); - ui_labelf("Cursor Key: {0x%I64x, %I64u}", ewv->cursor.key.parent_hash, ewv->cursor.key.child_id); - ui_spacer(ui_em(1.f, 1.f)); - ui_labelf("Cursor Table Coordinates: {%I64u, %I64u}", selection_tbl.min.x, selection_tbl.min.y); - } - - //- rjf: [DEV] hovering -> eval system tooltips - if(DEV_eval_compiler_tooltips && x == 0 && ui_hovering(sig)) UI_Tooltip RD_Font(RD_FontSlot_Code) - { - local_persist char *spaces = " "; - String8 string = ev_expr_string_from_row(scratch.arena, row, 0); - E_TokenArray tokens = e_token_array_from_text(scratch.arena, string); - E_Parse parse = e_parse_expr_from_text_tokens(scratch.arena, string, &tokens); - E_IRTreeAndType irtree = e_irtree_and_type_from_expr(scratch.arena, parse.expr); - E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree.root); - String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("Text:"); - ui_label(string); - ui_spacer(ui_em(2.f, 1.f)); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("Tokens:"); - for(U64 idx = 0; idx < tokens.count; idx += 1) - { - ui_labelf("%S: '%S'", e_token_kind_strings[tokens.v[idx].kind], str8_substr(string, tokens.v[idx].range)); - } - ui_spacer(ui_em(2.f, 1.f)); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("Expression:"); - { - typedef struct Task Task; - struct Task - { - Task *next; - Task *prev; - E_Expr *expr; - S64 depth; - }; - Task start_task = {0, 0, parse.expr}; - Task *first_task = &start_task; - Task *last_task = first_task; - for(Task *t = first_task; t != 0; t = t->next) - { - String8 ext = {0}; - switch(t->expr->kind) - { - default: - { - if(t->expr->string.size != 0) - { - ext = push_str8f(scratch.arena, "'%S'", t->expr->string); - } - else if(t->expr->value.u32 != 0) - { - ext = push_str8f(scratch.arena, "0x%x", t->expr->value.u32); - } - else if(t->expr->value.f32 != 0) - { - ext = push_str8f(scratch.arena, "%f", t->expr->value.f32); - } - else if(t->expr->value.f64 != 0) - { - ext = push_str8f(scratch.arena, "%f", t->expr->value.f64); - } - else if(t->expr->value.u64 != 0) - { - ext = push_str8f(scratch.arena, "0x%I64x", t->expr->value.u64); - } - }break; - } - ui_labelf("%.*s%S%s%S", (int)t->depth*2, spaces, e_expr_kind_strings[t->expr->kind], ext.size ? " " : "", ext); - for(E_Expr *child = t->expr->first; child != &e_expr_nil; child = child->next) - { - Task *task = push_array(scratch.arena, Task, 1); - task->expr = child; - task->depth = t->depth+1; - DLLInsert(first_task, last_task, t, task); - } - } - } - ui_spacer(ui_em(2.f, 1.f)); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("IR Tree:"); - { - typedef struct Task Task; - struct Task - { - Task *next; - Task *prev; - E_IRNode *node; - S64 depth; - }; - Task start_task = {0, 0, irtree.root}; - Task *first_task = &start_task; - Task *last_task = first_task; - for(Task *t = first_task; t != 0; t = t->next) - { - String8 op_string = {0}; - switch(t->node->op) - { - default:{}break; - case E_IRExtKind_Bytecode:{op_string = str8_lit("Bytecode");}break; - case E_IRExtKind_SetSpace:{op_string = str8_lit("SetSpace");}break; -#define X(name) case RDI_EvalOp_##name:{op_string = str8_lit(#name);}break; - RDI_EvalOp_XList -#undef X - } - String8 ext = {0}; - ui_labelf("%.*s%S", (int)t->depth*2, spaces, op_string); - for(E_IRNode *child = t->node->first; child != &e_irnode_nil; child = child->next) - { - Task *task = push_array(scratch.arena, Task, 1); - task->node = child; - task->depth = t->depth+1; - DLLInsert(first_task, last_task, t, task); - } - } - } - ui_spacer(ui_em(2.f, 1.f)); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("Op List:"); - { - for(E_Op *op = oplist.first; op != 0; op = op->next) - { - String8 op_string = {0}; - switch(op->opcode) - { - default:{}break; - case E_IRExtKind_Bytecode:{op_string = str8_lit("Bytecode");}break; - case E_IRExtKind_SetSpace:{op_string = str8_lit("SetSpace");}break; -#define X(name) case RDI_EvalOp_##name:{op_string = str8_lit(#name);}break; - RDI_EvalOp_XList -#undef X - } - String8 ext = {0}; - switch(op->opcode) - { - case E_IRExtKind_Bytecode:{ext = str8_lit("[bytecode]");}break; - default: - { - ext = str8_from_u64(scratch.arena, op->value.u64, 16, 0, 0); - }break; - } - ui_labelf(" %S%s%S", op_string, ext.size ? " " : "", ext); - } - } - ui_spacer(ui_em(2.f, 1.f)); - UI_Flags(UI_BoxFlag_DrawTextWeak) ui_labelf("Bytecode:"); - { - for(U64 idx = 0; idx < bytecode.size; idx += 1) - { - ui_labelf(" 0x%x ('%c')", (U32)bytecode.str[idx], (char)bytecode.str[idx]); - } - } - } - } - } - }break; - } - - ////////////////////// - //- rjf: commit expansion state changes - // - if(next_row_expanded != row_expanded) - { - ev_key_set_expansion(eval_view, row->block->key, row->key, next_row_expanded); - } - } - } - } - } - - ////////////////////////////// - //- rjf: general table-wide press logic - // - if(!is_top_level_hook) if(pressed) - { - rd_cmd(RD_CmdKind_FocusPanel); - } - - if(!is_top_level_hook) { rd_store_view_scroll_pos(scroll_pos); } - scratch_end(scratch); - di_scope_close(di_scope); - ProfEnd(); -} - //////////////////////////////// //~ rjf: null @view_hook_impl -RD_VIEW_RULE_UI_FUNCTION_DEF(null) {} - -//////////////////////////////// -//~ rjf: empty @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(empty) -{ - ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); - UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_Padding(ui_pct(1, 0)) UI_Focus(UI_FocusKind_Null) - { - UI_PrefHeight(ui_em(3.f, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_em(15.f, 1.f)) - UI_CornerRadius(ui_top_font_size()/2.f) - RD_Palette(RD_PaletteCode_NegativePopButton) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_X, 0, "Close Panel"))) - { - rd_cmd(RD_CmdKind_ClosePanel); - } - } - } -} - -//////////////////////////////// -//~ rjf: getting_started @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(getting_started) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - ui_set_next_flags(UI_BoxFlag_DefaultFocusNav); - UI_Focus(UI_FocusKind_On) UI_WidthFill UI_HeightFill UI_NamedColumn(str8_lit("empty_view")) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_Padding(ui_pct(1, 0)) UI_Focus(UI_FocusKind_Null) - { - RD_EntityList targets = rd_push_active_target_list(scratch.arena); - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); - - //- rjf: icon & info - UI_Padding(ui_em(2.f, 1.f)) - { - //- rjf: icon - { - F32 icon_dim = ui_top_font_size()*10.f; - UI_PrefHeight(ui_px(icon_dim, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_px(icon_dim, 1.f)) - { - R_Handle texture = rd_state->icon_texture; - Vec2S32 texture_dim = r_size_from_tex2d(texture); - ui_image(texture, R_Tex2DSampleKind_Linear, r2f32p(0, 0, texture_dim.x, texture_dim.y), v4f32(1, 1, 1, 1), 0, str8_lit("")); - } - } - - //- rjf: info - UI_Padding(ui_em(2.f, 1.f)) - UI_WidthFill UI_PrefHeight(ui_em(2.f, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_text_dim(10, 1)) - { - ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); - } - } - - //- rjf: targets state dependent helper - B32 helper_built = 0; - if(processes.count == 0) - { - helper_built = 1; - switch(targets.count) - { - //- rjf: user has no targets. build helper for adding them - case 0: - { - UI_PrefHeight(ui_em(3.75f, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_em(22.f, 1.f)) - UI_CornerRadius(ui_top_font_size()/2.f) - RD_Palette(RD_PaletteCode_NeutralPopButton) - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Add, 0, "Add Target"))) - { - rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_AddTarget].string); - } - }break; - - //- rjf: user has 1 target. build helper for launching it - case 1: - { - RD_Entity *target = rd_first_entity_from_list(&targets); - String8 target_full_path = target->string; - String8 target_name = str8_skip_last_slash(target_full_path); - UI_PrefHeight(ui_em(3.75f, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_em(22.f, 1.f)) - UI_CornerRadius(ui_top_font_size()/2.f) - RD_Palette(RD_PaletteCode_PositivePopButton) - { - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Play, 0, "Launch %S", target_name))) - { - rd_cmd(RD_CmdKind_LaunchAndRun, .entity = rd_handle_from_entity(target)); - } - ui_spacer(ui_em(1.5f, 1)); - if(ui_clicked(rd_icon_buttonf(RD_IconKind_Play, 0, "Step Into %S", target_name))) - { - rd_cmd(RD_CmdKind_LaunchAndInit, .entity = rd_handle_from_entity(target)); - } - } - }break; - - //- rjf: user has N targets. - default: - { - helper_built = 0; - }break; - } - } - - //- rjf: or text - if(helper_built) - { - UI_PrefHeight(ui_em(2.25f, 1.f)) - UI_Row - UI_Padding(ui_pct(1, 0)) - UI_TextAlignment(UI_TextAlign_Center) - UI_WidthFill - ui_labelf("- or -"); - } - - //- rjf: helper text for command lister activation - UI_PrefHeight(ui_em(2.25f, 1.f)) UI_Row - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextAlignment(UI_TextAlign_Center) - UI_Padding(ui_pct(1, 0)) - RD_Palette(RD_PaletteCode_Floating) - { - ui_labelf("use"); - UI_TextAlignment(UI_TextAlign_Center) rd_cmd_binding_buttons(rd_cmd_kind_info_table[RD_CmdKind_RunCommand].string); - ui_labelf("to open command menu"); - } - } - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: commands @view_hook_impl - -typedef struct RD_CmdListerItem RD_CmdListerItem; -struct RD_CmdListerItem -{ - String8 cmd_name; - U64 registrar_idx; - U64 ordering_idx; - FuzzyMatchRangeList name_match_ranges; - FuzzyMatchRangeList desc_match_ranges; - FuzzyMatchRangeList tags_match_ranges; -}; - -typedef struct RD_CmdListerItemNode RD_CmdListerItemNode; -struct RD_CmdListerItemNode -{ - RD_CmdListerItemNode *next; - RD_CmdListerItem item; -}; - -typedef struct RD_CmdListerItemList RD_CmdListerItemList; -struct RD_CmdListerItemList -{ - RD_CmdListerItemNode *first; - RD_CmdListerItemNode *last; - U64 count; -}; - -typedef struct RD_CmdListerItemArray RD_CmdListerItemArray; -struct RD_CmdListerItemArray -{ - RD_CmdListerItem *v; - U64 count; -}; - -internal RD_CmdListerItemList -rd_cmd_lister_item_list_from_needle(Arena *arena, String8 needle) -{ - Temp scratch = scratch_begin(&arena, 1); - RD_CmdListerItemList result = {0}; - // TODO(rjf): extend this with dynamically-registered command info - for EachNonZeroEnumVal(RD_CmdKind, k) - { - RD_CmdKindInfo *info = &rd_cmd_kind_info_table[k]; - if(info->flags & RD_CmdKindFlag_ListInUI) - { - String8 cmd_display_name = info->display_name; - String8 cmd_desc = info->description; - String8 cmd_tags = info->search_tags; - FuzzyMatchRangeList name_matches = fuzzy_match_find(arena, needle, cmd_display_name); - FuzzyMatchRangeList desc_matches = fuzzy_match_find(arena, needle, cmd_desc); - FuzzyMatchRangeList tags_matches = fuzzy_match_find(arena, needle, cmd_tags); - if(name_matches.count == name_matches.needle_part_count || - desc_matches.count == name_matches.needle_part_count || - tags_matches.count > 0 || - name_matches.needle_part_count == 0) - { - RD_CmdListerItemNode *node = push_array(arena, RD_CmdListerItemNode, 1); - node->item.cmd_name = info->string; - node->item.registrar_idx = (U64)k; - node->item.ordering_idx = (U64)k; - node->item.name_match_ranges = name_matches; - node->item.desc_match_ranges = desc_matches; - node->item.tags_match_ranges = tags_matches; - SLLQueuePush(result.first, result.last, node); - result.count += 1; - } - } - } - scratch_end(scratch); - return result; -} - -internal RD_CmdListerItemArray -rd_cmd_lister_item_array_from_list(Arena *arena, RD_CmdListerItemList list) -{ - RD_CmdListerItemArray result = {0}; - result.count = list.count; - result.v = push_array(arena, RD_CmdListerItem, result.count); - U64 idx = 0; - for(RD_CmdListerItemNode *n = list.first; n != 0; n = n->next, idx += 1) - { - result.v[idx] = n->item; - } - return result; -} - -internal int -rd_qsort_compare_cmd_lister__strength(RD_CmdListerItem *a, RD_CmdListerItem *b) -{ - int result = 0; - if(a->name_match_ranges.count > b->name_match_ranges.count) - { - result = -1; - } - else if(a->name_match_ranges.count < b->name_match_ranges.count) - { - result = +1; - } - else if(a->desc_match_ranges.count > b->desc_match_ranges.count) - { - result = -1; - } - else if(a->desc_match_ranges.count < b->desc_match_ranges.count) - { - result = +1; - } - else if(a->tags_match_ranges.count > b->tags_match_ranges.count) - { - result = -1; - } - else if(a->tags_match_ranges.count < b->tags_match_ranges.count) - { - result = +1; - } - else if(a->registrar_idx < b->registrar_idx) - { - result = -1; - } - else if(a->registrar_idx > b->registrar_idx) - { - result = +1; - } - else if(a->ordering_idx < b->ordering_idx) - { - result = -1; - } - else if(a->ordering_idx > b->ordering_idx) - { - result = +1; - } - return result; -} - -internal void -rd_cmd_lister_item_array_sort_by_strength__in_place(RD_CmdListerItemArray array) -{ - quick_sort(array.v, array.count, sizeof(RD_CmdListerItem), rd_qsort_compare_cmd_lister__strength); -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(commands) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - //- rjf: grab state - typedef struct RD_CmdsViewState RD_CmdsViewState; - struct RD_CmdsViewState - { - U64 selected_cmd_hash; - }; - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_CmdsViewState *cv = rd_view_state(RD_CmdsViewState); - - //- rjf: build filtered array of commands - RD_CmdListerItemList cmd_list = rd_cmd_lister_item_list_from_needle(scratch.arena, string); - RD_CmdListerItemArray cmd_array = rd_cmd_lister_item_array_from_list(scratch.arena, cmd_list); - rd_cmd_lister_item_array_sort_by_strength__in_place(cmd_array); - - //- rjf: submit best match when hitting enter w/ no selection - if(cv->selected_cmd_hash == 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - rd_cmd(RD_CmdKind_CompleteQuery, .cmd_name = (cmd_array.count > 0 ? cmd_array.v[0].cmd_name : str8_zero())); - } - - //- rjf: selected kind -> cursor - Vec2S64 cursor = {0}; - { - for(U64 idx = 0; idx < cmd_array.count; idx += 1) - { - if(d_hash_from_string(cmd_array.v[idx].cmd_name) == cv->selected_cmd_hash) - { - cursor.y = (S64)idx+1; - break; - } - } - } - - //- rjf: build contents - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*6.5f); - scroll_list_params.dim_px = dim_2f32(rect); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, cmd_array.count)); - scroll_list_params.item_range = r1s64(0, cmd_array.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - //- rjf: build buttons - for(S64 row_idx = visible_row_range.min; - row_idx <= visible_row_range.max && row_idx < cmd_array.count; - row_idx += 1) - { - RD_CmdListerItem *item = &cmd_array.v[row_idx]; - RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(item->cmd_name); - - //- rjf: build row contents - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_child_layout_axis(Axis2_X); - UI_Box *box = &ui_nil_box; - UI_Focus(cursor.y == row_idx+1 ? UI_FocusKind_On : UI_FocusKind_Off) - { - box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - "###cmd_button_%S", item->cmd_name); - } - UI_Parent(box) UI_PrefHeight(ui_em(1.65f, 1.f)) - { - //- rjf: icon - UI_PrefWidth(ui_em(3.f, 1.f)) - UI_HeightFill - UI_Column - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_HeightFill - UI_TextAlignment(UI_TextAlign_Center) - { - RD_IconKind icon = info->icon_kind; - if(icon != RD_IconKind_Null) - { - ui_label(rd_icon_kind_text_table[icon]); - } - } - - //- rjf: name + description - ui_set_next_pref_height(ui_pct(1, 0)); - UI_Column UI_Padding(ui_pct(1, 0)) - { - FNT_Tag font = ui_top_font(); - F32 font_size = ui_top_font_size(); - FNT_Metrics font_metrics = fnt_metrics_from_tag_size(font, font_size); - F32 font_line_height = fnt_line_height_from_metrics(&font_metrics); - String8 cmd_display_name = info->display_name; - String8 cmd_desc = info->description; - UI_Box *name_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##name_%S", cmd_display_name, info->string); - UI_Box *desc_box = &ui_nil_box; - UI_PrefHeight(ui_em(1.8f, 1.f)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - { - desc_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##desc_%S", cmd_desc, info->string); - } - ui_box_equip_fuzzy_match_ranges(name_box, &item->name_match_ranges); - ui_box_equip_fuzzy_match_ranges(desc_box, &item->desc_match_ranges); - } - - //- rjf: bindings - ui_set_next_flags(UI_BoxFlag_Clickable); - UI_PrefWidth(ui_children_sum(1.f)) UI_HeightFill UI_NamedColumn(str8_lit("binding_column")) UI_Padding(ui_em(1.5f, 1.f)) - { - ui_set_next_flags(UI_BoxFlag_Clickable); - UI_NamedRow(str8_lit("binding_row")) UI_Padding(ui_em(1.f, 1.f)) - { - rd_cmd_binding_buttons(item->cmd_name); - } - } - } - - //- rjf: interact - UI_Signal sig = ui_signal_from_box(box); - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_CompleteQuery, .cmd_name = item->cmd_name); - } - } - } - - //- rjf: map selected num -> selected kind - if(1 <= cursor.y && cursor.y <= cmd_array.count) - { - cv->selected_cmd_hash = d_hash_from_string(cmd_array.v[cursor.y-1].cmd_name); - } - else - { - cv->selected_cmd_hash = 0; - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: file_system @view_hook_impl - -typedef enum RD_FileSortKind -{ - RD_FileSortKind_Null, - RD_FileSortKind_Filename, - RD_FileSortKind_LastModified, - RD_FileSortKind_Size, - RD_FileSortKind_COUNT -} -RD_FileSortKind; - -typedef struct RD_FileInfo RD_FileInfo; -struct RD_FileInfo -{ - String8 filename; - FileProperties props; - FuzzyMatchRangeList match_ranges; -}; - -typedef struct RD_FileInfoNode RD_FileInfoNode; -struct RD_FileInfoNode -{ - RD_FileInfoNode *next; - RD_FileInfo file_info; -}; - -typedef struct RD_FileSystemViewPathState RD_FileSystemViewPathState; -struct RD_FileSystemViewPathState -{ - RD_FileSystemViewPathState *hash_next; - String8 normalized_path; - Vec2S64 cursor; -}; - -typedef struct RD_FileSystemViewState RD_FileSystemViewState; -struct RD_FileSystemViewState -{ - B32 initialized; - U64 path_state_table_size; - RD_FileSystemViewPathState **path_state_table; - RD_FileSortKind sort_kind; - Side sort_side; - Arena *cached_files_arena; - String8 cached_files_path; - RD_FileSortKind cached_files_sort_kind; - Side cached_files_sort_side; - U64 cached_file_count; - RD_FileInfo *cached_files; - F32 col_pcts[3]; -}; - -typedef struct RD_PathQuery RD_PathQuery; -struct RD_PathQuery -{ - String8 prefix; - String8 path; - String8 search; -}; - -internal RD_PathQuery -rd_path_query_from_string(String8 string) -{ - String8 dir_str_in_input = {0}; - for(U64 i = 0; i < string.size; i += 1) - { - String8 substr1 = str8_substr(string, r1u64(i, i+1)); - String8 substr2 = str8_substr(string, r1u64(i, i+2)); - String8 substr3 = str8_substr(string, r1u64(i, i+3)); - if(str8_match(substr1, str8_lit("/"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(string, r1u64(i, string.size)); - } - else if(i != 0 && str8_match(substr2, str8_lit(":/"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(string, r1u64(i-1, string.size)); - } - else if(str8_match(substr2, str8_lit("./"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(string, r1u64(i, string.size)); - } - else if(str8_match(substr3, str8_lit("../"), StringMatchFlag_SlashInsensitive)) - { - dir_str_in_input = str8_substr(string, r1u64(i, string.size)); - } - if(dir_str_in_input.size != 0) - { - break; - } - } - - RD_PathQuery path_query = {0}; - if(dir_str_in_input.size != 0) - { - String8 dir = dir_str_in_input; - String8 search = {0}; - U64 one_past_last_slash = dir.size; - for(U64 i = 0; i < dir_str_in_input.size; i += 1) - { - if(dir_str_in_input.str[i] == '/' || dir_str_in_input.str[i] == '\\') - { - one_past_last_slash = i+1; - } - } - dir.size = one_past_last_slash; - search = str8_substr(dir_str_in_input, r1u64(one_past_last_slash, dir_str_in_input.size)); - path_query.path = dir; - path_query.search = search; - path_query.prefix = str8_substr(string, r1u64(0, path_query.path.str - string.str)); - } - return path_query; -} - -internal int -rd_qsort_compare_file_info__filename(RD_FileInfo *a, RD_FileInfo *b) -{ - return strncmp((char *)a->filename.str, (char *)b->filename.str, Min(a->filename.size, b->filename.size)); -} - -internal int -rd_qsort_compare_file_info__default(RD_FileInfo *a, RD_FileInfo *b) -{ - int result = 0; - if(a->props.flags & FilePropertyFlag_IsFolder && !(b->props.flags & FilePropertyFlag_IsFolder)) - { - result = -1; - } - else if(b->props.flags & FilePropertyFlag_IsFolder && !(a->props.flags & FilePropertyFlag_IsFolder)) - { - result = +1; - } - else - { - result = rd_qsort_compare_file_info__filename(a, b); - } - return result; -} - -internal int -rd_qsort_compare_file_info__default_filtered(RD_FileInfo *a, RD_FileInfo *b) -{ - int result = 0; - if(a->filename.size < b->filename.size) - { - result = -1; - } - else if(a->filename.size > b->filename.size) - { - result = +1; - } - return result; -} - -internal int -rd_qsort_compare_file_info__last_modified(RD_FileInfo *a, RD_FileInfo *b) -{ - return ((a->props.modified < b->props.modified) ? -1 : - (a->props.modified > b->props.modified) ? +1 : - 0); -} - -internal int -rd_qsort_compare_file_info__size(RD_FileInfo *a, RD_FileInfo *b) -{ - return ((a->props.size < b->props.size) ? -1 : - (a->props.size > b->props.size) ? +1 : - 0); -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(file_system) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - String8 query = string; - String8 query_normalized = path_normalized_from_string(scratch.arena, query); - B32 query_has_slash = (query.size != 0 && char_to_correct_slash(query.str[query.size-1]) == '/'); - String8 query_normalized_with_opt_slash = push_str8f(scratch.arena, "%S%s", query_normalized, query_has_slash ? "/" : ""); - RD_PathQuery path_query = rd_path_query_from_string(query_normalized_with_opt_slash); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(window->query_cmd_name); - B32 file_selection = !!(cmd_kind_info->query.flags & RD_QueryFlag_AllowFiles); - B32 dir_selection = !!(cmd_kind_info->query.flags & RD_QueryFlag_AllowFolders); - - //- rjf: get extra state for this view - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_FileSystemViewState *fs = rd_view_state(RD_FileSystemViewState); - if(fs->initialized == 0) - { - fs->initialized = 1; - fs->path_state_table_size = 256; - fs->path_state_table = push_array(rd_view_arena(), RD_FileSystemViewPathState *, fs->path_state_table_size); - fs->cached_files_arena = rd_push_view_arena(); - fs->col_pcts[0] = 0.60f; - fs->col_pcts[1] = 0.20f; - fs->col_pcts[2] = 0.20f; - } - - //- rjf: grab state for the current path - RD_FileSystemViewPathState *ps = 0; - { - String8 key = query_normalized; - U64 hash = d_hash_from_string(key); - U64 slot = hash % fs->path_state_table_size; - for(RD_FileSystemViewPathState *p = fs->path_state_table[slot]; p != 0; p = p->hash_next) - { - if(str8_match(p->normalized_path, key, 0)) - { - ps = p; - break; - } - } - if(ps == 0) - { - ps = push_array(rd_view_arena(), RD_FileSystemViewPathState, 1); - ps->hash_next = fs->path_state_table[slot]; - fs->path_state_table[slot] = ps; - ps->normalized_path = push_str8_copy(rd_view_arena(), key); - } - } - - //- rjf: get file array from the current path - U64 file_count = fs->cached_file_count; - RD_FileInfo *files = fs->cached_files; - if(!str8_match(fs->cached_files_path, query_normalized_with_opt_slash, 0) || - fs->cached_files_sort_kind != fs->sort_kind || - fs->cached_files_sort_side != fs->sort_side) - { - arena_clear(fs->cached_files_arena); - - //- rjf: store off path that we're gathering from - fs->cached_files_path = push_str8_copy(fs->cached_files_arena, query_normalized_with_opt_slash); - fs->cached_files_sort_kind = fs->sort_kind; - fs->cached_files_sort_side = fs->sort_side; - - //- rjf: use stored path as the new browse path for the whole frontend - // (multiple file system views may conflict here. that's okay. we'll just always - // choose the most recent change to a file browser path, and live with the - // consequences). - { - rd_cmd(RD_CmdKind_SetCurrentPath, .file_path = path_query.path); - } - - //- rjf: get files, filtered - U64 new_file_count = 0; - RD_FileInfoNode *first_file = 0; - RD_FileInfoNode *last_file = 0; - { - OS_FileIter *it = os_file_iter_begin(scratch.arena, path_query.path, 0); - for(OS_FileInfo info = {0}; os_file_iter_next(scratch.arena, it, &info);) - { - FuzzyMatchRangeList match_ranges = fuzzy_match_find(fs->cached_files_arena, path_query.search, info.name); - B32 fits_search = (path_query.search.size == 0 || match_ranges.count == match_ranges.needle_part_count); - B32 fits_dir_only = !!(info.props.flags & FilePropertyFlag_IsFolder) || !dir_selection; - if(fits_search && fits_dir_only) - { - RD_FileInfoNode *node = push_array(scratch.arena, RD_FileInfoNode, 1); - node->file_info.filename = push_str8_copy(fs->cached_files_arena, info.name); - node->file_info.props = info.props; - node->file_info.match_ranges = match_ranges; - SLLQueuePush(first_file, last_file, node); - new_file_count += 1; - } - } - os_file_iter_end(it); - } - - //- rjf: convert list to array - RD_FileInfo *new_files = push_array(fs->cached_files_arena, RD_FileInfo, new_file_count); - { - U64 idx = 0; - for(RD_FileInfoNode *n = first_file; n != 0; n = n->next, idx += 1) - { - new_files[idx] = n->file_info; - } - } - - //- rjf: apply sort - switch(fs->sort_kind) - { - default: - { - if(path_query.search.size != 0) - { - quick_sort(new_files, new_file_count, sizeof(RD_FileInfo), rd_qsort_compare_file_info__default_filtered); - } - else - { - quick_sort(new_files, new_file_count, sizeof(RD_FileInfo), rd_qsort_compare_file_info__default); - } - }break; - case RD_FileSortKind_Filename: - { - quick_sort(new_files, new_file_count, sizeof(RD_FileInfo), rd_qsort_compare_file_info__filename); - }break; - case RD_FileSortKind_LastModified: - { - quick_sort(new_files, new_file_count, sizeof(RD_FileInfo), rd_qsort_compare_file_info__last_modified); - }break; - case RD_FileSortKind_Size: - { - quick_sort(new_files, new_file_count, sizeof(RD_FileInfo), rd_qsort_compare_file_info__size); - }break; - } - - //- rjf: apply reverse - if(fs->sort_kind != RD_FileSortKind_Null && fs->sort_side == Side_Max) - { - for(U64 idx = 0; idx < new_file_count/2; idx += 1) - { - U64 rev_idx = new_file_count - idx - 1; - Swap(RD_FileInfo, new_files[idx], new_files[rev_idx]); - } - } - - fs->cached_file_count = file_count = new_file_count; - fs->cached_files = files = new_files; - } - - //- rjf: submit best match when hitting enter w/ no selection - if(ps->cursor.y == 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - FileProperties query_normalized_with_opt_slash_props = os_properties_from_file_path(query_normalized_with_opt_slash); - FileProperties path_query_path_props = os_properties_from_file_path(path_query.path); - - // rjf: command search part is empty, but directory matches some file: - if(path_query_path_props.created != 0 && path_query.search.size == 0) - { - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = query_normalized_with_opt_slash); - } - - // rjf: command argument exactly matches some file: - else if(query_normalized_with_opt_slash_props.created != 0 && path_query.search.size != 0) - { - // rjf: is a folder -> autocomplete to slash - if(query_normalized_with_opt_slash_props.flags & FilePropertyFlag_IsFolder) - { - String8 new_path = push_str8f(scratch.arena, "%S%S/", path_query.path, path_query.search); - rd_store_view_filter(new_path); - } - - // rjf: is a file -> complete view - else - { - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = query_normalized_with_opt_slash); - } - } - - // rjf: command argument is empty, picking folders -> use current folder - else if(path_query.search.size == 0 && dir_selection) - { - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = path_query.path); - } - - // rjf: command argument does not exactly match any file, but lister results are in: - else if(file_count != 0) - { - String8 filename = files[0].filename; - if(files[0].props.flags & FilePropertyFlag_IsFolder) - { - String8 existing_path = str8_chop_last_slash(path_query.path); - String8 new_path = push_str8f(scratch.arena, "%S/%S/", existing_path, files[0].filename); - rd_store_view_filter(new_path); - } - else - { - String8 file_path = push_str8f(scratch.arena, "%S%S", path_query.path, filename); - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = file_path); - } - } - - // rjf: command argument does not match any file, and lister is empty (new file) - else - { - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = query); - } - } - - //- rjf: build non-scrolled table header - U64 row_num = 1; - F32 **col_pcts = push_array(scratch.arena, F32 *, ArrayCount(fs->col_pcts)); - for(U64 idx = 0; idx < ArrayCount(fs->col_pcts); idx += 1) - { - col_pcts[idx] = &fs->col_pcts[idx]; - } - UI_PrefHeight(ui_px(row_height_px, 1)) UI_Focus(UI_FocusKind_Off) UI_TableF(ArrayCount(fs->col_pcts), col_pcts, "###fs_tbl") - { - UI_TableVector - { - struct - { - RD_FileSortKind kind; - String8 string; - } - kinds[] = - { - { RD_FileSortKind_Filename, str8_lit_comp("Filename") }, - { RD_FileSortKind_LastModified, str8_lit_comp("Last Modified") }, - { RD_FileSortKind_Size, str8_lit_comp("Size") }, - }; - for(U64 idx = 0; idx < ArrayCount(kinds); idx += 1) - { - B32 sorting = (fs->sort_kind == kinds[idx].kind); - UI_TableCell UI_FlagsAdd(sorting ? 0 : UI_BoxFlag_DrawTextWeak) - { - UI_Signal sig = ui_sort_header(sorting, - fs->cached_files_sort_side == Side_Min, - kinds[idx].string); - if(ui_clicked(sig)) - { - if(fs->sort_kind != kinds[idx].kind) - { - fs->sort_kind = kinds[idx].kind; - fs->sort_side = Side_Max; - } - else if(fs->sort_kind == kinds[idx].kind && fs->sort_side == Side_Max) - { - fs->sort_side = Side_Min; - } - else if(fs->sort_kind == kinds[idx].kind && fs->sort_side == Side_Min) - { - fs->sort_kind = RD_FileSortKind_Null; - } - } - } - } - } - } - - //- rjf: build file list - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 content_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y-row_height_px); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, file_count+1)); - scroll_list_params.item_range = r1s64(0, file_count+1); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &ps->cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - // rjf: up-one-directory button (at idx 0) - if(visible_row_range.min == 0) - { - // rjf: build - UI_Signal sig = {0}; - UI_FocusHot(ps->cursor.y == row_num ? UI_FocusKind_On : UI_FocusKind_Off) - { - sig = ui_buttonf("###up_one"); - } - - // rjf: make content - UI_Parent(sig.box) - { - // rjf: icons - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_PrefWidth(ui_em(3.f, 1.f)) - UI_TextAlignment(UI_TextAlign_Center) - { - ui_label(rd_icon_kind_text_table[RD_IconKind_LeftArrow]); - } - - // rjf: text - { - ui_label(str8_lit("Up One Directory")); - } - - row_num += 1; - } - - // rjf: click => up one directory - if(ui_clicked(sig)) - { - String8 new_path = str8_chop_last_slash(str8_chop_last_slash(path_query.path)); - new_path = path_normalized_from_string(scratch.arena, new_path); - String8 new_cmd = push_str8f(scratch.arena, "%S%s", new_path, new_path.size != 0 ? "/" : ""); - rd_store_view_filter(new_cmd); - } - } - - // rjf: file buttons - for(U64 row_idx = Max(visible_row_range.min, 1); - row_idx <= visible_row_range.max && row_idx <= file_count; - row_idx += 1, row_num += 1) - { - U64 file_idx = row_idx-1; - RD_FileInfo *file = &files[file_idx]; - B32 file_kb_focus = (ps->cursor.y == (row_idx+1)); - - // rjf: make button - UI_Signal file_sig = {0}; - UI_FocusHot(file_kb_focus ? UI_FocusKind_On : UI_FocusKind_Off) - { - file_sig = ui_buttonf("##%S", file->filename); - } - - // rjf: make content - UI_Parent(file_sig.box) - { - UI_PrefWidth(ui_pct(fs->col_pcts[0], 1)) UI_Row - { - // rjf: icon to signify directory - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_PrefWidth(ui_em(3.f, 1.f)) - UI_TextAlignment(UI_TextAlign_Center) - { - if(file->props.flags & FilePropertyFlag_IsFolder) - { - ui_label((ui_key_match(ui_hot_key(), file_sig.box->key) || file_kb_focus) - ? rd_icon_kind_text_table[RD_IconKind_FolderOpenFilled] - : rd_icon_kind_text_table[RD_IconKind_FolderClosedFilled]); - } - else - { - ui_label(rd_icon_kind_text_table[RD_IconKind_FileOutline]); - } - } - - // rjf: filename - UI_PrefWidth(ui_pct(1, 0)) - { - UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText|UI_BoxFlag_DisableIDString, file->filename); - ui_box_equip_fuzzy_match_ranges(box, &file->match_ranges); - } - } - - // rjf: last-modified time - UI_PrefWidth(ui_pct(fs->col_pcts[1], 1)) UI_Row - UI_PrefWidth(ui_pct(1, 0)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - { - DateTime time = date_time_from_dense_time(file->props.modified); - DateTime time_local = os_local_time_from_universal(&time); - String8 string = push_date_time_string(scratch.arena, &time_local); - ui_label(string); - } - - // rjf: file size - UI_PrefWidth(ui_pct(fs->col_pcts[2], 1)) UI_Row - UI_PrefWidth(ui_pct(1, 0)) - { - if(file->props.size != 0) - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label(str8_from_memory_size(scratch.arena, file->props.size)); - } - } - } - - // rjf: click => activate this file - if(ui_clicked(file_sig)) - { - String8 existing_path = str8_chop_last_slash(path_query.path); - String8 new_path = push_str8f(scratch.arena, "%S%s%S/", existing_path, existing_path.size != 0 ? "/" : "", file->filename); - new_path = path_normalized_from_string(scratch.arena, new_path); - if(file->props.flags & FilePropertyFlag_IsFolder) - { - String8 new_cmd = push_str8f(scratch.arena, "%S%s", new_path, new_path.size != 0 ? "/" : ""); - rd_store_view_filter(new_cmd); - } - else - { - rd_cmd(RD_CmdKind_CompleteQuery, .file_path = new_path); - } - } - } - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: system_processes @view_hook_impl - -typedef struct RD_ProcessInfo RD_ProcessInfo; -struct RD_ProcessInfo -{ - DMN_ProcessInfo info; - B32 is_attached; - FuzzyMatchRangeList attached_match_ranges; - FuzzyMatchRangeList name_match_ranges; - FuzzyMatchRangeList pid_match_ranges; -}; - -typedef struct RD_ProcessInfoNode RD_ProcessInfoNode; -struct RD_ProcessInfoNode -{ - RD_ProcessInfoNode *next; - RD_ProcessInfo info; -}; - -typedef struct RD_ProcessInfoList RD_ProcessInfoList; -struct RD_ProcessInfoList -{ - RD_ProcessInfoNode *first; - RD_ProcessInfoNode *last; - U64 count; -}; - -typedef struct RD_ProcessInfoArray RD_ProcessInfoArray; -struct RD_ProcessInfoArray -{ - RD_ProcessInfo *v; - U64 count; -}; - -internal RD_ProcessInfoList -rd_process_info_list_from_query(Arena *arena, String8 query) -{ - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: gather PIDs that we're currently attached to - U64 attached_process_count = 0; - U32 *attached_process_pids = 0; - { - CTRL_EntityList processes = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, CTRL_EntityKind_Process); - attached_process_count = processes.count; - attached_process_pids = push_array(scratch.arena, U32, attached_process_count); - U64 idx = 0; - for(CTRL_EntityNode *n = processes.first; n != 0; n = n->next, idx += 1) - { - CTRL_Entity *process = n->v; - attached_process_pids[idx] = process->id; - } - } - - //- rjf: build list - RD_ProcessInfoList list = {0}; - { - DMN_ProcessIter iter = {0}; - dmn_process_iter_begin(&iter); - for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &iter, &info);) - { - // rjf: skip root-level or otherwise 0-pid processes - if(info.pid == 0) - { - continue; - } - - // rjf: determine if this process is attached - B32 is_attached = 0; - for(U64 attached_idx = 0; attached_idx < attached_process_count; attached_idx += 1) - { - if(attached_process_pids[attached_idx] == info.pid) - { - is_attached = 1; - break; - } - } - - // rjf: gather fuzzy matches - FuzzyMatchRangeList attached_match_ranges = {0}; - FuzzyMatchRangeList name_match_ranges = fuzzy_match_find(arena, query, info.name); - FuzzyMatchRangeList pid_match_ranges = fuzzy_match_find(arena, query, push_str8f(scratch.arena, "%i", info.pid)); - if(is_attached) - { - attached_match_ranges = fuzzy_match_find(arena, query, str8_lit("[attached]")); - } - - // rjf: determine if this item is filtered out - B32 matches_query = (query.size == 0 || - (attached_match_ranges.needle_part_count != 0 && attached_match_ranges.count >= attached_match_ranges.needle_part_count) || - (name_match_ranges.count != 0 && name_match_ranges.count >= name_match_ranges.needle_part_count) || - (pid_match_ranges.count != 0 && pid_match_ranges.count >= pid_match_ranges.needle_part_count)); - - // rjf: push if unfiltered - if(matches_query) - { - RD_ProcessInfoNode *n = push_array(arena, RD_ProcessInfoNode, 1); - n->info.info = info; - n->info.info.name = push_str8_copy(arena, info.name); - n->info.is_attached = is_attached; - n->info.attached_match_ranges = attached_match_ranges; - n->info.name_match_ranges = name_match_ranges; - n->info.pid_match_ranges = pid_match_ranges; - SLLQueuePush(list.first, list.last, n); - list.count += 1; - } - } - dmn_process_iter_end(&iter); - } - - scratch_end(scratch); - return list; -} - -internal RD_ProcessInfoArray -rd_process_info_array_from_list(Arena *arena, RD_ProcessInfoList list) -{ - RD_ProcessInfoArray array = {0}; - array.count = list.count; - array.v = push_array(arena, RD_ProcessInfo, array.count); - U64 idx = 0; - for(RD_ProcessInfoNode *n = list.first; n != 0; n = n->next, idx += 1) - { - array.v[idx] = n->info; - } - return array; -} - -internal int -rd_qsort_compare_process_info(RD_ProcessInfo *a, RD_ProcessInfo *b) -{ - int result = 0; - if(a->pid_match_ranges.count > b->pid_match_ranges.count) - { - result = -1; - } - else if(a->pid_match_ranges.count < b->pid_match_ranges.count) - { - result = +1; - } - else if(a->name_match_ranges.count < b->name_match_ranges.count) - { - result = -1; - } - else if(a->name_match_ranges.count > b->name_match_ranges.count) - { - result = +1; - } - else if(a->attached_match_ranges.count < b->attached_match_ranges.count) - { - result = -1; - } - else if(a->attached_match_ranges.count > b->attached_match_ranges.count) - { - result = +1; - } - return result; -} - -internal void -rd_process_info_array_sort_by_strength__in_place(RD_ProcessInfoArray array) -{ - quick_sort(array.v, array.count, sizeof(RD_ProcessInfo), rd_qsort_compare_process_info); -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(system_processes) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - - //- rjf: grab state - typedef struct RD_SystemProcessesViewState RD_SystemProcessesViewState; - struct RD_SystemProcessesViewState - { - B32 initialized; - B32 need_initial_gather; - U32 selected_pid; - Arena *cached_process_arena; - String8 cached_process_arg; - RD_ProcessInfoArray cached_process_array; - }; - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_SystemProcessesViewState *sp = rd_view_state(RD_SystemProcessesViewState); - if(sp->initialized == 0) - { - sp->initialized = 1; - sp->need_initial_gather = 1; - sp->cached_process_arena = rd_push_view_arena(); - } - - //- rjf: gather list of filtered process infos - String8 query = string; - RD_ProcessInfoArray process_info_array = sp->cached_process_array; - if(sp->need_initial_gather || !str8_match(sp->cached_process_arg, query, 0)) - { - arena_clear(sp->cached_process_arena); - sp->need_initial_gather = 0; - sp->cached_process_arg = push_str8_copy(sp->cached_process_arena, query); - RD_ProcessInfoList list = rd_process_info_list_from_query(sp->cached_process_arena, query); - sp->cached_process_array = rd_process_info_array_from_list(sp->cached_process_arena, list); - process_info_array = sp->cached_process_array; - rd_process_info_array_sort_by_strength__in_place(process_info_array); - } - - //- rjf: submit best match when hitting enter w/ no selection - if(sp->selected_pid == 0 && process_info_array.count > 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - RD_ProcessInfo *info = &process_info_array.v[0]; - rd_cmd(RD_CmdKind_CompleteQuery, .pid = info->info.pid); - } - - //- rjf: selected PID -> cursor - Vec2S64 cursor = {0}; - { - for(U64 idx = 0; idx < process_info_array.count; idx += 1) - { - if(process_info_array.v[idx].info.pid == sp->selected_pid) - { - cursor.y = idx+1; - break; - } - } - } - - //- rjf: build contents - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 content_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, process_info_array.count)); - scroll_list_params.item_range = r1s64(0, process_info_array.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - //- rjf: build rows - for(U64 idx = visible_row_range.min; - idx <= visible_row_range.max && idx < process_info_array.count; - idx += 1) - { - RD_ProcessInfo *info = &process_info_array.v[idx]; - B32 is_attached = info->is_attached; - UI_Signal sig = {0}; - UI_FocusHot(cursor.y == idx+1 ? UI_FocusKind_On : UI_FocusKind_Off) - { - sig = ui_buttonf("###proc_%i", info->info.pid); - } - UI_Parent(sig.box) - { - // rjf: icon - RD_Font(RD_FontSlot_Icons) - UI_FontSize(rd_font_size_from_slot(RD_FontSlot_Icons)) - UI_PrefWidth(ui_em(3.f, 1.f)) - UI_TextAlignment(UI_TextAlign_Center) - { - ui_label(rd_icon_kind_text_table[RD_IconKind_Threads]); - } - - // rjf: attached indicator - if(is_attached) UI_PrefWidth(ui_text_dim(10, 1)) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - { - UI_Box *attached_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "[attached]##attached_label_%i", (int)info->info.pid); - ui_box_equip_fuzzy_match_ranges(attached_label, &info->attached_match_ranges); - } - - // rjf: process name - UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##name_label_%i", info->info.name, (int)info->info.pid); - ui_box_equip_fuzzy_match_ranges(name_label, &info->name_match_ranges); - } - - // rjf: process number - UI_PrefWidth(ui_text_dim(1, 1)) UI_TextAlignment(UI_TextAlign_Center) UI_TextPadding(0) - { - ui_labelf("[PID: "); - UI_Box *pid_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%i##pid_label", info->info.pid); - ui_box_equip_fuzzy_match_ranges(pid_label, &info->pid_match_ranges); - ui_labelf("]"); - } - } - - // rjf: click => activate this specific process - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_CompleteQuery, .pid = info->info.pid); - } - } - } - - //- rjf: selected num -> selected PID - { - if(1 <= cursor.y && cursor.y <= process_info_array.count) - { - sp->selected_pid = process_info_array.v[cursor.y-1].info.pid; - } - else - { - sp->selected_pid = 0; - } - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: entity_lister @view_hook_impl - -typedef struct RD_EntityListerItem RD_EntityListerItem; -struct RD_EntityListerItem -{ - RD_Entity *entity; - FuzzyMatchRangeList name_match_ranges; -}; - -typedef struct RD_EntityListerItemNode RD_EntityListerItemNode; -struct RD_EntityListerItemNode -{ - RD_EntityListerItemNode *next; - RD_EntityListerItem item; -}; - -typedef struct RD_EntityListerItemList RD_EntityListerItemList; -struct RD_EntityListerItemList -{ - RD_EntityListerItemNode *first; - RD_EntityListerItemNode *last; - U64 count; -}; - -typedef struct RD_EntityListerItemArray RD_EntityListerItemArray; -struct RD_EntityListerItemArray -{ - RD_EntityListerItem *v; - U64 count; -}; - -internal RD_EntityListerItemList -rd_entity_lister_item_list_from_needle(Arena *arena, RD_EntityKind kind, RD_EntityFlags omit_flags, String8 needle) -{ - Temp scratch = scratch_begin(&arena, 1); - RD_EntityListerItemList result = {0}; - RD_EntityList ent_list = rd_query_cached_entity_list_with_kind(kind); - for(RD_EntityNode *n = ent_list.first; n != 0; n = n->next) - { - RD_Entity *entity = n->entity; - if(!(entity->flags & omit_flags)) - { - DR_FancyStringList title_fstrs = rd_title_fstrs_from_entity(scratch.arena, entity, v4f32(0, 0, 0, 0), 0); - String8 title_string = dr_string_from_fancy_string_list(scratch.arena, &title_fstrs); - FuzzyMatchRangeList match_rngs = fuzzy_match_find(arena, needle, title_string); - if(match_rngs.count != 0 || needle.size == 0) - { - RD_EntityListerItemNode *item_n = push_array(arena, RD_EntityListerItemNode, 1); - item_n->item.entity = entity; - item_n->item.name_match_ranges = match_rngs; - SLLQueuePush(result.first, result.last, item_n); - result.count += 1; - } - } - } - scratch_end(scratch); - return result; -} - -internal RD_EntityListerItemArray -rd_entity_lister_item_array_from_list(Arena *arena, RD_EntityListerItemList list) -{ - RD_EntityListerItemArray result = {0}; - result.count = list.count; - result.v = push_array(arena, RD_EntityListerItem, result.count); - { - U64 idx = 0; - for(RD_EntityListerItemNode *n = list.first; n != 0; n = n->next, idx += 1) - { - result.v[idx] = n->item; - } - } - return result; -} - -internal int -rd_qsort_compare_entity_lister__strength(RD_EntityListerItem *a, RD_EntityListerItem *b) -{ - int result = 0; - if(a->name_match_ranges.count > b->name_match_ranges.count) - { - result = -1; - } - else if(a->name_match_ranges.count < b->name_match_ranges.count) - { - result = +1; - } - return result; -} - -internal void -rd_entity_lister_item_array_sort_by_strength__in_place(RD_EntityListerItemArray array) -{ - quick_sort(array.v, array.count, sizeof(RD_EntityListerItem), rd_qsort_compare_entity_lister__strength); -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(entity_lister) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(window->query_cmd_name); - RD_EntityKind entity_kind = cmd_kind_info->query.entity_kind; - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); - - //- rjf: grab state - typedef struct RD_EntityListerViewState RD_EntityListerViewState; - struct RD_EntityListerViewState - { - RD_Handle selected_entity_handle; - }; - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_EntityListerViewState *fev = rd_view_state(RD_EntityListerViewState); - RD_Handle selected_entity_handle = fev->selected_entity_handle; - RD_Entity *selected_entity = rd_entity_from_handle(selected_entity_handle); - - //- rjf: build filtered array of entities - RD_EntityListerItemList ent_list = rd_entity_lister_item_list_from_needle(scratch.arena, entity_kind, 0, string); - RD_EntityListerItemArray ent_arr = rd_entity_lister_item_array_from_list(scratch.arena, ent_list); - rd_entity_lister_item_array_sort_by_strength__in_place(ent_arr); - - //- rjf: submit best match when hitting enter w/ no selection - if(rd_entity_is_nil(rd_entity_from_handle(fev->selected_entity_handle)) && ent_arr.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - RD_Entity *ent = ent_arr.v[0].entity; - rd_cmd(RD_CmdKind_CompleteQuery, .entity = rd_handle_from_entity(ent)); - } - - //- rjf: selected entity -> cursor - Vec2S64 cursor = {0}; - { - for(U64 idx = 0; idx < ent_arr.count; idx += 1) - { - if(ent_arr.v[idx].entity == selected_entity) - { - cursor.y = (S64)(idx+1); - break; - } - } - } - - //- rjf: build list - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 content_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, ent_arr.count)); - scroll_list_params.item_range = r1s64(0, ent_arr.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - for(S64 idx = visible_row_range.min; - idx <= visible_row_range.max && idx < ent_arr.count; - idx += 1) - { - RD_EntityListerItem item = ent_arr.v[idx]; - RD_Entity *ent = item.entity; - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_child_layout_axis(Axis2_X); - UI_Box *box = &ui_nil_box; - UI_FocusHot(idx+1 == cursor.y ? UI_FocusKind_On : UI_FocusKind_Off) - { - box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - "###ent_btn_%p", ent); - } - UI_Parent(box) UI_WidthFill UI_Padding(ui_em(1.f, 1.f)) - { - DR_FancyStringList title_fstrs = rd_title_fstrs_from_entity(scratch.arena, ent, ui_top_palette()->text_weak, ui_top_font_size()); - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &title_fstrs); - ui_box_equip_fuzzy_match_ranges(title_box, &item.name_match_ranges); - } - if(ui_clicked(ui_signal_from_box(box))) - { - rd_cmd(RD_CmdKind_CompleteQuery, .entity = rd_handle_from_entity(ent)); - } - } - } - - //- rjf: selected entity num -> handle - { - fev->selected_entity_handle = (1 <= cursor.y && cursor.y <= ent_arr.count) ? rd_handle_from_entity(ent_arr.v[cursor.y-1].entity) : rd_handle_zero(); - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: ctrl_entity_lister @view_hook_impl - -typedef struct RD_CtrlEntityListerItem RD_CtrlEntityListerItem; -struct RD_CtrlEntityListerItem -{ - CTRL_Entity *entity; - FuzzyMatchRangeList name_match_ranges; -}; - -typedef struct RD_CtrlEntityListerItemNode RD_CtrlEntityListerItemNode; -struct RD_CtrlEntityListerItemNode -{ - RD_CtrlEntityListerItemNode *next; - RD_CtrlEntityListerItem item; -}; - -typedef struct RD_CtrlEntityListerItemList RD_CtrlEntityListerItemList; -struct RD_CtrlEntityListerItemList -{ - RD_CtrlEntityListerItemNode *first; - RD_CtrlEntityListerItemNode *last; - U64 count; -}; - -typedef struct RD_CtrlEntityListerItemArray RD_CtrlEntityListerItemArray; -struct RD_CtrlEntityListerItemArray -{ - RD_CtrlEntityListerItem *v; - U64 count; -}; - -internal RD_CtrlEntityListerItemList -rd_ctrl_entity_lister_item_list_from_needle(Arena *arena, CTRL_EntityKind kind, String8 needle) -{ - Temp scratch = scratch_begin(&arena, 1); - RD_CtrlEntityListerItemList result = {0}; - CTRL_EntityList ent_list = ctrl_entity_list_from_kind(d_state->ctrl_entity_store, kind); - for(CTRL_EntityNode *n = ent_list.first; n != 0; n = n->next) - { - CTRL_Entity *entity = n->v; - DR_FancyStringList title_fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, entity, v4f32(0, 0, 0, 0), 0, 0); - String8 title_fstrs_text = dr_string_from_fancy_string_list(scratch.arena, &title_fstrs); - FuzzyMatchRangeList match_rngs = fuzzy_match_find(arena, needle, title_fstrs_text); - if(match_rngs.count == match_rngs.needle_part_count || needle.size == 0) - { - RD_CtrlEntityListerItemNode *item_n = push_array(arena, RD_CtrlEntityListerItemNode, 1); - item_n->item.entity = entity; - item_n->item.name_match_ranges = match_rngs; - SLLQueuePush(result.first, result.last, item_n); - result.count += 1; - } - } - scratch_end(scratch); - return result; -} - -internal RD_CtrlEntityListerItemArray -rd_ctrl_entity_lister_item_array_from_list(Arena *arena, RD_CtrlEntityListerItemList list) -{ - RD_CtrlEntityListerItemArray result = {0}; - result.count = list.count; - result.v = push_array(arena, RD_CtrlEntityListerItem, result.count); - { - U64 idx = 0; - for(RD_CtrlEntityListerItemNode *n = list.first; n != 0; n = n->next, idx += 1) - { - result.v[idx] = n->item; - } - } - return result; -} - -internal int -rd_qsort_compare_ctrl_entity_lister__strength(RD_CtrlEntityListerItem *a, RD_CtrlEntityListerItem *b) -{ - int result = 0; - if(a->name_match_ranges.count > b->name_match_ranges.count) - { - result = -1; - } - else if(a->name_match_ranges.count < b->name_match_ranges.count) - { - result = +1; - } - return result; -} - -internal void -rd_ctrl_entity_lister_item_array_sort_by_strength__in_place(RD_CtrlEntityListerItemArray array) -{ - quick_sort(array.v, array.count, sizeof(RD_CtrlEntityListerItem), rd_qsort_compare_ctrl_entity_lister__strength); -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(ctrl_entity_lister) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - RD_CmdKindInfo *cmd_kind_info = rd_cmd_kind_info_from_string(window->query_cmd_name); - CTRL_EntityKind entity_kind = cmd_kind_info->query.ctrl_entity_kind; - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); - - //- rjf: grab state - typedef struct RD_CtrlEntityListerViewState RD_CtrlEntityListerViewState; - struct RD_CtrlEntityListerViewState - { - CTRL_Handle selected_entity_handle; - }; - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_CtrlEntityListerViewState *fev = rd_view_state(RD_CtrlEntityListerViewState); - CTRL_Handle selected_entity_handle = fev->selected_entity_handle; - CTRL_Entity *selected_entity = ctrl_entity_from_handle(d_state->ctrl_entity_store, selected_entity_handle); - - //- rjf: build filtered array of entities - RD_CtrlEntityListerItemList ent_list = rd_ctrl_entity_lister_item_list_from_needle(scratch.arena, entity_kind, string); - RD_CtrlEntityListerItemArray ent_arr = rd_ctrl_entity_lister_item_array_from_list(scratch.arena, ent_list); - rd_ctrl_entity_lister_item_array_sort_by_strength__in_place(ent_arr); - - //- rjf: submit best match when hitting enter w/ no selection - if(ctrl_entity_from_handle(d_state->ctrl_entity_store, fev->selected_entity_handle) == &ctrl_entity_nil && ent_arr.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - CTRL_Entity *ent = ent_arr.v[0].entity; - RD_RegsScope() - { - switch(ent->kind) - { - default:{}break; - case CTRL_EntityKind_Machine:{rd_regs()->machine = ent->handle;}break; - case CTRL_EntityKind_Process:{rd_regs()->process = ent->handle;}break; - case CTRL_EntityKind_Thread: {rd_regs()->thread = ent->handle;}break; - case CTRL_EntityKind_Module: {rd_regs()->module = ent->handle;}break; - } - rd_cmd(RD_CmdKind_CompleteQuery, .ctrl_entity = ent->handle); - } - } - - //- rjf: selected entity -> cursor - Vec2S64 cursor = {0}; - { - for(U64 idx = 0; idx < ent_arr.count; idx += 1) - { - if(ent_arr.v[idx].entity == selected_entity) - { - cursor.y = (S64)(idx+1); - break; - } - } - } - - //- rjf: build list - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 content_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, ent_arr.count)); - scroll_list_params.item_range = r1s64(0, ent_arr.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - for(S64 idx = visible_row_range.min; - idx <= visible_row_range.max && idx < ent_arr.count; - idx += 1) - { - RD_CtrlEntityListerItem item = ent_arr.v[idx]; - CTRL_Entity *ent = item.entity; - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_child_layout_axis(Axis2_X); - UI_Box *box = &ui_nil_box; - UI_FocusHot(idx+1 == cursor.y ? UI_FocusKind_On : UI_FocusKind_Off) - { - box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - "###ent_btn_%p", ent); - } - UI_Parent(box) UI_WidthFill UI_Padding(ui_em(1.f, 1.f)) - { - DR_FancyStringList title_fstrs = rd_title_fstrs_from_ctrl_entity(scratch.arena, ent, ui_top_palette()->text_weak, ui_top_font_size(), 1); - UI_Box *title_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(title_box, &title_fstrs); - ui_box_equip_fuzzy_match_ranges(title_box, &item.name_match_ranges); - } - if(ui_clicked(ui_signal_from_box(box))) - { - RD_RegsScope() - { - switch(ent->kind) - { - default:{}break; - case CTRL_EntityKind_Machine:{rd_regs()->machine = ent->handle;}break; - case CTRL_EntityKind_Process:{rd_regs()->process = ent->handle;}break; - case CTRL_EntityKind_Thread: {rd_regs()->thread = ent->handle;}break; - case CTRL_EntityKind_Module: {rd_regs()->module = ent->handle;}break; - } - rd_cmd(RD_CmdKind_CompleteQuery, .ctrl_entity = ent->handle); - } - } - } - } - - //- rjf: selected entity num -> handle - { - fev->selected_entity_handle = (1 <= cursor.y && cursor.y <= ent_arr.count) ? (ent_arr.v[cursor.y-1].entity->handle) : ctrl_handle_zero(); - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: symbol_lister @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(symbol_lister) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - DI_Scope *di_scope = di_scope_open(); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena); - DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); - DI_SearchParams search_params = {RDI_SectionKind_Procedures, dbgi_keys}; - U64 endt_us = os_now_microseconds()+200; - - //- rjf: grab rdis - U64 rdis_count = dbgi_keys.count; - RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); - { - for(U64 idx = 0; idx < rdis_count; idx += 1) - { - RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_keys.v[idx], endt_us); - RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); - rdis[idx] = rdi; - } - } - - //- rjf: grab state - typedef struct RD_SymbolListerViewState RD_SymbolListerViewState; - struct RD_SymbolListerViewState - { - Vec2S64 cursor; - }; - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - RD_SymbolListerViewState *slv = rd_view_state(RD_SymbolListerViewState); - - //- rjf: query -> raddbg, filtered items - U128 search_key = {rd_regs()->view.u64[0], rd_regs()->view.u64[1]}; - B32 items_stale = 0; - DI_SearchItemArray items = di_search_items_from_key_params_query(di_scope, search_key, &search_params, string, endt_us, &items_stale); - if(items_stale) - { - rd_request_frame(); - } - - //- rjf: submit best match when hitting enter w/ no selection - if(slv->cursor.y == 0 && items.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) - { - DI_SearchItem *item = &items.v[0]; - if(item->dbgi_idx < rdis_count) - { - RDI_Parsed *rdi = rdis[item->dbgi_idx]; - U64 rdi_procedures_count = 0; - rdi_section_raw_table_from_kind(rdi, RDI_SectionKind_Procedures, &rdi_procedures_count); - if(item->idx < rdi_procedures_count) - { - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, item->idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); - String8 name = str8(name_base, name_size); - if(name.size != 0) - { - rd_cmd(RD_CmdKind_CompleteQuery, .string = name); - } - } - } - } - - //- rjf: build contents - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 content_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(content_dim.x, content_dim.y); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, items.count)); - scroll_list_params.item_range = r1s64(0, items.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &slv->cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - UI_TextRasterFlags(rd_raster_flags_from_slot(RD_FontSlot_Code)) - { - //- rjf: build rows - for(U64 idx = visible_row_range.min; - idx <= visible_row_range.max && idx < items.count; - idx += 1) - UI_Focus((slv->cursor.y == idx+1) ? UI_FocusKind_On : UI_FocusKind_Off) - { - DI_SearchItem *item = &items.v[idx]; - if(item->dbgi_idx >= rdis_count) {continue;} - DI_Key dbgi_key = dbgi_keys.v[item->dbgi_idx]; - RDI_Parsed *rdi = rdis[item->dbgi_idx]; - - //- rjf: unpack this item's info - RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, item->idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); - String8 name = str8(name_base, name_size); - RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, procedure->type_idx); - E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), procedure->type_idx, e_parse_ctx_module_idx_from_rdi(rdi)); - - //- rjf: build item button - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawText| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - "###procedure_%I64x", item->idx); - UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 1)) RD_Font(RD_FontSlot_Code) - { - UI_Box *box = rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges); - if(!e_type_key_match(e_type_key_zero(), type_key)) - { - String8 type_string = e_type_string_from_key(scratch.arena, type_key); - rd_code_label(0.5f, 0, rd_rgba_from_theme_color(RD_ThemeColor_TextWeak), type_string); - } - } - - //- rjf: interact - UI_Signal sig = ui_signal_from_box(box); - if(ui_clicked(sig)) - { - rd_cmd(RD_CmdKind_CompleteQuery, .string = name); - } - if(ui_hovering(sig)) UI_Tooltip - { - RD_Font(RD_FontSlot_Code) rd_code_label(1.f, 0, rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol), name); - RD_Font(RD_FontSlot_Main) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_labelf("Procedure #%I64u", idx); - U64 binary_voff = d_voff_from_dbgi_key_symbol_name(&dbgi_key, name); - D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, binary_voff); - if(lines.first != 0 && lines.first->v.file_path.size != 0 && lines.first->v.pt.line != 0) - { - String8 file_path = lines.first->v.file_path; - S64 line_num = lines.first->v.pt.line; - RD_Font(RD_FontSlot_Main) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_labelf("%S:%I64d", file_path, line_num); - } - else - { - RD_Font(RD_FontSlot_Main) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - ui_label(str8_lit("(No source code location found)")); - } - } - } - } - - rd_store_view_scroll_pos(scroll_pos); - di_scope_close(di_scope); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: targets @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(targets) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1, .is_non_code = 0); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:targets"), str8_lit("only: label exe args working_directory entry_point stdout_path stderr_path stdin_path debug_subprocesses b32 str"), 1, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: file_path_map @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(file_path_map) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1, .is_non_code = 0); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:file_path_maps"), str8_lit("only: source_path destination_path str"), 1, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: auto_view_rules @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(auto_view_rules) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1, .is_non_code = 0); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:auto_view_rules"), str8_lit("only: type view_rule str"), 1, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: breakpoints @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(breakpoints) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:breakpoints"), str8_lit("only: label condition str hit_count source_location address_location function_location"), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: watch_pins @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(watch_pins) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:watch_pins"), str8_lit("only: label source_location address_location str"), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: scheduler @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(scheduler) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:machines"), str8_lit("only: label str id callstack v count vaddr inline_depth"), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: call_stack @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(call_stack) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_CallStackFrameSelection, 0.05f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_CallStackFrame, 0.50f, .display_string = str8_lit("Symbol"), .dequote_string = 1); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Member, 0.20f, .string = str8_lit("vaddr"), .display_string = str8_lit("Address"), .view_rule = str8_lit("cast:U64")); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Module, 0.25f, .string = str8_lit("module.str"), .display_string = str8_lit("Module"), .dequote_string = 1, .is_non_code = 1); - } - rd_watch_view_build(wv, 0, str8_lit("thread:current_thread.callstack.v"), str8_lit("array:'thread:current_thread.callstack.count', hex"), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: modules @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(modules) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.75f, .dequote_string = 1); - } - rd_watch_view_build(wv, RD_WatchViewFlag_NoHeader|RD_WatchViewFlag_PrettyNameMembers|RD_WatchViewFlag_PrettyEntityRows|RD_WatchViewFlag_DisableCacheLines, - str8_lit("collection:modules"), str8_lit("only: exe dbg str vaddr_range min max"), 0, 16, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: watch @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(watch) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:watches"), str8_lit(""), 1, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: locals @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(locals) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:locals"), str8_lit(""), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: registers @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(registers) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:registers"), str8_lit("hex"), 0, 16, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: globals @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(globals) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:globals"), str8_lit(""), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: thread_locals @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(thread_locals) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:thread_locals"), str8_lit(""), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: types @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(types) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.25f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.3f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Type, 0.15f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.30f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:types"), str8_lit(""), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: procedures @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(procedures) -{ - ProfBeginFunction(); - RD_WatchViewState *wv = rd_view_state(RD_WatchViewState); - if(!wv->initialized) - { - rd_watch_view_init(wv); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Expr, 0.2f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_Value, 0.6f); - rd_watch_view_column_alloc(wv, RD_WatchViewColumnKind_ViewRule, 0.2f); - } - rd_watch_view_build(wv, 0, str8_lit("collection:procedures"), str8_lit(""), 0, 10, rect); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: pending_file @view_hook_impl - -typedef struct RD_PendingFileViewState RD_PendingFileViewState; -struct RD_PendingFileViewState -{ - Arena *deferred_cmd_arena; - RD_CmdList deferred_cmds; -}; - -RD_VIEW_RULE_UI_FUNCTION_DEF(pending_file) -{ - Temp scratch = scratch_begin(0, 0); - RD_PendingFileViewState *pves = rd_view_state(RD_PendingFileViewState); - if(pves->deferred_cmd_arena == 0) - { - pves->deferred_cmd_arena = rd_push_view_arena(); - } - rd_store_view_loading_info(1, 0, 0); - - ////////////////////////////// - //- rjf: process commands - // - for(RD_Cmd *cmd = 0; rd_next_cmd(&cmd);) - { - // rjf: mismatched window/panel => skip - if(!rd_handle_match(rd_regs()->view, cmd->regs->view)) - { - continue; - } - - // rjf: process - RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); - switch(kind) - { - default:break; - - // rjf: gather deferred commands to redispatch when entity is ready - case RD_CmdKind_GoToLine: - case RD_CmdKind_GoToAddress: - case RD_CmdKind_CenterCursor: - case RD_CmdKind_ContainCursor: - { - rd_cmd_list_push_new(pves->deferred_cmd_arena, &pves->deferred_cmds, cmd->name, cmd->regs); - }break; - } - } - - //- rjf: determine if file is ready, and which viewer to use - String8 expr_string = rd_view_expr_string(); - String8 file_path = rd_file_path_from_eval_string(scratch.arena, expr_string); - Rng1U64 file_range = r1u64(0, 1024); - U128 file_hash = fs_hash_from_path_range(file_path, file_range, 0); - B32 file_is_ready = 0; - RD_ViewRuleKind viewer_kind = RD_ViewRuleKind_Text; - { - HS_Scope *hs_scope = hs_scope_open(); - String8 data = hs_data_from_hash(hs_scope, file_hash); - if(!u128_match(file_hash, u128_zero())) - { - U64 num_utf8_bytes = 0; - U64 num_unknown_bytes = 0; - for(U64 idx = 0; idx < data.size && idx < file_range.max;) - { - UnicodeDecode decode = utf8_decode(data.str+idx, data.size-idx); - if(decode.codepoint != max_U32 && (decode.inc > 1 || - (10 <= decode.codepoint && decode.codepoint <= 13) || - (32 <= decode.codepoint && decode.codepoint <= 126))) - { - num_utf8_bytes += decode.inc; - idx += decode.inc; - } - else - { - num_unknown_bytes += 1; - idx += 1; - } - } - file_is_ready = 1; - if(num_utf8_bytes > num_unknown_bytes*4 || num_unknown_bytes == 0) - { - viewer_kind = RD_ViewRuleKind_Text; - } - else - { - viewer_kind = RD_ViewRuleKind_Memory; - } - } - hs_scope_close(hs_scope); - } - - //- rjf: if file is ready, dispatch all deferred commands - if(file_is_ready) - { - for(RD_CmdNode *cmd_node = pves->deferred_cmds.first; cmd_node != 0; cmd_node = cmd_node->next) - { - RD_Cmd *cmd = &cmd_node->cmd; - rd_push_cmd(cmd->name, cmd->regs); - } - arena_clear(pves->deferred_cmd_arena); - MemoryZeroStruct(&pves->deferred_cmds); - } - - //- rjf: if file is ready, move params tree to scratch for new command - MD_Node *params_copy = &md_nil_node; - if(file_is_ready) - { - params_copy = md_tree_copy(scratch.arena, params); - } - - //- rjf: if file is ready, replace this view with the correct one, if any viewer is specified - if(file_is_ready && viewer_kind != RD_ViewRuleKind_Null) - { - RD_ViewRuleInfo *view_rule_info = rd_view_rule_info_from_kind(viewer_kind); - String8 query = rd_eval_string_from_file_path(scratch.arena, file_path); - RD_View *view = rd_view_from_handle(rd_regs()->view); - rd_view_equip_spec(view, view_rule_info, query, params_copy); - } - - //- rjf: if entity is ready, but we have no viewer for it, then just close this tab - if(file_is_ready && viewer_kind == RD_ViewRuleKind_Null) - { - rd_cmd(RD_CmdKind_CloseTab); - } - - scratch_end(scratch); -} +RD_VIEW_UI_FUNCTION_DEF(null) {} //////////////////////////////// //~ rjf: text @view_hook_impl -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(text) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(text) { EV_ExpandInfo info = {0}; info.row_count = 8; @@ -5804,7 +1990,7 @@ EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(text) return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(text) +RD_VIEW_UI_FUNCTION_DEF(text) { RD_CodeViewState *cv = rd_view_state(RD_CodeViewState); rd_code_view_init(cv); @@ -5815,22 +2001,16 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) ////////////////////////////// //- rjf: set up invariants // - F32 bottom_bar_height = ui_top_font_size()*2.f; + F32 main_font_size = ui_bottom_font_size(); + F32 bottom_bar_height = main_font_size*2.f; Rng2F32 code_area_rect = r2f32p(rect.x0, rect.y0, rect.x1, rect.y1 - bottom_bar_height); Rng2F32 bottom_bar_rect = r2f32p(rect.x0, rect.y1 - bottom_bar_height, rect.x1, rect.y1); ////////////////////////////// //- rjf: process code-file commands // - for(RD_Cmd *cmd = 0; rd_next_cmd(&cmd);) + ProfScope("process code-file commands") for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) { - // rjf: mismatched window/panel => skip - if(!rd_handle_match(rd_regs()->view, cmd->regs->view)) - { - continue; - } - - // rjf: process RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); switch(kind) { @@ -5839,7 +2019,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) // rjf: override file picking case RD_CmdKind_PickFile: { - String8 src = rd_file_path_from_eval_string(scratch.arena, rd_view_expr_string()); + String8 src = rd_regs()->file_path; String8 dst = cmd->regs->file_path; if(src.size != 0 && dst.size != 0) { @@ -5856,43 +2036,68 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) ////////////////////////////// //- rjf: unpack parameterization info // - String8 path = rd_file_path_from_eval_string(rd_frame_arena(), string); - rd_regs()->file_path = path; + ProfBegin("unpack parameterization info"); + rd_regs()->file_path = rd_file_path_from_eval(rd_frame_arena(), eval); rd_regs()->vaddr = 0; rd_regs()->prefer_disasm = 0; - rd_regs()->cursor.line = rd_value_from_params_key(params, str8_lit("cursor_line")).s64; - rd_regs()->cursor.column = rd_value_from_params_key(params, str8_lit("cursor_column")).s64; - rd_regs()->mark.line = rd_value_from_params_key(params, str8_lit("mark_line")).s64; - rd_regs()->mark.column = rd_value_from_params_key(params, str8_lit("mark_column")).s64; + rd_regs()->cursor.line = rd_view_setting_value_from_name(str8_lit("cursor_line")).s64; + rd_regs()->cursor.column = rd_view_setting_value_from_name(str8_lit("cursor_column")).s64; + rd_regs()->mark.line = rd_view_setting_value_from_name(str8_lit("mark_line")).s64; + rd_regs()->mark.column = rd_view_setting_value_from_name(str8_lit("mark_column")).s64; if(rd_regs()->cursor.line == 0) { rd_regs()->cursor.line = 1; } if(rd_regs()->cursor.column == 0) { rd_regs()->cursor.column = 1; } - if(rd_regs()->mark.line == 0) { rd_regs()->mark.line = 1; } - if(rd_regs()->mark.column == 0) { rd_regs()->mark.column = 1; } - E_Eval eval = e_eval_from_string(scratch.arena, string); - Rng1U64 range = rd_range_from_eval_params(eval, params); + if(rd_regs()->mark.line == 0) { rd_regs()->mark.line = 1; } + if(rd_regs()->mark.column == 0) { rd_regs()->mark.column = 1; } + U64 base_offset = e_base_offset_from_eval(eval); + U64 size = rd_view_setting_value_from_name(str8_lit("size")).u64; + if(size == 0) + { + size = e_range_size_from_eval(eval); + } + Rng1U64 range = r1u64(base_offset, base_offset+size); rd_regs()->text_key = rd_key_from_eval_space_range(eval.space, range, 1); - rd_regs()->lang_kind = rd_lang_kind_from_eval_params(eval, params); + String8 lang = rd_view_setting_from_name(str8_lit("lang")); + if(lang.size == 0) + { + rd_regs()->lang_kind = rd_lang_kind_from_eval(eval); + } + else + { + rd_regs()->lang_kind = txt_lang_kind_from_extension(lang); + } U128 hash = {0}; TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, rd_regs()->text_key, rd_regs()->lang_kind, &hash); String8 data = hs_data_from_hash(hs_scope, hash); - B32 file_is_missing = (path.size != 0 && os_properties_from_file_path(path).modified == 0); + B32 file_is_missing = (rd_regs()->file_path.size != 0 && os_properties_from_file_path(rd_regs()->file_path).modified == 0); B32 key_has_data = !u128_match(hash, u128_zero()) && info.lines_count; + ProfEnd(); + + ////////////////////////////// + //- rjf: update last hash - scroll-to-bottom if needed + // + if(rd_setting_b32_from_name(str8_lit("scroll_to_bottom_on_change")) && !u128_match(hash, cv->last_hash) && !u128_match(cv->last_hash, u128_zero())) + { + cv->goto_line_num = info.lines_count; + cv->contain_cursor = 1; + cv->force_contain_only = 1; + } + cv->last_hash = hash; ////////////////////////////// //- rjf: build missing file interface // - if(file_is_missing && !u128_match(hash, u128_zero())) + if(file_is_missing) { UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) { Temp scratch = scratch_begin(0, 0); UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_em(3, 1)) UI_Row UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative))) + UI_PrefWidth(ui_text_dim(1, 1)) + UI_TagF("weak") { RD_Font(RD_FontSlot_Icons) ui_label(rd_icon_kind_text_table[RD_IconKind_WarningBig]); - ui_labelf("Could not find \"%S\".", path); + ui_labelf("Could not find \"%S\".", rd_regs()->file_path); } UI_PrefHeight(ui_em(3, 1)) UI_Row UI_Padding(ui_pct(1, 0)) @@ -5900,8 +2105,8 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) UI_CornerRadius(ui_top_font_size()/3) UI_PrefWidth(ui_text_dim(10, 1)) UI_Focus(UI_FocusKind_On) - RD_Palette(RD_PaletteCode_NeutralPopButton) UI_TextAlignment(UI_TextAlign_Center) + UI_TagF("pop") if(ui_clicked(ui_buttonf("Find alternative..."))) { rd_cmd(RD_CmdKind_RunCommand, .cmd_name = rd_cmd_kind_info_table[RD_CmdKind_PickFile].string); @@ -5924,18 +2129,23 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) DI_KeyList dbgi_keys = {0}; if(!file_is_missing) { - RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, RD_CodeViewBuildFlag_All, code_area_rect, data, &info, 0, r1u64(0, 0), di_key_zero()); + RD_CodeViewBuildFlags flags = RD_CodeViewBuildFlag_All; + if(rd_regs()->file_path.size == 0) + { + flags &= ~RD_CodeViewBuildFlag_Margins; + } + RD_CodeViewBuildResult result = rd_code_view_build(scratch.arena, cv, flags, code_area_rect, data, &info, 0, r1u64(0, 0), di_key_zero()); dbgi_keys = result.dbgi_keys; } ////////////////////////////// //- rjf: unpack cursor info // - if(path.size != 0) + if(rd_regs()->file_path.size != 0) { - CTRL_Entity *module = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->module); + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->module); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); - rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, path, rd_regs()->cursor.line); + rd_regs()->lines = d_lines_from_dbgi_key_file_path_line_num(rd_frame_arena(), dbgi_key, rd_regs()->file_path, rd_regs()->cursor.line); } ////////////////////////////// @@ -5944,7 +2154,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) B32 file_is_out_of_date = 0; String8 out_of_date_dbgi_name = {0}; { - U64 file_timestamp = fs_timestamp_from_path(path); + U64 file_timestamp = fs_properties_from_path(rd_regs()->file_path).modified; if(file_timestamp != 0) { for(DI_KeyNode *n = dbgi_keys.first; n != 0; n = n->next) @@ -5963,45 +2173,38 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(text) ////////////////////////////// //- rjf: build bottom bar // - if(!file_is_missing && key_has_data) + if(!file_is_missing && key_has_data) UI_FontSize(main_font_size) UI_TagF(file_is_out_of_date ? "bad_pop" : ".") { ui_set_next_rect(shift_2f32(bottom_bar_rect, scale_2f32(rect.p0, -1.f))); ui_set_next_flags(UI_BoxFlag_DrawBackground); - UI_Palette *palette = ui_top_palette(); - if(file_is_out_of_date) - { - palette = rd_palette_from_code(RD_PaletteCode_NegativePopButton); - } - UI_Palette(palette) - UI_Row + UI_Row UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(10, 1)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + UI_TagF("weak") { - if(file_is_out_of_date) + if(file_is_out_of_date) { UI_Box *box = &ui_nil_box; - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative))) - RD_Font(RD_FontSlot_Icons) + RD_Font(RD_FontSlot_Icons) { box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%S###file_ood_warning", rd_icon_kind_text_table[RD_IconKind_WarningBig]); } UI_Signal sig = ui_signal_from_box(box); if(ui_hovering(sig)) UI_Tooltip { - UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) UI_TextPadding(0) { - ui_labelf("This file has changed since ", out_of_date_dbgi_name); - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNeutral))) ui_label(out_of_date_dbgi_name); - ui_labelf(" was produced."); + UI_TagF("weak") ui_labelf("This file has changed since "); + ui_label(out_of_date_dbgi_name); + UI_TagF("weak") ui_labelf(" was produced."); } } } RD_Font(RD_FontSlot_Code) { - if(path.size != 0) + if(rd_regs()->file_path.size != 0) { - ui_label(path); + ui_label(rd_regs()->file_path); ui_spacer(ui_em(1.5f, 1)); } ui_labelf("Line: %I64d, Column: %I64d", rd_regs()->cursor.line, rd_regs()->cursor.column); @@ -6037,7 +2240,6 @@ struct RD_DisasmViewState B32 initialized; TxtPt cursor; TxtPt mark; - DASM_StyleFlags style_flags; CTRL_Handle temp_look_process; U64 temp_look_vaddr; U64 temp_look_run_gen; @@ -6045,7 +2247,7 @@ struct RD_DisasmViewState RD_CodeViewState cv; }; -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(disasm) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(disasm) { EV_ExpandInfo info = {0}; info.row_count = 8; @@ -6053,7 +2255,7 @@ EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(disasm) return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) +RD_VIEW_UI_FUNCTION_DEF(disasm) { RD_DisasmViewState *dv = rd_view_state(RD_DisasmViewState); if(dv->initialized == 0) @@ -6061,7 +2263,6 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) dv->initialized = 1; dv->cursor = txt_pt(1, 1); dv->mark = txt_pt(1, 1); - dv->style_flags = DASM_StyleFlag_Addresses|DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines|DASM_StyleFlag_SymbolNames; rd_code_view_init(&dv->cv); } RD_CodeViewState *cv = &dv->cv; @@ -6078,26 +2279,27 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) // B32 auto_selected = 0; E_Space auto_space = {0}; - if(string.size == 0) + if(eval.expr == &e_expr_nil) { if(dv->temp_look_vaddr != 0 && dv->temp_look_run_gen == ctrl_run_gen()) { auto_selected = 1; - auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(d_state->ctrl_entity_store, dv->temp_look_process), RD_EvalSpaceKind_CtrlEntity); - string = push_str8f(scratch.arena, "(0x%I64x & (~(0x4000 - 1)))", dv->temp_look_vaddr); + auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, dv->temp_look_process), RD_EvalSpaceKind_CtrlEntity); + eval = e_eval_from_stringf("(0x%I64x & (~(0x4000 - 1)))", dv->temp_look_vaddr); } else { auto_selected = 1; - auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); - string = str8_lit("(rip.u64 & (~(0x4000 - 1)))"); + auto_space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); + eval = e_eval_from_stringf("(rip.u64 & (~(0x4000 - 1)))"); } } ////////////////////////////// //- rjf: set up invariants // - F32 bottom_bar_height = ui_top_font_size()*2.f; + F32 main_font_size = ui_bottom_font_size(); + F32 bottom_bar_height = main_font_size*2.f; Rng2F32 code_area_rect = r2f32p(rect.x0, rect.y0, rect.x1, rect.y1 - bottom_bar_height); Rng2F32 bottom_bar_rect = r2f32p(rect.x0, rect.y1 - bottom_bar_height, rect.x1, rect.y1); rd_regs()->file_path = str8_zero(); @@ -6107,15 +2309,8 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) ////////////////////////////// //- rjf: process disassembly-specific commands // - for(RD_Cmd *cmd = 0; rd_next_cmd(&cmd);) + for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) { - // rjf: mismatched window/panel => skip - if(!rd_handle_match(rd_regs()->view, cmd->regs->view)) - { - continue; - } - - // rjf: process RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); switch(kind) { @@ -6127,22 +2322,25 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) dv->temp_look_run_gen = ctrl_run_gen(); dv->goto_vaddr = cmd->regs->vaddr; }break; - case RD_CmdKind_ToggleCodeBytesVisibility: {dv->style_flags ^= DASM_StyleFlag_CodeBytes;}break; - case RD_CmdKind_ToggleAddressVisibility: {dv->style_flags ^= DASM_StyleFlag_Addresses;}break; } } ////////////////////////////// //- rjf: unpack parameterization info // - E_Eval eval = e_eval_from_string(scratch.arena, string); E_Space space = eval.space; if(auto_selected) { space = auto_space; } - Rng1U64 range = rd_range_from_eval_params(eval, params); - Arch arch = rd_arch_from_eval_params(eval, params); + U64 base_offset = e_base_offset_from_eval(eval); + U64 size = rd_view_setting_value_from_name(str8_lit("size")).u64; + if(size == 0) + { + size = e_range_size_from_eval(eval); + } + Rng1U64 range = r1u64(base_offset, base_offset+size); + Arch arch = rd_arch_from_eval(eval); CTRL_Entity *space_entity = rd_ctrl_entity_from_eval_space(space); CTRL_Entity *dasm_module = &ctrl_entity_nil; DI_Key dbgi_key = {0}; @@ -6158,14 +2356,39 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) base_vaddr = dasm_module->vaddr_range.min; }break; } - U128 dasm_key = rd_key_from_eval_space_range(space, range, 0); + DASM_StyleFlags style_flags = 0; + DASM_Syntax syntax = DASM_Syntax_Intel; + { + if(rd_setting_b32_from_name(str8_lit("show_addresses"))) + { + style_flags |= DASM_StyleFlag_Addresses; + } + if(rd_setting_b32_from_name(str8_lit("show_code_bytes"))) + { + style_flags |= DASM_StyleFlag_CodeBytes; + } + if(rd_setting_b32_from_name(str8_lit("show_source_lines"))) + { + style_flags |= DASM_StyleFlag_SourceFilesNames; + style_flags |= DASM_StyleFlag_SourceLines; + } + if(rd_setting_b32_from_name(str8_lit("show_symbol_names"))) + { + style_flags |= DASM_StyleFlag_SymbolNames; + } + if(str8_match(rd_setting_from_name(str8_lit("syntax")), str8_lit("att"), 0)) + { + syntax = DASM_Syntax_ATT; + } + } + HS_Key dasm_key = rd_key_from_eval_space_range(space, range, 0); U128 dasm_data_hash = {0}; DASM_Params dasm_params = {0}; { dasm_params.vaddr = range.min; dasm_params.arch = arch; - dasm_params.style_flags = dv->style_flags; - dasm_params.syntax = DASM_Syntax_Intel; + dasm_params.style_flags = style_flags; + dasm_params.syntax = syntax; dasm_params.base_vaddr = base_vaddr; dasm_params.dbgi_key = dbgi_key; } @@ -6225,20 +2448,20 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) ////////////////////////////// //- rjf: build bottom bar // - if(!is_loading && has_disasm) + if(!is_loading && has_disasm) UI_FontSize(main_font_size) { ui_set_next_rect(shift_2f32(bottom_bar_rect, scale_2f32(rect.p0, -1.f))); ui_set_next_flags(UI_BoxFlag_DrawBackground); UI_Row UI_TextAlignment(UI_TextAlign_Center) UI_PrefWidth(ui_text_dim(10, 1)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + UI_TagF("weak") RD_Font(RD_FontSlot_Code) { U64 cursor_vaddr = (1 <= rd_regs()->cursor.line && rd_regs()->cursor.line <= dasm_info.lines.count) ? (range.min+dasm_info.lines.v[rd_regs()->cursor.line-1].code_off) : 0; if(dasm_module != &ctrl_entity_nil) { - ui_labelf("%S", path_normalized_from_string(scratch.arena, dasm_module->string)); + ui_labelf("%S", dasm_module->string); ui_spacer(ui_em(1.5f, 1)); } ui_labelf("Address: 0x%I64x, Line: %I64d, Column: %I64d", cursor_vaddr, rd_regs()->cursor.line, rd_regs()->cursor.column); @@ -6260,118 +2483,19 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(disasm) scratch_end(scratch); } -//////////////////////////////// -//~ rjf: output @view_hook_impl - -typedef struct RD_OutputViewState RD_OutputViewState; -struct RD_OutputViewState -{ - U128 last_hash; - RD_CodeViewState cv; -}; - -RD_VIEW_RULE_UI_FUNCTION_DEF(output) -{ - RD_OutputViewState *ov = rd_view_state(RD_OutputViewState); - RD_CodeViewState *cv = &ov->cv; - rd_code_view_init(cv); - Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); - TXT_Scope *txt_scope = txt_scope_open(); - - ////////////////////////////// - //- rjf: set up invariants - // - F32 bottom_bar_height = ui_top_font_size()*2.f; - Rng2F32 code_area_rect = r2f32p(rect.x0, rect.y0, rect.x1, rect.y1 - bottom_bar_height); - Rng2F32 bottom_bar_rect = r2f32p(rect.x0, rect.y1 - bottom_bar_height, rect.x1, rect.y1); - - ////////////////////////////// - //- rjf: unpack parameterization info - // - rd_regs()->file_path = str8_zero(); - rd_regs()->vaddr = 0; - rd_regs()->cursor.line = rd_value_from_params_key(params, str8_lit("cursor_line")).s64; - rd_regs()->cursor.column = rd_value_from_params_key(params, str8_lit("cursor_column")).s64; - rd_regs()->mark.line = rd_value_from_params_key(params, str8_lit("mark_line")).s64; - rd_regs()->mark.column = rd_value_from_params_key(params, str8_lit("mark_column")).s64; - - ////////////////////////////// - //- rjf: unpack text info - // - U128 key = d_state->output_log_key; - TXT_LangKind lang_kind = TXT_LangKind_Null; - U128 hash = {0}; - TXT_TextInfo info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); - String8 data = hs_data_from_hash(hs_scope, hash); - Rng1U64 empty_range = {0}; - if(info.lines_count == 0) - { - info.lines_count = 1; - info.lines_ranges = &empty_range; - } - - ////////////////////////////// - //- rjf: scroll-to-bottom - // - if(!u128_match(hash, ov->last_hash)) - { - ov->last_hash = hash; - cv->goto_line_num = info.lines_count; - cv->contain_cursor= 1; - } - - ////////////////////////////// - //- rjf: build code contents - // - { - rd_code_view_build(scratch.arena, cv, 0, code_area_rect, data, &info, 0, r1u64(0, 0), di_key_zero()); - } - - ////////////////////////////// - //- rjf: build bottom bar - // - { - ui_set_next_rect(shift_2f32(bottom_bar_rect, scale_2f32(rect.p0, -1.f))); - ui_set_next_flags(UI_BoxFlag_DrawBackground); - UI_Row - UI_TextAlignment(UI_TextAlign_Center) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - RD_Font(RD_FontSlot_Code) - { - ui_labelf("(Debug String Output)"); - ui_spacer(ui_em(1.5f, 1)); - ui_labelf("Line: %I64d, Column: %I64d", rd_regs()->cursor.line, rd_regs()->cursor.column); - ui_spacer(ui_pct(1, 0)); - ui_labelf("(read only)"); - } - } - - ////////////////////////////// - //- rjf: store params - // - rd_store_view_param_s64(str8_lit("cursor_line"), rd_regs()->cursor.line); - rd_store_view_param_s64(str8_lit("cursor_column"), rd_regs()->cursor.column); - rd_store_view_param_s64(str8_lit("mark_line"), rd_regs()->mark.line); - rd_store_view_param_s64(str8_lit("mark_column"), rd_regs()->mark.column); - - txt_scope_close(txt_scope); - hs_scope_close(hs_scope); - scratch_end(scratch); -} - //////////////////////////////// //~ rjf: memory @view_hook_impl typedef struct RD_MemoryViewState RD_MemoryViewState; struct RD_MemoryViewState { + Rng1U64 last_view_range; + Rng1U64 last_cursor_range; B32 center_cursor; B32 contain_cursor; }; -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(memory) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(memory) { EV_ExpandInfo info = {0}; info.row_count = 16; @@ -6379,51 +2503,53 @@ EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(memory) return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(memory) +RD_VIEW_UI_FUNCTION_DEF(memory) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - HS_Scope *hs_scope = hs_scope_open(); RD_MemoryViewState *mv = rd_view_state(RD_MemoryViewState); ////////////////////////////// //- rjf: unpack parameterization info // - E_Eval eval = e_eval_from_string(scratch.arena, string); - Rng1U64 space_range = rd_range_from_eval_params(eval, params); + F32 main_font_size = ui_bottom_font_size(); + U64 base_offset = e_base_offset_from_eval(eval); + U64 size = rd_view_setting_value_from_name(str8_lit("size")).u64; + if(size == 0) + { + size = e_range_size_from_eval(eval); + } + Rng1U64 view_range = r1u64(base_offset, base_offset+size); if(eval.space.kind == 0) { - eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); - space_range = rd_whole_range_from_eval_space(eval.space); + eval.space = rd_eval_space_from_ctrl_entity(ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process), RD_EvalSpaceKind_CtrlEntity); + view_range = rd_whole_range_from_eval_space(eval.space); } - if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity && dim_1u64(space_range) == KB(16)) + if(eval.space.kind == RD_EvalSpaceKind_CtrlEntity && dim_1u64(view_range) == KB(16)) { - space_range = r1u64(0, 0x7FFFFFFFFFFFull); + view_range = r1u64(0, 0x7FFFFFFFFFFFull); } - U64 cursor = rd_value_from_params_key(params, str8_lit("cursor_vaddr")).u64; - U64 mark = rd_value_from_params_key(params, str8_lit("mark_vaddr")).u64; - U64 bytes_per_cell = rd_value_from_params_key(params, str8_lit("bytes_per_cell")).u64; - U64 num_columns = rd_value_from_params_key(params, str8_lit("num_columns")).u64; + U64 cursor_base_vaddr = rd_view_setting_u64_from_name(str8_lit("cursor")); + U64 mark_base_vaddr = rd_view_setting_u64_from_name(str8_lit("mark")); + U64 cursor_size = rd_view_setting_u64_from_name(str8_lit("cursor_size")); + cursor_size = ClampBot(1, cursor_size); + U64 initial_cursor_base_vaddr = cursor_base_vaddr; + U64 initial_mark_base_vaddr = mark_base_vaddr; + U64 num_columns = rd_view_setting_u64_from_name(str8_lit("num_columns")); if(num_columns == 0) { num_columns = 16; } num_columns = ClampBot(1, num_columns); - bytes_per_cell = ClampBot(1, bytes_per_cell); UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); + Vec4F32 selection_color = ui_color_from_name(str8_lit("selection")); + Vec4F32 border_color = ui_color_from_name(str8_lit("selection")); ////////////////////////////// //- rjf: process commands // - for(RD_Cmd *cmd = 0; rd_next_cmd(&cmd);) + for(RD_Cmd *cmd = 0; rd_next_view_cmd(&cmd);) { - // rjf: mismatched window/panel => skip - if(!rd_handle_match(rd_regs()->view, cmd->regs->view)) - { - continue; - } - - // rjf: process RD_CmdKind kind = rd_cmd_kind_from_string(cmd->name); switch(kind) { @@ -6438,13 +2564,9 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) }break; case RD_CmdKind_GoToAddress: { - cursor = mark = cmd->regs->vaddr; + cursor_base_vaddr = mark_base_vaddr = cmd->regs->vaddr; mv->center_cursor = 1; }break; - case RD_CmdKind_SetColumns: - { - // TODO(rjf) - }break; } } @@ -6452,50 +2574,72 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) //- rjf: unpack visual params // FNT_Tag font = rd_font_from_slot(RD_FontSlot_Code); - F32 font_size = rd_font_size_from_slot(RD_FontSlot_Code); + FNT_RasterFlags font_raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code); + F32 font_size = ui_top_font_size(); F32 big_glyph_advance = fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_lit("H")).x; F32 row_height_px = floor_f32(font_size*2.f); - F32 cell_width_px = floor_f32(font_size*2.f * bytes_per_cell); - F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); - Vec2F32 panel_dim = dim_2f32(rect); - F32 footer_dim = font_size*10.f; - Rng2F32 header_rect = r2f32p(0, 0, panel_dim.x, row_height_px); - Rng2F32 footer_rect = r2f32p(0, panel_dim.y-footer_dim, panel_dim.x, panel_dim.y); - Rng2F32 content_rect = r2f32p(0, row_height_px, panel_dim.x-scroll_bar_dim, footer_rect.y0); + F32 cell_width_px = floor_f32(font_size*2.f); ////////////////////////////// //- rjf: determine legal scroll range // - Rng1S64 scroll_idx_rng = r1s64(0, dim_1u64(space_range)/num_columns); + U64 view_range_last = view_range.max; + if(view_range_last != 0) + { + view_range_last -= 1; + } + Rng1S64 scroll_idx_rng = r1s64(0, (view_range_last - view_range.min) / num_columns); ////////////////////////////// - //- rjf: determine info about visible range of rows + //- rjf: determine visible range of rows // Rng1S64 viz_range_rows = {0}; - Rng1U64 viz_range_bytes = {0}; S64 num_possible_visible_rows = 0; { - num_possible_visible_rows = dim_2f32(content_rect).y/row_height_px; + num_possible_visible_rows = dim_2f32(rect).y/row_height_px; viz_range_rows.min = scroll_pos.y.idx + (S64)scroll_pos.y.off - !!(scroll_pos.y.off<0); viz_range_rows.max = scroll_pos.y.idx + (S64)scroll_pos.y.off + num_possible_visible_rows, viz_range_rows.min = clamp_1s64(scroll_idx_rng, viz_range_rows.min); viz_range_rows.max = clamp_1s64(scroll_idx_rng, viz_range_rows.max); - viz_range_bytes.min = space_range.min + viz_range_rows.min*num_columns; - viz_range_bytes.max = space_range.min + (viz_range_rows.max+1)*num_columns+1; - if(viz_range_bytes.min > viz_range_bytes.max) - { - Swap(U64, viz_range_bytes.min, viz_range_bytes.max); - } - viz_range_bytes = intersect_1u64(space_range, viz_range_bytes); } + ////////////////////////////// + //- rjf: calculate rectangles + // + F32 scroll_bar_dim = floor_f32(main_font_size*1.5f); + Vec2F32 panel_dim = dim_2f32(rect); + F32 footer_dim = floor_f32(main_font_size*10.f); + Rng2F32 header_rect = r2f32p(0, 0, panel_dim.x, row_height_px); + Rng2F32 footer_rect = r2f32p(0, panel_dim.y-footer_dim, panel_dim.x-scroll_bar_dim, panel_dim.y); + Rng2F32 content_rect = r2f32p(0, row_height_px, panel_dim.x-scroll_bar_dim, panel_dim.y); + + ////////////////////////////// + //- rjf: bump backwards if we are past the first + if(viz_range_rows.min > 0) + { + viz_range_rows.min -= 1; + content_rect.y0 -= row_height_px; + } + + ////////////////////////////// + //- rjf: determine visible range of bytes + // + Rng1U64 viz_range_bytes = {0}; + viz_range_bytes.min = view_range.min + (viz_range_rows.min)*num_columns; + viz_range_bytes.max = view_range.min + (viz_range_rows.max+1)*num_columns+1; + if(viz_range_bytes.min > viz_range_bytes.max) + { + Swap(U64, viz_range_bytes.min, viz_range_bytes.max); + } + viz_range_bytes = intersect_1u64(view_range, viz_range_bytes); + ////////////////////////////// //- rjf: take keyboard controls // UI_Focus(UI_FocusKind_On) if(ui_is_focus_active()) { - U64 next_cursor = cursor; - U64 next_mark = mark; + U64 next_cursor_base_vaddr = cursor_base_vaddr; + U64 next_mark_base_vaddr = mark_base_vaddr; for(UI_Event *evt = 0; ui_next_event(&evt);) { Vec2S64 cell_delta = {0}; @@ -6512,11 +2656,11 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) { if(evt->delta_2s32.x < 0) { - cell_delta.x = -(S64)(cursor%num_columns); + cell_delta.x = -(S64)(cursor_base_vaddr%num_columns); } else if(evt->delta_2s32.x > 0) { - cell_delta.x = (num_columns-1) - (S64)(cursor%num_columns); + cell_delta.x = (num_columns-1) - (S64)(cursor_base_vaddr%num_columns); } if(evt->delta_2s32.y < 0) { @@ -6533,31 +2677,31 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) { good_action = 1; } - if(good_action && evt->flags & UI_EventFlag_ZeroDeltaOnSelect && cursor != mark) + if(good_action && evt->flags & UI_EventFlag_ZeroDeltaOnSelect && cursor_base_vaddr != mark_base_vaddr) { MemoryZeroStruct(&cell_delta); } if(good_action) { - cell_delta.x = ClampBot(cell_delta.x, (S64)-next_cursor); - cell_delta.y = ClampBot(cell_delta.y, (S64)-(next_cursor/num_columns)); - next_cursor += cell_delta.x; - next_cursor += cell_delta.y*num_columns; + cell_delta.x = ClampBot(cell_delta.x, (S64)-next_cursor_base_vaddr); + cell_delta.y = ClampBot(cell_delta.y, (S64)-(next_cursor_base_vaddr/num_columns)); + next_cursor_base_vaddr += cell_delta.x; + next_cursor_base_vaddr += cell_delta.y*num_columns; } - if(good_action && evt->flags & UI_EventFlag_PickSelectSide && cursor != mark) + if(good_action && evt->flags & UI_EventFlag_PickSelectSide && cursor_base_vaddr != mark_base_vaddr) { if(evt->delta_2s32.x < 0 || evt->delta_2s32.y < 0) { - next_cursor = Min(cursor, mark); + next_cursor_base_vaddr = Min(cursor_base_vaddr, mark_base_vaddr); } else { - next_cursor = Max(cursor, mark); + next_cursor_base_vaddr = Max(cursor_base_vaddr, mark_base_vaddr); } } if(good_action && !(evt->flags & UI_EventFlag_KeepMark)) { - next_mark = next_cursor; + next_mark_base_vaddr = next_cursor_base_vaddr; } if(good_action) { @@ -6565,21 +2709,54 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) ui_eat_event(evt); } } - cursor = next_cursor; - mark = next_mark; + cursor_base_vaddr = next_cursor_base_vaddr; + mark_base_vaddr = next_mark_base_vaddr; } ////////////////////////////// //- rjf: clamp cursor // + Rng1U64 cursor_valid_rng = view_range; + if(cursor_valid_rng.max != 0) { - Rng1U64 cursor_valid_rng = space_range; - if(cursor_valid_rng.max != 0) - { - cursor_valid_rng.max -= 1; - } - cursor = clamp_1u64(cursor_valid_rng, cursor); - mark = clamp_1u64(cursor_valid_rng, mark); + cursor_valid_rng.max -= 1; + } + if(cursor_base_vaddr != initial_cursor_base_vaddr) + { + cursor_base_vaddr = clamp_1u64(cursor_valid_rng, cursor_base_vaddr); + } + if(mark_base_vaddr != initial_mark_base_vaddr) + { + mark_base_vaddr = clamp_1u64(cursor_valid_rng, mark_base_vaddr); + } + + ////////////////////////////// + //- rjf: unpack post-move cursor/mark info + // + Rng1U64 cursor_range = r1u64(cursor_base_vaddr, cursor_base_vaddr + cursor_size); + Rng1U64 mark_range = r1u64(mark_base_vaddr, mark_base_vaddr + cursor_size); + Rng1U64 selection = union_1u64(r1u64(cursor_base_vaddr, cursor_base_vaddr+cursor_size-1), + r1u64(mark_base_vaddr, mark_base_vaddr+cursor_size-1)); + + ////////////////////////////// + //- rjf: center cursor if range has changed + // + if(mv->last_view_range.max != view_range.max || + mv->last_view_range.min != view_range.min) + { + mv->center_cursor = 1; + mv->last_view_range = view_range; + } + + ////////////////////////////// + //- rjf: match mark to cursor if cursor has changed + // + if(mv->last_cursor_range.min != cursor_range.min || + mv->last_cursor_range.max != cursor_range.max) + { + mv->contain_cursor = 1; + mv->last_cursor_range = cursor_range; + mark_range = cursor_range; } ////////////////////////////// @@ -6588,7 +2765,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) if(mv->center_cursor) { mv->center_cursor = 0; - S64 cursor_row_idx = cursor/num_columns; + S64 cursor_row_idx = (cursor_base_vaddr - view_range.min) / num_columns; S64 new_idx = (cursor_row_idx-num_possible_visible_rows/2+1); new_idx = clamp_1s64(scroll_idx_rng, new_idx); ui_scroll_pt_target_idx(&scroll_pos.y, new_idx); @@ -6600,7 +2777,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) if(mv->contain_cursor) { mv->contain_cursor = 0; - S64 cursor_row_idx = cursor/num_columns; + S64 cursor_row_idx = (cursor_base_vaddr - view_range.min) / num_columns; Rng1S64 cursor_viz_range = r1s64(clamp_1s64(scroll_idx_rng, cursor_row_idx-2), clamp_1s64(scroll_idx_rng, cursor_row_idx+3)); S64 min_delta = Min(0, cursor_viz_range.min-viz_range_rows.min); S64 max_delta = Max(0, cursor_viz_range.max-viz_range_rows.max); @@ -6610,13 +2787,15 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } ////////////////////////////// - //- rjf: produce fancy string runs for all possible byte values in all cells + //- rjf: produce fancy strings for all possible byte values in all cells // - DR_FancyStringList byte_fancy_strings[256] = {0}; + DR_FStrList byte_fstrs[256] = {0}; { - Vec4F32 full_color = rd_rgba_from_theme_color(RD_ThemeColor_TextPositive); - Vec4F32 zero_color = rd_rgba_from_theme_color(RD_ThemeColor_TextWeak); - for(U64 idx = 0; idx < ArrayCount(byte_fancy_strings); idx += 1) + Vec4F32 full_color = {0}; + UI_TagF("neutral") full_color = ui_color_from_name(str8_lit("text")); + Vec4F32 zero_color = full_color; + UI_TagF("weak") zero_color = ui_color_from_name(str8_lit("text")); + for(U64 idx = 0; idx < ArrayCount(byte_fstrs); idx += 1) { U8 byte = (U8)idx; F32 pct = (byte/255.f); @@ -6625,8 +2804,8 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) { text_color.w *= 0.5f; } - DR_FancyString fstr = {font, push_str8f(scratch.arena, "%02x", byte), text_color, font_size, 0, 0}; - dr_fancy_string_list_push(scratch.arena, &byte_fancy_strings[idx], &fstr); + DR_FStr fstr = {push_str8f(scratch.arena, "%02x", byte), {font, font_raster_flags, text_color, font_size, 0, 0}}; + dr_fstrs_push(scratch.arena, &byte_fstrs[idx], &fstr); } } @@ -6660,17 +2839,18 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) }; AnnotationList *visible_memory_annotations = push_array(scratch.arena, AnnotationList, visible_memory_size); { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process); - CTRL_Unwind unwind = d_query_cached_unwind_from_thread(thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, thread, 1, 0); //- rjf: fill unwind frame annotations - if(unwind.frames.count != 0) + if(call_stack.concrete_frames_count != 0) UI_Tag(str8_lit("weak")) { - U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); - for(U64 idx = 1; idx < unwind.frames.count; idx += 1) + U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, call_stack.concrete_frames[0]->regs); + for(U64 idx = 1; idx < call_stack.concrete_frames_count; idx += 1) { - CTRL_UnwindFrame *f = &unwind.frames.v[idx]; + CTRL_CallStackFrame *f = call_stack.concrete_frames[idx]; U64 f_stack_top = regs_rsp_from_arch_block(thread->arch, f->regs); Rng1U64 frame_vaddr_range = r1u64(last_stack_top, f_stack_top); Rng1U64 frame_vaddr_range_in_viz = intersect_1u64(frame_vaddr_range, viz_range_bytes); @@ -6681,11 +2861,33 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) CTRL_Entity *module = ctrl_module_from_process_vaddr(process, f_rip); DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); U64 rip_voff = ctrl_voff_from_vaddr(module, f_rip); - String8 symbol_name = d_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff, 1); + String8 symbol_name = {0}; + { + U64 vaddr = eval.value.u64; + CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->process); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + U64 voff = ctrl_voff_from_vaddr(module, vaddr); + { + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); + if(symbol_name.size == 0) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, voff); + symbol_name.str = rdi_name_from_procedure(rdi, procedure, &symbol_name.size); + } + if(symbol_name.size == 0) + { + RDI_GlobalVariable *gvar = rdi_global_variable_from_voff(rdi, voff); + symbol_name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &symbol_name.size); + } + di_scope_close(scope); + } + } Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); annotation->kind_string = str8_lit("Call Stack Frame"); - annotation->color = symbol_name.size != 0 ? rd_rgba_from_theme_color(RD_ThemeColor_CodeSymbol) : rd_rgba_from_theme_color(RD_ThemeColor_TextWeak); + annotation->color = symbol_name.size != 0 ? ui_color_from_name(str8_lit("code_symbol")) : ui_color_from_name(str8_lit("text")); annotation->vaddr_range = frame_vaddr_range; for(U64 vaddr = frame_vaddr_range_in_viz.min; vaddr < frame_vaddr_range_in_viz.max; vaddr += 1) { @@ -6697,10 +2899,10 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } //- rjf: fill selected thread stack range annotation - if(unwind.frames.count > 0) + if(call_stack.concrete_frames_count > 0) { U64 stack_base_vaddr = thread->stack_base; - U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); + U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, call_stack.concrete_frames[0]->regs); Rng1U64 stack_vaddr_range = r1u64(stack_base_vaddr, stack_top_vaddr); Rng1U64 stack_vaddr_range_in_viz = intersect_1u64(stack_vaddr_range, viz_range_bytes); if(dim_1u64(stack_vaddr_range_in_viz) != 0) @@ -6708,7 +2910,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = thread->string.size ? thread->string : push_str8f(scratch.arena, "TID: %I64u", thread->id); annotation->kind_string = str8_lit("Stack"); - annotation->color = rd_rgba_from_ctrl_entity(thread); + annotation->color = rd_color_from_ctrl_entity(thread); annotation->vaddr_range = stack_vaddr_range; for(U64 vaddr = stack_vaddr_range_in_viz.min; vaddr < stack_vaddr_range_in_viz.max; vaddr += 1) { @@ -6723,24 +2925,17 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) DI_Scope *scope = di_scope_open(); Vec4F32 color_gen_table[] = { - rd_rgba_from_theme_color(RD_ThemeColor_Thread0), - rd_rgba_from_theme_color(RD_ThemeColor_Thread1), - rd_rgba_from_theme_color(RD_ThemeColor_Thread2), - rd_rgba_from_theme_color(RD_ThemeColor_Thread3), - rd_rgba_from_theme_color(RD_ThemeColor_Thread4), - rd_rgba_from_theme_color(RD_ThemeColor_Thread5), - rd_rgba_from_theme_color(RD_ThemeColor_Thread6), - rd_rgba_from_theme_color(RD_ThemeColor_Thread7), + ui_color_from_name(str8_lit("code_local")), }; U64 thread_rip_vaddr = d_query_cached_rip_from_thread_unwind(thread, rd_regs()->unwind_count); - for(E_String2NumMapNode *n = e_parse_ctx->locals_map->first; n != 0; n = n->order_next) + for(E_String2NumMapNode *n = e_ir_ctx->locals_map->first; n != 0; n = n->order_next) { String8 local_name = n->string; - E_Eval local_eval = e_eval_from_string(scratch.arena, local_name); - if(local_eval.mode == E_Mode_Offset) + E_Eval local_eval = e_eval_from_string(local_name); + if(local_eval.irtree.mode == E_Mode_Offset) { - E_TypeKind local_eval_type_kind = e_type_kind_from_key(local_eval.type_key); - U64 local_eval_type_size = e_type_byte_size_from_key(local_eval.type_key); + E_TypeKind local_eval_type_kind = e_type_kind_from_key(local_eval.irtree.type_key); + U64 local_eval_type_size = e_type_byte_size_from_key(local_eval.irtree.type_key); Rng1U64 vaddr_rng = r1u64(local_eval.value.u64, local_eval.value.u64+local_eval_type_size); Rng1U64 vaddr_rng_in_visible = intersect_1u64(viz_range_bytes, vaddr_rng); if(vaddr_rng_in_visible.max != vaddr_rng_in_visible.min) @@ -6749,7 +2944,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) { annotation->name_string = push_str8_copy(scratch.arena, local_name); annotation->kind_string = str8_lit("Local"); - annotation->type_string = e_type_string_from_key(scratch.arena, local_eval.type_key); + annotation->type_string = e_type_string_from_key(scratch.arena, local_eval.irtree.type_key); annotation->color = color_gen_table[(vaddr_rng.min/8)%ArrayCount(color_gen_table)]; annotation->vaddr_range = vaddr_rng; } @@ -6762,6 +2957,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } di_scope_close(scope); } + ctrl_scope_close(ctrl_scope); } ////////////////////////////// @@ -6776,31 +2972,49 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) container_box = ui_build_box_from_stringf(0, "memory_view_container"); } + ////////////////////////////// + //- rjf: build scroll bar + // + UI_Parent(container_box) UI_FontSize(main_font_size) + { + ui_set_next_fixed_x(content_rect.x1); + ui_set_next_fixed_y(0); + ui_set_next_fixed_width(scroll_bar_dim); + ui_set_next_fixed_height(dim_2f32(rect).y); + { + scroll_pos.y = ui_scroll_bar(Axis2_Y, + ui_px(scroll_bar_dim, 1.f), + scroll_pos.y, + scroll_idx_rng, + num_possible_visible_rows); + } + } + ////////////////////////////// //- rjf: build header // UI_Box *header_box = &ui_nil_box; - UI_Parent(container_box) + UI_Parent(container_box) UI_TagF("floating") { - UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) UI_Row - header_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom, "table_header"); + UI_Rect(r2f32p(0, 0, dim_2f32(rect).x - scroll_bar_dim, row_height_px)) + header_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideBottom| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawDropShadow| + UI_BoxFlag_DrawBackgroundBlur| + UI_BoxFlag_Floating, "table_header"); UI_Parent(header_box) RD_Font(RD_FontSlot_Code) UI_FontSize(font_size) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) { UI_PrefWidth(ui_px(big_glyph_advance*20.f, 1.f)) ui_labelf("Address"); UI_PrefWidth(ui_px(cell_width_px, 1.f)) UI_TextAlignment(UI_TextAlign_Center) { - Rng1U64 col_selection_rng = r1u64(cursor%num_columns, mark%num_columns); - for(U64 row_off = 0; row_off < num_columns*bytes_per_cell; row_off += bytes_per_cell) + Rng1U64 col_selection_rng = r1u64(cursor_base_vaddr%num_columns, mark_base_vaddr%num_columns); + for(U64 row_off = 0; row_off < num_columns; row_off += 1) { - if(!(col_selection_rng.min <= row_off && row_off <= col_selection_rng.max)) - { - ui_set_next_flags(UI_BoxFlag_DrawTextWeak); - } - ui_labelf("%I64X", row_off); + B32 column_is_selected = (selection.min%num_columns <= row_off && row_off <= selection.max%num_columns); + UI_TagF(column_is_selected ? "" : "weak") ui_labelf("%I64X", row_off); } } ui_spacer(ui_px(big_glyph_advance*1.5f, 1.f)); @@ -6809,20 +3023,46 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } ////////////////////////////// - //- rjf: build scroll bar + //- rjf: build footer // - UI_Parent(container_box) + UI_Box *footer_box = &ui_nil_box; + UI_Parent(container_box) UI_FontSize(main_font_size) UI_TagF("floating") { - ui_set_next_fixed_x(content_rect.x1); - ui_set_next_fixed_y(content_rect.y0); - ui_set_next_fixed_width(scroll_bar_dim); - ui_set_next_fixed_height(dim_2f32(content_rect).y); + ui_set_next_fixed_x(footer_rect.x0); + ui_set_next_fixed_y(footer_rect.y0); + ui_set_next_fixed_width(dim_2f32(footer_rect).x); + ui_set_next_fixed_height(dim_2f32(footer_rect).y); + footer_box = ui_build_box_from_stringf(UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow, "footer"); + UI_Parent(footer_box) RD_Font(RD_FontSlot_Code) { - scroll_pos.y = ui_scroll_bar(Axis2_Y, - ui_px(scroll_bar_dim, 1.f), - scroll_pos.y, - scroll_idx_rng, - num_possible_visible_rows); + UI_PrefWidth(ui_em(7.5f, 1.f)) UI_HeightFill UI_Column UI_TagF("weak") + UI_PrefHeight(ui_em(2.f, 0.f)) + { + ui_labelf("Address:"); + ui_labelf("U8:"); + ui_labelf("U16:"); + ui_labelf("U32:"); + ui_labelf("U64:"); + } + UI_PrefWidth(ui_em(45.f, 1.f)) UI_HeightFill UI_Column + UI_PrefHeight(ui_em(2.f, 0.f)) + { + ui_labelf("%016I64X", cursor_base_vaddr); + { + U64 as_u8 = 0; + U64 as_u16 = 0; + U64 as_u32 = 0; + U64 as_u64 = 0; + e_space_read(eval.space, &as_u64, r1u64(cursor_base_vaddr, cursor_base_vaddr+1)); + as_u32 = *(U32 *)&as_u64; + as_u16 = *(U16 *)&as_u64; + as_u8 = *(U8 *)&as_u64; + ui_labelf("%02X (%I64u)", as_u8, as_u8); + ui_labelf("%04X (%I64u)", as_u16, as_u16); + ui_labelf("%08X (%I64u)", as_u32, as_u32); + ui_labelf("%016I64X (%I64u)", as_u64, as_u64); + } + } } } @@ -6836,10 +3076,8 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) ui_set_next_fixed_y(content_rect.y0); ui_set_next_fixed_width(dim_2f32(content_rect).x); ui_set_next_fixed_height(dim_2f32(content_rect).y); - ui_set_next_child_layout_axis(Axis2_Y); scrollable_box = ui_build_box_from_stringf(UI_BoxFlag_Clip| UI_BoxFlag_Scroll| - UI_BoxFlag_AllowOverflowX| UI_BoxFlag_AllowOverflowY, "scrollable_box"); container_box->view_off.x = container_box->view_off_target.x = scroll_pos.x.idx + scroll_pos.x.off; @@ -6854,7 +3092,6 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) UI_Parent(scrollable_box) UI_WidthFill UI_HeightFill { ui_set_next_child_layout_axis(Axis2_Y); - ui_set_next_hover_cursor(OS_Cursor_IBar); row_container_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "row_container"); UI_Parent(row_container_box) { @@ -6909,11 +3146,10 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) { mv->contain_cursor = 1; } - cursor = mouse_hover_byte_num-1; - cursor = clamp_1u64(space_range, cursor); + cursor_base_vaddr = mouse_hover_byte_num-1; if(ui_pressed(sig)) { - mark = cursor; + mark_base_vaddr = cursor_base_vaddr; } } @@ -6927,11 +3163,11 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) ui_eat_event(evt); if(evt->delta_2f32.y < 0) { - rd_cmd(RD_CmdKind_IncCodeFontScale); + rd_cmd(RD_CmdKind_IncViewFontSize); } else if(evt->delta_2f32.y > 0) { - rd_cmd(RD_CmdKind_DecCodeFontScale); + rd_cmd(RD_CmdKind_DecViewFontSize); } } } @@ -6943,32 +3179,32 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) // UI_Parent(row_container_box) RD_Font(RD_FontSlot_Code) UI_FontSize(font_size) { - Rng1U64 selection = r1u64(cursor, mark); U8 *row_ascii_buffer = push_array(scratch.arena, U8, num_columns); UI_WidthFill UI_PrefHeight(ui_px(row_height_px, 1.f)) for(S64 row_idx = viz_range_rows.min; row_idx <= viz_range_rows.max; row_idx += 1) { - Rng1U64 row_range_bytes = r1u64(space_range.min + row_idx*num_columns, - space_range.min + (row_idx+1)*num_columns); - if(row_range_bytes.min >= space_range.max) + Rng1U64 row_range_bytes = r1u64(view_range.min + row_idx*num_columns, view_range.min + (row_idx+1)*num_columns); + if(row_range_bytes.min >= view_range.max) { break; } - B32 row_is_boundary = 0; - if(row_range_bytes.min%64 == 0) + UI_BoxFlags row_flags = 0; + if(row_range_bytes.min <= selection.min && selection.min < row_range_bytes.max) { - row_is_boundary = 1; - Vec4F32 row_boundary_color = rd_rgba_from_theme_color(RD_ThemeColor_CacheLineBoundary); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .border = row_boundary_color)); + row_flags |= UI_BoxFlag_DrawSideTop; } - UI_Box *row = ui_build_box_from_stringf(UI_BoxFlag_DrawSideTop*!!row_is_boundary, "row_%I64x", row_range_bytes.min); + if(row_range_bytes.min <= selection.max && selection.max < row_range_bytes.max) + { + row_flags |= UI_BoxFlag_DrawSideBottom; + } + UI_Box *row = ui_build_box_from_stringf(row_flags, "row_%I64x", row_range_bytes.min); UI_Parent(row) { UI_PrefWidth(ui_px(big_glyph_advance*20.f, 1.f)) { if(!(selection.max >= row_range_bytes.min && selection.min < row_range_bytes.max)) { - ui_set_next_flags(UI_BoxFlag_DrawTextWeak); + ui_set_next_tag(str8_lit("weak")); } ui_labelf("0x%016I64X", row_range_bytes.min); } @@ -6998,12 +3234,10 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) // rjf: unpack visual cell info UI_BoxFlags cell_flags = 0; - Vec4F32 cell_border_rgba = {0}; Vec4F32 cell_bg_rgba = {0}; if(global_byte_num == mouse_hover_byte_num) { cell_flags |= UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawSideTop|UI_BoxFlag_DrawSideBottom|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight; - cell_border_rgba = rd_rgba_from_theme_color(RD_ThemeColor_Hover); } if(annotation != 0) { @@ -7021,20 +3255,28 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) if(selection.min <= global_byte_idx && global_byte_idx <= selection.max) { cell_flags |= UI_BoxFlag_DrawBackground; - cell_bg_rgba = rd_rgba_from_theme_color(RD_ThemeColor_SelectionOverlay); + cell_bg_rgba = selection_color; + } + if(selection.min%num_columns == col_idx) + { + cell_flags |= UI_BoxFlag_DrawSideLeft; + } + if(selection.max%num_columns == col_idx) + { + cell_flags |= UI_BoxFlag_DrawSideRight; } // rjf: build - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = cell_bg_rgba)); + ui_set_next_background_color(cell_bg_rgba); UI_Box *cell_box = ui_build_box_from_key(UI_BoxFlag_DrawText|cell_flags, ui_key_zero()); - ui_box_equip_display_fancy_strings(cell_box, &byte_fancy_strings[byte_value]); + ui_box_equip_display_fstrs(cell_box, &byte_fstrs[byte_value]); { F32 off = 0; for(Annotation *a = annotation; a != 0; a = a->next) { if(global_byte_idx == a->vaddr_range.min) UI_Parent(row_overlay_box) { - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = annotation->color)); + ui_set_next_background_color(annotation->color); ui_set_next_fixed_x(big_glyph_advance*20.f + col_idx*cell_width_px + -cell_width_px/8.f + off); ui_set_next_fixed_y((row_idx-viz_range_rows.min)*row_height_px + -cell_width_px/8.f); ui_set_next_fixed_width(cell_width_px/4.f); @@ -7059,7 +3301,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } if(a->type_string.size != 0) { - rd_code_label(1.f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeType), a->type_string); + rd_code_label(1.f, 1, ui_color_from_name(str8_lit("code_type")), a->type_string); } UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label(str8_from_memory_size(scratch.arena, dim_1u64(a->vaddr_range))); if(a->next != 0) @@ -7099,11 +3341,13 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) DR_BucketScope(bucket) { Vec2F32 text_pos = ui_box_text_position(ascii_box); + Vec4F32 color = selection_color; + color.w *= 0.2f; dr_rect(r2f32p(text_pos.x + fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_prefix(ascii_text, selection_in_row.min+0-row_range_bytes.min)).x - font_size/8.f, ascii_box->rect.y0, text_pos.x + fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_prefix(ascii_text, selection_in_row.max+1-row_range_bytes.min)).x + font_size/4.f, ascii_box->rect.y1), - rd_rgba_from_theme_color(RD_ThemeColor_SelectionOverlay), + color, 0, 0, 1.f); } ui_box_equip_draw_bucket(ascii_box, bucket); @@ -7114,7 +3358,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) DR_BucketScope(bucket) { Vec2F32 text_pos = ui_box_text_position(ascii_box); - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); + Vec4F32 color = border_color; dr_rect(r2f32p(text_pos.x + fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_prefix(ascii_text, mouse_hover_byte_num-1-row_range_bytes.min)).x - font_size/8.f, ascii_box->rect.y0, text_pos.x + fnt_dim_from_tag_size_string(font, font_size, 0, 0, str8_prefix(ascii_text, mouse_hover_byte_num+0-row_range_bytes.min)).x + font_size/4.f, @@ -7129,53 +3373,6 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } } - ////////////////////////////// - //- rjf: build footer - // - UI_Box *footer_box = &ui_nil_box; - UI_Parent(container_box) - { - ui_set_next_fixed_x(footer_rect.x0); - ui_set_next_fixed_y(footer_rect.y0); - ui_set_next_fixed_width(dim_2f32(footer_rect).x); - ui_set_next_fixed_height(dim_2f32(footer_rect).y); - footer_box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, "footer"); - UI_Parent(footer_box) RD_Font(RD_FontSlot_Code) UI_FontSize(font_size) - { - UI_PrefWidth(ui_em(7.5f, 1.f)) UI_HeightFill UI_Column UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_PrefHeight(ui_px(row_height_px, 0.f)) - { - ui_labelf("Address:"); - ui_labelf("U8:"); - ui_labelf("U16:"); - ui_labelf("U32:"); - ui_labelf("U64:"); - } - UI_PrefWidth(ui_em(45.f, 1.f)) UI_HeightFill UI_Column - UI_PrefHeight(ui_px(row_height_px, 0.f)) - { - B32 cursor_in_range = (viz_range_bytes.min <= cursor && cursor+8 <= viz_range_bytes.max); - ui_labelf("%016I64X", cursor); - if(cursor_in_range) - { - U64 as_u8 = 0; - U64 as_u16 = 0; - U64 as_u32 = 0; - U64 as_u64 = 0; - U64 cursor_off = cursor-viz_range_bytes.min; - as_u8 = (U64)*(U8 *)(visible_memory + cursor_off); - as_u16 = (U64)*(U16*)(visible_memory + cursor_off); - as_u32 = (U64)*(U32*)(visible_memory + cursor_off); - as_u64 = (U64)*(U64*)(visible_memory + cursor_off); - ui_labelf("%02X (%I64u)", as_u8, as_u8); - ui_labelf("%04X (%I64u)", as_u16, as_u16); - ui_labelf("%08X (%I64u)", as_u32, as_u32); - ui_labelf("%016I64X (%I64u)", as_u64, as_u64); - } - } - } - } - ////////////////////////////// //- rjf: scroll // @@ -7189,16 +3386,31 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) } } + ////////////////////////////// + //- rjf: re-clamp + // + if(cursor_base_vaddr != initial_cursor_base_vaddr) + { + cursor_base_vaddr = clamp_1u64(cursor_valid_rng, cursor_base_vaddr); + } + if(mark_base_vaddr != initial_mark_base_vaddr) + { + mark_base_vaddr = clamp_1u64(cursor_valid_rng, mark_base_vaddr); + } + ////////////////////////////// //- rjf: save parameters // - rd_store_view_param_u64(str8_lit("cursor_vaddr"), cursor); - rd_store_view_param_u64(str8_lit("mark_vaddr"), mark); - rd_store_view_param_u64(str8_lit("bytes_per_cell"), bytes_per_cell); - rd_store_view_param_u64(str8_lit("num_columns"), num_columns); + if(cursor_base_vaddr != initial_cursor_base_vaddr) + { + rd_store_view_param_u64(str8_lit("cursor"), cursor_base_vaddr); + } + if(mark_base_vaddr != initial_mark_base_vaddr) + { + rd_store_view_param_u64(str8_lit("mark"), mark_base_vaddr); + } rd_store_view_scroll_pos(scroll_pos); - hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); } @@ -7206,7 +3418,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(memory) //////////////////////////////// //~ rjf: "graph" -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(graph) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(graph) { EV_ExpandInfo info = {0}; info.row_count = 8; @@ -7278,7 +3490,11 @@ internal UI_BOX_CUSTOM_DRAW(rd_bitmap_view_canvas_box_draw) Rng2F32 rect_cvs = rd_bitmap_canvas_from_screen_rect(draw_data->view_center_pos, draw_data->zoom, rect_scrn, rect_scrn); F32 grid_cell_size_cvs = box->font_size*10.f; F32 grid_line_thickness_px = Max(2.f, box->font_size*0.1f); - Vec4F32 grid_line_color = rd_rgba_from_theme_color(RD_ThemeColor_TextWeak); + Vec4F32 grid_line_color = {0}; + UI_TagF("weak") + { + grid_line_color = ui_color_from_name(str8_lit("text")); + } for EachEnumVal(Axis2, axis) { for(F32 v = rect_cvs.p0.v[axis] - mod_f32(rect_cvs.p0.v[axis], grid_cell_size_cvs); @@ -7298,7 +3514,7 @@ internal UI_BOX_CUSTOM_DRAW(rd_bitmap_view_canvas_box_draw) } } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(bitmap) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(bitmap) { EV_ExpandInfo info = {0}; info.row_count = 8; @@ -7306,7 +3522,7 @@ EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(bitmap) return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) +RD_VIEW_UI_FUNCTION_DEF(bitmap) { Temp scratch = scratch_begin(0, 0); HS_Scope *hs_scope = hs_scope_open(); @@ -7315,21 +3531,29 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) ////////////////////////////// //- rjf: evaluate expression // - E_Eval eval = e_eval_from_string(scratch.arena, string); - Vec2S32 dim = rd_dim2s32_from_eval_params(eval, params); - R_Tex2DFormat fmt = rd_tex2dformat_from_eval_params(eval, params); - U64 base_offset = rd_base_offset_from_eval(eval); + Vec2S32 dim = v2s32((S32)rd_view_setting_u64_from_name(str8_lit("w")), (S32)rd_view_setting_u64_from_name(str8_lit("h"))); + String8 fmt_string = rd_view_setting_from_name(str8_lit("fmt")); + R_Tex2DFormat fmt = R_Tex2DFormat_RGBA8; + for EachEnumVal(R_Tex2DFormat, f) + { + if(str8_match(fmt_string, r_tex2d_format_display_string_table[f], StringMatchFlag_CaseInsensitive)) + { + fmt = f; + break; + } + } + U64 base_offset = e_base_offset_from_eval(eval); U64 expected_size = dim.x*dim.y*r_tex2d_format_bytes_per_pixel_table[fmt]; Rng1U64 offset_range = r1u64(base_offset, base_offset + expected_size); ////////////////////////////// //- rjf: unpack params // - F32 zoom = rd_value_from_params_key(params, str8_lit("zoom")).f32; + F32 zoom = rd_view_setting_value_from_name(str8_lit("zoom")).f32; Vec2F32 view_center_pos = { - rd_value_from_params_key(params, str8_lit("x")).f32, - rd_value_from_params_key(params, str8_lit("y")).f32, + rd_view_setting_value_from_name(str8_lit("x")).f32, + rd_view_setting_value_from_name(str8_lit("y")).f32, }; if(zoom == 0) { @@ -7348,7 +3572,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) ////////////////////////////// //- rjf: map expression artifacts -> texture // - U128 texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); + HS_Key texture_key = rd_key_from_eval_space_range(eval.space, offset_range, 0); TEX_Topology topology = tex_topology_make(dim, fmt); U128 data_hash = {0}; R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology, &data_hash); @@ -7358,6 +3582,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) //- rjf: equip loading info // if(offset_range.max != offset_range.min && + eval.string.size != 0 && eval.msgs.max_kind == E_MsgKind_Null && (u128_match(data_hash, u128_zero()) || r_handle_match(texture, r_handle_zero()) || @@ -7434,7 +3659,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) //- rjf: image-region canvas interaction // Vec2S32 mouse_bmp = {-1, -1}; - if(ui_hovering(canvas_sig) && !ui_dragging(canvas_sig)) + if(ui_hovering(canvas_sig) && !ui_dragging(canvas_sig)) RD_Font(RD_FontSlot_Code) { Vec2F32 mouse_scr = sub_2f32(ui_mouse(), rect.p0); Vec2F32 mouse_cvs = rd_bitmap_canvas_from_screen_pos(view_center_pos, zoom, canvas_rect, mouse_scr); @@ -7454,7 +3679,7 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) case R_Tex2DFormat_R8: {color = v4f32(((U8 *)(data.str+off_bytes))[0]/255.f, 0, 0, 1);}break; case R_Tex2DFormat_RG8: {color = v4f32(((U8 *)(data.str+off_bytes))[0]/255.f, ((U8 *)(data.str+off_bytes))[1]/255.f, 0, 1);}break; case R_Tex2DFormat_RGBA8: {color = v4f32(((U8 *)(data.str+off_bytes))[0]/255.f, ((U8 *)(data.str+off_bytes))[1]/255.f, ((U8 *)(data.str+off_bytes))[2]/255.f, ((U8 *)(data.str+off_bytes))[3]/255.f);}break; - case R_Tex2DFormat_BGRA8: {color = v4f32(((U8 *)(data.str+off_bytes))[3]/255.f, ((U8 *)(data.str+off_bytes))[2]/255.f, ((U8 *)(data.str+off_bytes))[1]/255.f, ((U8 *)(data.str+off_bytes))[0]/255.f);}break; + case R_Tex2DFormat_BGRA8: {color = v4f32(((U8 *)(data.str+off_bytes))[2]/255.f, ((U8 *)(data.str+off_bytes))[1]/255.f, ((U8 *)(data.str+off_bytes))[0]/255.f, ((U8 *)(data.str+off_bytes))[3]/255.f);}break; case R_Tex2DFormat_R16: {color = v4f32(((U16 *)(data.str+off_bytes))[0]/(F32)max_U16, 0, 0, 1);}break; case R_Tex2DFormat_RGBA16: {color = v4f32(((U16 *)(data.str+off_bytes))[0]/(F32)max_U16, ((U16 *)(data.str+off_bytes))[1]/(F32)max_U16, ((U16 *)(data.str+off_bytes))[2]/(F32)max_U16, ((U16 *)(data.str+off_bytes))[3]/(F32)max_U16);}break; case R_Tex2DFormat_R32: {color = v4f32(((F32 *)(data.str+off_bytes))[0], 0, 0, 1);}break; @@ -7507,150 +3732,246 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(bitmap) } //////////////////////////////// -//~ rjf: "checkbox" +//~ rjf: rgba @view_hook_impl -RD_VIEW_RULE_UI_FUNCTION_DEF(checkbox) +typedef struct RD_EvalColor RD_EvalColor; +struct RD_EvalColor +{ + Vec4F32 rgba; + E_Eval rgba_evals[4]; +}; + +internal RD_EvalColor +rd_eval_color_from_eval(E_Eval eval) { Temp scratch = scratch_begin(0, 0); - E_Eval eval = e_eval_from_string(scratch.arena, string); - E_Eval value_eval = e_value_eval_from_eval(eval); - if(ui_clicked(rd_icon_buttonf(value_eval.value.u64 == 0 ? RD_IconKind_CheckHollow : RD_IconKind_CheckFilled, 0, "###check"))) + + //- rjf: walk eval's type tree, find all four component evaluations + E_Eval component_evals[4] = {0}; { - rd_commit_eval_value_string(eval, value_eval.value.u64 == 0 ? str8_lit("1") : str8_lit("0"), 0); + typedef struct LeafTask LeafTask; + struct LeafTask + { + LeafTask *next; + E_Eval eval; + }; + U64 num_components_left = 4; + LeafTask start_task = {0, eval}; + LeafTask *first_task = &start_task; + LeafTask *last_task = first_task; + for(LeafTask *t = first_task; t != 0 && num_components_left > 0; t = t->next) + { + E_Type *type = e_type_from_key(e_type_key_unwrap(t->eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)); + switch(type->kind) + { + default:{}break; + + // rjf: leaf >u32/s32 -> take all 4 components + case E_TypeKind_U32: + case E_TypeKind_S32: + case E_TypeKind_U64: + case E_TypeKind_S64: + { + component_evals[0] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)(($ & 0xff000000) >> 24) / 255.f")); + component_evals[1] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)(($ & 0x00ff0000) >> 16) / 255.f")); + component_evals[2] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)(($ & 0x0000ff00) >> 8) / 255.f")); + component_evals[3] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)(($ & 0x000000ff) >> 0) / 255.f")); + num_components_left -= 4; + }break; + + //- rjf: array -> generate tasks for first four elements + case E_TypeKind_Array: + { + component_evals[0] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)($[0])")); + component_evals[1] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)($[1])")); + component_evals[2] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)($[2])")); + component_evals[3] = e_value_eval_from_eval(e_eval_wrapf(t->eval, "(float32)($[3])")); + num_components_left -= 4; + }break; + } + } } + + //- rjf: swizzle / extract the component values from the evals, depending on this lens + // (the lens implicitly tells us the format) + RD_EvalColor result = {0}; + { + E_Type *lens_type = e_type_from_key(eval.irtree.type_key); + for(E_Type *t = lens_type; t->kind == E_TypeKind_Lens; t = e_type_from_key(t->direct_type_key)) + { + if(str8_match(t->name, str8_lit("color"), 0)) + { + lens_type = t; + break; + } + } + String8 format_string = str8_lit("rgba"); + if(lens_type->kind == E_TypeKind_Lens && lens_type->count > 0) + { + format_string = lens_type->args[0]->string; + } + if(str8_match(format_string, str8_lit("rgba"), 0)) + { + result.rgba_evals[0] = component_evals[0]; + result.rgba_evals[1] = component_evals[1]; + result.rgba_evals[2] = component_evals[2]; + result.rgba_evals[3] = component_evals[3]; + } + else if(str8_match(format_string, str8_lit("argb"), 0)) + { + result.rgba_evals[0] = component_evals[1]; + result.rgba_evals[1] = component_evals[2]; + result.rgba_evals[2] = component_evals[3]; + result.rgba_evals[3] = component_evals[0]; + } + else if(str8_match(format_string, str8_lit("bgra"), 0)) + { + result.rgba_evals[0] = component_evals[2]; + result.rgba_evals[1] = component_evals[1]; + result.rgba_evals[2] = component_evals[0]; + result.rgba_evals[3] = component_evals[3]; + } + else if(str8_match(format_string, str8_lit("abgr"), 0)) + { + result.rgba_evals[0] = component_evals[3]; + result.rgba_evals[1] = component_evals[2]; + result.rgba_evals[2] = component_evals[1]; + result.rgba_evals[3] = component_evals[0]; + } + for EachIndex(idx, 4) + { + result.rgba.v[idx] = e_value_eval_from_eval(result.rgba_evals[idx]).value.f32; + } + } + scratch_end(scratch); + return result; } -//////////////////////////////// -//~ rjf: color_rgba @view_hook_impl - -internal Vec4F32 -rd_rgba_from_eval_params(E_Eval eval, MD_Node *params) -{ - Vec4F32 rgba = {0}; - { - E_Eval value_eval = e_value_eval_from_eval(eval); - E_TypeKey type_key = eval.type_key; - E_TypeKind type_kind = e_type_kind_from_key(type_key); - U64 type_size = e_type_byte_size_from_key(type_key); - if(16 <= type_size) - { - e_space_read(eval.space, &rgba, r1u64(eval.value.u64, eval.value.u64 + 16)); - } - else if(4 <= type_size) - { - U32 hex_val = value_eval.value.u32; - rgba = rgba_from_u32(hex_val); - } - } - return rgba; -} - -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(color_rgba) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(color) { EV_ExpandInfo info = {0}; - info.row_count = 8; + info.row_count = 12; info.single_item = 1; return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(color_rgba) +RD_VIEW_UI_FUNCTION_DEF(color) { Temp scratch = scratch_begin(0, 0); - Vec2F32 dim = dim_2f32(rect); - F32 padding = ui_top_font_size()*3.f; - E_Eval eval = e_eval_from_string(scratch.arena, string); - Vec4F32 rgba = rd_rgba_from_eval_params(eval, params); - Vec4F32 hsva = hsva_from_rgba(rgba); - //- rjf: too small -> just show components - if(dim.y <= ui_top_font_size()*8.f) + ////////////////////////////// + //- rjf: unpack state + // + typedef struct RD_ColorViewState RD_ColorViewState; + struct RD_ColorViewState { - //- rjf: build text box - UI_Box *text_box = &ui_nil_box; - UI_WidthFill RD_Font(RD_FontSlot_Code) - { - text_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - DR_FancyStringList fancy_strings = {0}; - { - DR_FancyString open_paren = {ui_top_font(), str8_lit("("), ui_top_palette()->text, ui_top_font_size(), 0, 0}; - DR_FancyString comma = {ui_top_font(), str8_lit(", "), ui_top_palette()->text, ui_top_font_size(), 0, 0}; - DR_FancyString r_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.x), v4f32(1.f, 0.25f, 0.25f, 1.f), ui_top_font_size(), 4.f, 0}; - DR_FancyString g_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.y), v4f32(0.25f, 1.f, 0.25f, 1.f), ui_top_font_size(), 4.f, 0}; - DR_FancyString b_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.z), v4f32(0.25f, 0.25f, 1.f, 1.f), ui_top_font_size(), 4.f, 0}; - DR_FancyString a_fstr = {ui_top_font(), push_str8f(scratch.arena, "%.2f", rgba.w), v4f32(1.f, 1.f, 1.f, 1.f), ui_top_font_size(), 4.f, 0}; - DR_FancyString clse_paren = {ui_top_font(), str8_lit(")"), ui_top_palette()->text, ui_top_font_size(), 0, 0}; - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &open_paren); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &r_fstr); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &g_fstr); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &b_fstr); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &comma); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &a_fstr); - dr_fancy_string_list_push(scratch.arena, &fancy_strings, &clse_paren); - } - ui_box_equip_display_fancy_strings(text_box, &fancy_strings); - } - - //- rjf: build color box - UI_Box *color_box = &ui_nil_box; - UI_PrefWidth(ui_em(1.875f, 1.f)) UI_ChildLayoutAxis(Axis2_Y) - { - color_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "color_box"); - UI_Parent(color_box) UI_PrefHeight(ui_em(1.875f, 1.f)) UI_Padding(ui_pct(1, 0)) - { - UI_Palette(ui_build_palette(ui_top_palette(), .background = rgba)) UI_CornerRadius(ui_top_font_size()*0.5f) - ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); - } - } - - //- rjf: space - ui_spacer(ui_em(0.375f, 1.f)); - - //- rjf: hover color box -> show components - UI_Signal sig = ui_signal_from_box(color_box); - if(ui_hovering(sig)) - { - ui_do_color_tooltip_hsva(hsva); - } + B32 initialized; + U32 start_rgba_u32; + Vec4F32 hsva; + }; + RD_ColorViewState *state = rd_view_state(RD_ColorViewState); + RD_EvalColor eval_color = rd_eval_color_from_eval(eval); + U32 rgba_u32 = u32_from_rgba(eval_color.rgba); + if(!state->initialized || rgba_u32 != state->start_rgba_u32) + { + Vec4F32 rgba = eval_color.rgba; + Vec4F32 hsva = hsva_from_rgba(rgba); + state->initialized = 1; + state->start_rgba_u32 = rgba_u32; + state->hsva = hsva; } + Vec4F32 hsva = state->hsva; + Vec4F32 rgba = rgba_from_hsva(hsva); - //- rjf: large enough -> full color picker - else + ////////////////////////////// + //- rjf: calculate dimensions + // + Vec2F32 dim = dim_2f32(rect); + F32 sv_dim_px = Min(dim.x, dim.y); + F32 padding = sv_dim_px*0.2f; + sv_dim_px -= padding*2.f; + sv_dim_px = Min(sv_dim_px, ui_top_font_size()*70.f); + + ////////////////////////////// + //- rjf: build UI + // { - UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_px(padding, 1.f)) UI_Row UI_Padding(ui_pct(1.f, 0.f)) UI_HeightFill + UI_WidthFill UI_HeightFill + UI_PrefHeight(ui_children_sum(1)) UI_Column UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefHeight(ui_children_sum(1)) UI_Row UI_Padding(ui_pct(1.f, 0.f)) + UI_PrefWidth(ui_px(sv_dim_px, 1.f)) + UI_PrefHeight(ui_px(sv_dim_px, 1.f)) + RD_Font(RD_FontSlot_Code) { - UI_PrefWidth(ui_px(dim.y - padding*2, 1.f)) - { - UI_Signal sv_sig = ui_sat_val_pickerf(hsva.x, &hsva.y, &hsva.z, "sat_val_picker"); - } + UI_Signal sv_sig = ui_sat_val_pickerf(hsva.x, &hsva.y, &hsva.z, "sat_val_picker"); + UI_Signal h_sig = {0}; + UI_Signal a_sig = {0}; + ui_spacer(ui_em(1.f, 1.f)); UI_PrefWidth(ui_em(3.f, 1.f)) { - UI_Signal h_sig = ui_hue_pickerf(&hsva.x, hsva.y, hsva.z, "hue_picker"); + h_sig = ui_hue_pickerf(&hsva.x, hsva.y, hsva.z, "hue_picker"); } - UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_em(2.f, 0.f)) RD_Font(RD_FontSlot_Code) UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + ui_spacer(ui_em(1.f, 1.f)); + UI_PrefWidth(ui_em(3.f, 1.f)) { - ui_labelf("Hex"); - ui_labelf("R"); - ui_labelf("G"); - ui_labelf("B"); - ui_labelf("H"); - ui_labelf("S"); - ui_labelf("V"); - ui_labelf("A"); + a_sig = ui_alpha_pickerf(&hsva.w, "alpha_picker"); } - UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_em(2.f, 0.f)) RD_Font(RD_FontSlot_Code) + ui_spacer(ui_em(1.f, 1.f)); + UI_PrefWidth(ui_children_sum(1)) UI_Column { - String8 hex_string = hex_string_from_rgba_4f32(scratch.arena, rgba); - ui_label(hex_string); - ui_labelf("%.2f", rgba.x); - ui_labelf("%.2f", rgba.y); - ui_labelf("%.2f", rgba.z); - ui_labelf("%.2f", hsva.x); - ui_labelf("%.2f", hsva.y); - ui_labelf("%.2f", hsva.z); - ui_labelf("%.2f", rgba.w); + UI_PrefWidth(ui_em(6.f, 0.f)) UI_PrefHeight(ui_em(6.f, 0.f)) + UI_BackgroundColor(linear_from_srgba(v4f32(rgba.x, rgba.y, rgba.z, 1.f))) + UI_CornerRadius(4.f) + UI_PrefWidth(ui_em(6.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) + ui_build_box_from_string(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, str8_lit("")); + ui_spacer(ui_em(2.f, 1.f)); + UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_children_sum(1)) UI_Row + { + UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_em(2.f, 0.f)) RD_Font(RD_FontSlot_Code) + UI_TagF("weak") + { + ui_labelf("Hex"); + ui_labelf("R"); + ui_labelf("G"); + ui_labelf("B"); + ui_labelf("H"); + ui_labelf("S"); + ui_labelf("V"); + ui_labelf("A"); + } + UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_PrefHeight(ui_em(2.f, 0.f)) RD_Font(RD_FontSlot_Code) + { + String8 hex_string = hex_string_from_rgba_4f32(scratch.arena, rgba); + ui_label(hex_string); + ui_labelf("%.2f", rgba.x); + ui_labelf("%.2f", rgba.y); + ui_labelf("%.2f", rgba.z); + ui_labelf("%.2f", hsva.x); + ui_labelf("%.2f", hsva.y); + ui_labelf("%.2f", hsva.z); + ui_labelf("%.2f", rgba.w); + } + } + } + if(ui_dragging(h_sig) || ui_dragging(sv_sig) || ui_dragging(a_sig)) + { + // TODO(rjf): hard-coding U32 committing for now + E_Type *type = e_type_from_key(e_type_key_unwrap(eval.irtree.type_key, E_TypeUnwrapFlag_AllDecorative)); + if(type->kind == E_TypeKind_U32 || + type->kind == E_TypeKind_S32 || + type->kind == E_TypeKind_U64 || + type->kind == E_TypeKind_S64) + { + Vec4F32 new_rgba = rgba_from_hsva(hsva); + U32 u32 = u32_from_rgba(new_rgba); + String8 string = push_str8f(scratch.arena, "0x%x", u32); + if(rd_commit_eval_value_string(eval, string)) + { + state->start_rgba_u32 = u32; + state->hsva = hsva; + } + } } } } @@ -7707,7 +4028,7 @@ internal UI_BOX_CUSTOM_DRAW(rd_geo3d_box_draw) dr_mesh(draw_data->vertex_buffer, draw_data->index_buffer, R_GeoTopologyKind_Triangles, R_GeoVertexFlag_TexCoord|R_GeoVertexFlag_Normals|R_GeoVertexFlag_RGB, r_handle_zero(), mat_4x4f32(1.f)); } -EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(geo3d) +EV_EXPAND_RULE_INFO_FUNCTION_DEF(geo3d) { EV_ExpandInfo info = {0}; info.row_count = 16; @@ -7715,7 +4036,7 @@ EV_VIEW_RULE_EXPR_EXPAND_INFO_FUNCTION_DEF(geo3d) return info; } -RD_VIEW_RULE_UI_FUNCTION_DEF(geo3d) +RD_VIEW_UI_FUNCTION_DEF(geo3d) { Temp scratch = scratch_begin(0, 0); GEO_Scope *geo_scope = geo_scope_open(); @@ -7724,29 +4045,29 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(geo3d) ////////////////////////////// //- rjf: unpack parameters // - U64 count = rd_value_from_params_key(params, str8_lit("count")).u64; - U64 vtx_base_off = rd_value_from_params_key(params, str8_lit("vtx")).u64; - U64 vtx_size = rd_value_from_params_key(params, str8_lit("vtx_size")).u64; - F32 yaw_target = rd_value_from_params_key(params, str8_lit("yaw")).f32; - F32 pitch_target = rd_value_from_params_key(params, str8_lit("pitch")).f32; - F32 zoom_target = rd_value_from_params_key(params, str8_lit("zoom")).f32; + U64 count = rd_view_setting_u64_from_name(str8_lit("count")); + U64 vtx_base_off = rd_view_setting_u64_from_name(str8_lit("vtx")); + U64 vtx_size = rd_view_setting_u64_from_name(str8_lit("vtx_size")); + F32 yaw_target = rd_view_setting_f32_from_name(str8_lit("yaw")); + F32 pitch_target = rd_view_setting_f32_from_name(str8_lit("pitch")); + F32 zoom_target = rd_view_setting_f32_from_name(str8_lit("zoom")); ////////////////////////////// //- rjf: evaluate & unpack expression // - E_Eval eval = e_eval_from_string(scratch.arena, string); - U64 base_offset = rd_base_offset_from_eval(eval); + U64 base_offset = e_base_offset_from_eval(eval); Rng1U64 idxs_range = r1u64(base_offset, base_offset+count*sizeof(U32)); Rng1U64 vtxs_range = r1u64(vtx_base_off, vtx_base_off+vtx_size); - U128 idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); - U128 vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); + HS_Key idxs_key = rd_key_from_eval_space_range(eval.space, idxs_range, 0); + HS_Key vtxs_key = rd_key_from_eval_space_range(eval.space, vtxs_range, 0); R_Handle idxs_buffer = geo_buffer_from_key(geo_scope, idxs_key); R_Handle vtxs_buffer = geo_buffer_from_key(geo_scope, vtxs_key); ////////////////////////////// //- rjf: equip loading info // - if(eval.msgs.max_kind == E_MsgKind_Null && + if(eval.string.size != 0 && + eval.msgs.max_kind == E_MsgKind_Null && (r_handle_match(idxs_buffer, r_handle_zero()) || r_handle_match(vtxs_buffer, r_handle_zero()))) { @@ -7827,840 +4148,3 @@ RD_VIEW_RULE_UI_FUNCTION_DEF(geo3d) geo_scope_close(geo_scope); scratch_end(scratch); } - -//////////////////////////////// -//~ rjf: exception_filters @view_hook_impl - -RD_VIEW_RULE_UI_FUNCTION_DEF(exception_filters) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - String8 query = string; - - //- rjf: get state - typedef struct RD_ExceptionFiltersViewState RD_ExceptionFiltersViewState; - struct RD_ExceptionFiltersViewState - { - Vec2S64 cursor; - }; - RD_ExceptionFiltersViewState *sv = rd_view_state(RD_ExceptionFiltersViewState); - - //- rjf: get list of options - typedef struct RD_ExceptionFiltersOption RD_ExceptionFiltersOption; - struct RD_ExceptionFiltersOption - { - String8 name; - FuzzyMatchRangeList matches; - B32 is_enabled; - CTRL_ExceptionCodeKind exception_code_kind; - }; - typedef struct RD_ExceptionFiltersOptionChunkNode RD_ExceptionFiltersOptionChunkNode; - struct RD_ExceptionFiltersOptionChunkNode - { - RD_ExceptionFiltersOptionChunkNode *next; - RD_ExceptionFiltersOption *v; - U64 cap; - U64 count; - }; - typedef struct RD_ExceptionFiltersOptionChunkList RD_ExceptionFiltersOptionChunkList; - struct RD_ExceptionFiltersOptionChunkList - { - RD_ExceptionFiltersOptionChunkNode *first; - RD_ExceptionFiltersOptionChunkNode *last; - U64 option_count; - U64 node_count; - }; - typedef struct RD_ExceptionFiltersOptionArray RD_ExceptionFiltersOptionArray; - struct RD_ExceptionFiltersOptionArray - { - RD_ExceptionFiltersOption *v; - U64 count; - }; - RD_ExceptionFiltersOptionChunkList opts_list = {0}; - for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)(CTRL_ExceptionCodeKind_Null+1); - k < CTRL_ExceptionCodeKind_COUNT; - k = (CTRL_ExceptionCodeKind)(k+1)) - { - RD_ExceptionFiltersOptionChunkNode *node = opts_list.last; - String8 name = push_str8f(scratch.arena, "0x%x %S", ctrl_exception_code_kind_code_table[k], ctrl_exception_code_kind_display_string_table[k]); - FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, query, name); - if(matches.count >= matches.needle_part_count) - { - if(node == 0 || node->count >= node->cap) - { - node = push_array(scratch.arena, RD_ExceptionFiltersOptionChunkNode, 1); - node->cap = 256; - node->v = push_array_no_zero(scratch.arena, RD_ExceptionFiltersOption, node->cap); - SLLQueuePush(opts_list.first, opts_list.last, node); - opts_list.node_count += 1; - } - node->v[node->count].name = name; - node->v[node->count].matches = matches; - node->v[node->count].is_enabled = !!(rd_state->ctrl_exception_code_filters[k/64] & (1ull<<(k%64))); - node->v[node->count].exception_code_kind = k; - node->count += 1; - opts_list.option_count += 1; - } - } - RD_ExceptionFiltersOptionArray opts = {0}; - { - opts.count = opts_list.option_count; - opts.v = push_array_no_zero(scratch.arena, RD_ExceptionFiltersOption, opts.count); - U64 idx = 0; - for(RD_ExceptionFiltersOptionChunkNode *n = opts_list.first; n != 0; n = n->next) - { - MemoryCopy(opts.v+idx, n->v, n->count*sizeof(RD_ExceptionFiltersOption)); - idx += n->count; - } - } - - //- rjf: build option table - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 rect_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = rect_dim; - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, opts.count)); - scroll_list_params.item_range = r1s64(0, opts.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, - &scroll_pos.y, - &sv->cursor, - 0, - &visible_row_range, - &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - for(S64 row = visible_row_range.min; row <= visible_row_range.max && row < opts.count; row += 1) - UI_FocusHot(sv->cursor.y == row+1 ? UI_FocusKind_On : UI_FocusKind_Off) - { - RD_ExceptionFiltersOption *opt = &opts.v[row]; - UI_Signal sig = rd_icon_buttonf(opt->is_enabled ? RD_IconKind_CheckFilled : RD_IconKind_CheckHollow, &opt->matches, "%S", opt->name); - if(ui_clicked(sig)) - { - if(opt->exception_code_kind != CTRL_ExceptionCodeKind_Null) - { - CTRL_ExceptionCodeKind k = opt->exception_code_kind; - if(opt->is_enabled) - { - rd_state->ctrl_exception_code_filters[k/64] &= ~(1ull<<(k%64)); - } - else - { - rd_state->ctrl_exception_code_filters[k/64] |= (1ull<<(k%64)); - } - } - } - } - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} - -//////////////////////////////// -//~ rjf: settings @view_hook_impl - -typedef enum RD_SettingsItemKind -{ - RD_SettingsItemKind_CategoryHeader, - RD_SettingsItemKind_GlobalSetting, - RD_SettingsItemKind_WindowSetting, - RD_SettingsItemKind_ThemeColor, - RD_SettingsItemKind_ThemePreset, - RD_SettingsItemKind_COUNT -} -RD_SettingsItemKind; - -typedef struct RD_SettingsItem RD_SettingsItem; -struct RD_SettingsItem -{ - RD_SettingsItemKind kind; - String8 kind_string; - String8 string; - FuzzyMatchRangeList kind_string_matches; - FuzzyMatchRangeList string_matches; - RD_IconKind icon_kind; - RD_SettingCode code; - RD_ThemeColor color; - RD_ThemePreset preset; - RD_SettingsItemKind category; -}; - -typedef struct RD_SettingsItemNode RD_SettingsItemNode; -struct RD_SettingsItemNode -{ - RD_SettingsItemNode *next; - RD_SettingsItem v; -}; - -typedef struct RD_SettingsItemList RD_SettingsItemList; -struct RD_SettingsItemList -{ - RD_SettingsItemNode *first; - RD_SettingsItemNode *last; - U64 count; -}; - -typedef struct RD_SettingsItemArray RD_SettingsItemArray; -struct RD_SettingsItemArray -{ - RD_SettingsItem *v; - U64 count; -}; - -internal int -rd_qsort_compare_settings_item(RD_SettingsItem *a, RD_SettingsItem *b) -{ - int result = 0; - if(a->string_matches.count > b->string_matches.count) - { - result = -1; - } - else if(a->string_matches.count < b->string_matches.count) - { - result = +1; - } - else if(a->kind_string_matches.count > b->kind_string_matches.count) - { - result = -1; - } - else if(a->kind_string_matches.count < b->kind_string_matches.count) - { - result = +1; - } - return result; -} - -RD_VIEW_RULE_UI_FUNCTION_DEF(settings) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - String8 query = string; - RD_Window *window = rd_window_from_handle(rd_regs()->window); - UI_ScrollPt2 scroll_pos = rd_view_scroll_pos(); - - ////////////////////////////// - //- rjf: get state - // - typedef struct RD_SettingsViewState RD_SettingsViewState; - struct RD_SettingsViewState - { - B32 initialized; - Vec2S64 cursor; - TxtPt txt_cursor; - TxtPt txt_mark; - U8 txt_buffer[1024]; - U64 txt_size; - RD_ThemeColor color_ctx_menu_color; - Vec4F32 color_ctx_menu_color_hsva; - RD_ThemePreset preset_apply_confirm; - B32 category_opened[RD_SettingsItemKind_COUNT]; - }; - RD_SettingsViewState *sv = rd_view_state(RD_SettingsViewState); - if(!sv->initialized) - { - sv->initialized = 1; - sv->preset_apply_confirm = RD_ThemePreset_COUNT; - } - - ////////////////////////////// - //- rjf: gather all filtered settings items - // - RD_SettingsItemArray items = {0}; - { - RD_SettingsItemList items_list = {0}; - - //- rjf: global settings header - if(query.size == 0) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_CategoryHeader; - n->v.string = str8_lit("Global Interface Settings"); - n->v.icon_kind = sv->category_opened[RD_SettingsItemKind_GlobalSetting] ? RD_IconKind_DownCaret : RD_IconKind_RightCaret; - n->v.category = RD_SettingsItemKind_GlobalSetting; - } - - //- rjf: gather all global settings - if(sv->category_opened[RD_SettingsItemKind_GlobalSetting] || query.size != 0) - { - for EachEnumVal(RD_SettingCode, code) - { - if(rd_setting_code_default_is_per_window_table[code]) - { - continue; - } - String8 kind_string = str8_lit("Global Interface Setting"); - String8 string = rd_setting_code_display_string_table[code]; - FuzzyMatchRangeList kind_string_matches = fuzzy_match_find(scratch.arena, query, kind_string); - FuzzyMatchRangeList string_matches = fuzzy_match_find(scratch.arena, query, string); - if(string_matches.count == string_matches.needle_part_count || - kind_string_matches.count == kind_string_matches.needle_part_count) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_GlobalSetting; - n->v.kind_string = kind_string; - n->v.string = string; - n->v.kind_string_matches = kind_string_matches; - n->v.string_matches = string_matches; - n->v.icon_kind = RD_IconKind_Window; - n->v.code = code; - } - } - } - - //- rjf: window settings header - if(query.size == 0) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_CategoryHeader; - n->v.string = str8_lit("Window Interface Settings"); - n->v.icon_kind = sv->category_opened[RD_SettingsItemKind_WindowSetting] ? RD_IconKind_DownCaret : RD_IconKind_RightCaret; - n->v.category = RD_SettingsItemKind_WindowSetting; - } - - //- rjf: gather all window settings - if(sv->category_opened[RD_SettingsItemKind_WindowSetting] || query.size != 0) - { - for EachEnumVal(RD_SettingCode, code) - { - if(!rd_setting_code_default_is_per_window_table[code]) - { - continue; - } - String8 kind_string = str8_lit("Window Interface Setting"); - String8 string = rd_setting_code_display_string_table[code]; - FuzzyMatchRangeList kind_string_matches = fuzzy_match_find(scratch.arena, query, kind_string); - FuzzyMatchRangeList string_matches = fuzzy_match_find(scratch.arena, query, string); - if(string_matches.count == string_matches.needle_part_count || - kind_string_matches.count == kind_string_matches.needle_part_count) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_WindowSetting; - n->v.kind_string = kind_string; - n->v.string = string; - n->v.kind_string_matches = kind_string_matches; - n->v.string_matches = string_matches; - n->v.icon_kind = RD_IconKind_Window; - n->v.code = code; - } - } - } - - //- rjf: theme presets header - if(query.size == 0) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_CategoryHeader; - n->v.string = str8_lit("Theme Presets"); - n->v.icon_kind = sv->category_opened[RD_SettingsItemKind_ThemePreset] ? RD_IconKind_DownCaret : RD_IconKind_RightCaret; - n->v.category = RD_SettingsItemKind_ThemePreset; - } - - //- rjf: gather theme presets - if(sv->category_opened[RD_SettingsItemKind_ThemePreset] || query.size != 0) - { - for EachEnumVal(RD_ThemePreset, preset) - { - String8 kind_string = str8_lit("Theme Preset"); - String8 string = rd_theme_preset_display_string_table[preset]; - FuzzyMatchRangeList kind_string_matches = fuzzy_match_find(scratch.arena, query, kind_string); - FuzzyMatchRangeList string_matches = fuzzy_match_find(scratch.arena, query, string); - if(string_matches.count == string_matches.needle_part_count || - kind_string_matches.count == kind_string_matches.needle_part_count) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_ThemePreset; - n->v.kind_string = kind_string; - n->v.string = string; - n->v.kind_string_matches = kind_string_matches; - n->v.string_matches = string_matches; - n->v.icon_kind = RD_IconKind_Palette; - n->v.preset = preset; - } - } - } - - //- rjf: theme colors header - if(query.size == 0) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_CategoryHeader; - n->v.string = str8_lit("Theme Colors"); - n->v.icon_kind = sv->category_opened[RD_SettingsItemKind_ThemeColor] ? RD_IconKind_DownCaret : RD_IconKind_RightCaret; - n->v.category = RD_SettingsItemKind_ThemeColor; - } - - //- rjf: gather all theme colors - if(sv->category_opened[RD_SettingsItemKind_ThemeColor] || query.size != 0) - { - for EachNonZeroEnumVal(RD_ThemeColor, color) - { - String8 kind_string = str8_lit("Theme Color"); - String8 string = rd_theme_color_display_string_table[color]; - FuzzyMatchRangeList kind_string_matches = fuzzy_match_find(scratch.arena, query, kind_string); - FuzzyMatchRangeList string_matches = fuzzy_match_find(scratch.arena, query, string); - if(string_matches.count == string_matches.needle_part_count || - kind_string_matches.count == kind_string_matches.needle_part_count) - { - RD_SettingsItemNode *n = push_array(scratch.arena, RD_SettingsItemNode, 1); - SLLQueuePush(items_list.first, items_list.last, n); - items_list.count += 1; - n->v.kind = RD_SettingsItemKind_ThemeColor; - n->v.kind_string = kind_string; - n->v.string = string; - n->v.kind_string_matches = kind_string_matches; - n->v.string_matches = string_matches; - n->v.icon_kind = RD_IconKind_Palette; - n->v.color = color; - } - } - } - - //- rjf: convert to array - items.count = items_list.count; - items.v = push_array(scratch.arena, RD_SettingsItem, items.count); - { - U64 idx = 0; - for(RD_SettingsItemNode *n = items_list.first; n != 0; n = n->next, idx += 1) - { - items.v[idx] = n->v; - } - } - } - - ////////////////////////////// - //- rjf: sort filtered settings item list - // - if(query.size != 0) - { - quick_sort(items.v, items.count, sizeof(items.v[0]), rd_qsort_compare_settings_item); - } - - ////////////////////////////// - //- rjf: produce per-color context menu keys - // - UI_Key *color_ctx_menu_keys = push_array(scratch.arena, UI_Key, RD_ThemeColor_COUNT); - { - for(RD_ThemeColor color = (RD_ThemeColor)(RD_ThemeColor_Null+1); - color < RD_ThemeColor_COUNT; - color = (RD_ThemeColor)(color+1)) - { - color_ctx_menu_keys[color] = ui_key_from_stringf(ui_key_zero(), "###settings_color_ctx_menu_%I64x", (U64)color); - } - } - - ////////////////////////////// - //- rjf: build color context menus - // - for(RD_ThemeColor color = (RD_ThemeColor)(RD_ThemeColor_Null+1); - color < RD_ThemeColor_COUNT; - color = (RD_ThemeColor)(color+1)) - { - RD_Palette(RD_PaletteCode_Floating) - UI_CtxMenu(color_ctx_menu_keys[color]) - UI_Padding(ui_em(1.5f, 1.f)) - UI_PrefWidth(ui_em(28.5f, 1)) UI_PrefHeight(ui_children_sum(1.f)) - { - // rjf: build title - UI_Row - { - ui_spacer(ui_em(1.5f, 1.f)); - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) ui_label(rd_theme_color_display_string_table[color]); - } - - ui_spacer(ui_em(1.5f, 1.f)); - - // rjf: build picker - { - ui_set_next_pref_height(ui_em(22.f, 1.f)); - UI_Row UI_Padding(ui_pct(1, 0)) - { - UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) - { - ui_sat_val_pickerf(sv->color_ctx_menu_color_hsva.x, &sv->color_ctx_menu_color_hsva.y, &sv->color_ctx_menu_color_hsva.z, "###settings_satval_picker"); - } - - ui_spacer(ui_em(0.75f, 1.f)); - - UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) - ui_hue_pickerf(&sv->color_ctx_menu_color_hsva.x, sv->color_ctx_menu_color_hsva.y, sv->color_ctx_menu_color_hsva.z, "###settings_hue_picker"); - - UI_PrefWidth(ui_em(1.5f, 1.f)) UI_PrefHeight(ui_em(22.f, 1.f)) UI_Flags(UI_BoxFlag_FocusNavSkip) - ui_alpha_pickerf(&sv->color_ctx_menu_color_hsva.w, "###settings_alpha_picker"); - } - } - - ui_spacer(ui_em(1.5f, 1.f)); - - // rjf: build line edits - UI_Row - UI_WidthFill - UI_Padding(ui_em(1.5f, 1.f)) - UI_PrefHeight(ui_children_sum(1.f)) - UI_Column - UI_PrefHeight(ui_em(2.25f, 1.f)) - { - Vec4F32 hsva = sv->color_ctx_menu_color_hsva; - Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); - Vec3F32 rgb = rgb_from_hsv(hsv); - Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, sv->color_ctx_menu_color_hsva.w); - String8 hex_string = hex_string_from_rgba_4f32(scratch.arena, rgba); - hex_string = push_str8f(scratch.arena, "#%S", hex_string); - String8 r_string = push_str8f(scratch.arena, "%.2f", rgba.x); - String8 g_string = push_str8f(scratch.arena, "%.2f", rgba.y); - String8 b_string = push_str8f(scratch.arena, "%.2f", rgba.z); - String8 h_string = push_str8f(scratch.arena, "%.2f", hsva.x); - String8 s_string = push_str8f(scratch.arena, "%.2f", hsva.y); - String8 v_string = push_str8f(scratch.arena, "%.2f", hsva.z); - String8 a_string = push_str8f(scratch.arena, "%.2f", rgba.w); - UI_Row RD_Font(RD_FontSlot_Code) - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("Hex"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, hex_string, "###hex_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_rgba = rgba_from_hex_string_4f32(string); - Vec4F32 new_hsva = hsva_from_rgba(new_rgba); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - ui_spacer(ui_em(0.75f, 1.f)); - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("R"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, r_string, "###r_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_rgba = v4f32((F32)f64_from_str8(string), rgba.y, rgba.z, rgba.w); - Vec4F32 new_hsva = hsva_from_rgba(new_rgba); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("G"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, g_string, "###g_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_rgba = v4f32(rgba.x, (F32)f64_from_str8(string), rgba.z, rgba.w); - Vec4F32 new_hsva = hsva_from_rgba(new_rgba); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("B"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, b_string, "###b_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_rgba = v4f32(rgba.x, rgba.y, (F32)f64_from_str8(string), rgba.w); - Vec4F32 new_hsva = hsva_from_rgba(new_rgba); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - ui_spacer(ui_em(0.75f, 1.f)); - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("H"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, h_string, "###h_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_hsva = v4f32((F32)f64_from_str8(string), hsva.y, hsva.z, hsva.w); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("S"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, s_string, "###s_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_hsva = v4f32(hsva.x, (F32)f64_from_str8(string), hsva.z, hsva.w); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("V"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, v_string, "###v_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_hsva = v4f32(hsva.x, hsva.y, (F32)f64_from_str8(string), hsva.w); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - ui_spacer(ui_em(0.75f, 1.f)); - UI_Row - { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("A"); - UI_Signal sig = rd_line_editf(RD_LineEditFlag_Border, 0, 0, &sv->txt_cursor, &sv->txt_mark, sv->txt_buffer, sizeof(sv->txt_buffer), &sv->txt_size, 0, a_string, "###a_edit"); - if(ui_committed(sig)) - { - String8 string = str8(sv->txt_buffer, sv->txt_size); - Vec4F32 new_hsva = v4f32(hsva.x, hsva.y, hsva.z, (F32)f64_from_str8(string)); - sv->color_ctx_menu_color_hsva = new_hsva; - } - } - } - - // rjf: commit state to theme - Vec4F32 hsva = sv->color_ctx_menu_color_hsva; - Vec3F32 hsv = v3f32(hsva.x, hsva.y, hsva.z); - Vec3F32 rgb = rgb_from_hsv(hsv); - Vec4F32 rgba = v4f32(rgb.x, rgb.y, rgb.z, sv->color_ctx_menu_color_hsva.w); - rd_state->cfg_theme_target.colors[sv->color_ctx_menu_color] = rgba; - } - } - - ////////////////////////////// - //- rjf: cancels - // - UI_Focus(UI_FocusKind_On) if(ui_is_focus_active() && sv->preset_apply_confirm < RD_ThemePreset_COUNT && ui_slot_press(UI_EventActionSlot_Cancel)) - { - sv->preset_apply_confirm = RD_ThemePreset_COUNT; - } - - ////////////////////////////// - //- rjf: build items list - // - Rng1S64 visible_row_range = {0}; - UI_ScrollListParams scroll_list_params = {0}; - { - Vec2F32 rect_dim = dim_2f32(rect); - scroll_list_params.flags = UI_ScrollListFlag_All; - scroll_list_params.row_height_px = row_height_px; - scroll_list_params.dim_px = v2f32(rect_dim.x, rect_dim.y); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(0, items.count)); - scroll_list_params.item_range = r1s64(0, items.count); - scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; - } - UI_ScrollListSignal scroll_list_sig = {0}; - UI_Focus(UI_FocusKind_On) - UI_ScrollList(&scroll_list_params, &scroll_pos.y, &sv->cursor, 0, &visible_row_range, &scroll_list_sig) - UI_Focus(UI_FocusKind_Null) - { - for(S64 row_num = visible_row_range.min; row_num <= visible_row_range.max && row_num < items.count; row_num += 1) - { - //- rjf: unpack item - RD_SettingsItem *item = &items.v[row_num]; - UI_Palette *palette = ui_top_palette(); - Vec4F32 rgba = ui_top_palette()->text_weak; - OS_Cursor cursor = OS_Cursor_HandPoint; - Rng1S32 s32_range = {0}; - B32 is_toggler = 0; - B32 is_toggled = 0; - B32 is_slider = 0; - S32 slider_s32_val = 0; - F32 slider_pct = 0.f; - UI_BoxFlags flags = UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawActiveEffects; - RD_SettingVal *val_table = &rd_state->cfg_setting_vals[RD_CfgSrc_User][0]; - switch(item->kind) - { - case RD_SettingsItemKind_COUNT:{}break; - case RD_SettingsItemKind_CategoryHeader: - { - cursor = OS_Cursor_HandPoint; - flags = UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawHotEffects; - }break; - case RD_SettingsItemKind_ThemePreset: - { - Vec4F32 *colors = rd_theme_preset_colors_table[item->preset]; - Vec4F32 bg_color = colors[RD_ThemeColor_BaseBackground]; - Vec4F32 tx_color = colors[RD_ThemeColor_Text]; - Vec4F32 tw_color = colors[RD_ThemeColor_TextWeak]; - Vec4F32 bd_color = colors[RD_ThemeColor_BaseBorder]; - palette = ui_build_palette(ui_top_palette(), - .text = tx_color, - .text_weak = tw_color, - .border = bd_color, - .background = bg_color); - }break; - case RD_SettingsItemKind_ThemeColor: - { - rgba = rd_rgba_from_theme_color(item->color); - }break; - case RD_SettingsItemKind_WindowSetting: {val_table = &window->setting_vals[0];}goto setting; - case RD_SettingsItemKind_GlobalSetting:{}goto setting; - setting:; - { - s32_range = rd_setting_code_s32_range_table[item->code]; - if(s32_range.min != 0 || s32_range.max != 1) - { - cursor = OS_Cursor_LeftRight; - is_slider = 1; - slider_s32_val = val_table[item->code].s32; - slider_pct = (F32)(slider_s32_val - s32_range.min) / dim_1s32(s32_range); - } - else - { - is_toggler = 1; - is_toggled = !!val_table[item->code].s32; - } - }break; - } - - //- rjf: build item widget - UI_Box *item_box = &ui_nil_box; - UI_Row - { - if(query.size == 0 && item->kind != RD_SettingsItemKind_CategoryHeader) - { - ui_set_next_flags(UI_BoxFlag_DrawSideLeft); - ui_spacer(ui_em(2.f, 1.f)); - } - UI_Focus(row_num+1 == sv->cursor.y ? UI_FocusKind_On : UI_FocusKind_Off) UI_Palette(palette) - { - ui_set_next_hover_cursor(cursor); - item_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|flags, "###option_%S_%S", item->kind_string, item->string); - UI_Parent(item_box) - { - if(item->icon_kind != RD_IconKind_Null) - { - UI_PrefWidth(ui_em(3.f, 1.f)) - RD_Font(RD_FontSlot_Icons) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rgba)) - UI_TextAlignment(UI_TextAlign_Center) - ui_label(rd_icon_kind_text_table[item->icon_kind]); - } - if(query.size != 0 && item->kind_string.size != 0) UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DrawTextWeak, "%S", item->kind_string); - ui_box_equip_fuzzy_match_ranges(box, &item->kind_string_matches); - } - UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S", item->string); - ui_box_equip_fuzzy_match_ranges(box, &item->string_matches); - } - if(is_slider) UI_PrefWidth(ui_text_dim(10, 1)) - { - UI_Flags(UI_BoxFlag_DrawTextWeak) - ui_labelf("(%i)", slider_s32_val); - UI_PrefWidth(ui_pct(slider_pct, 1.f)) UI_HeightFill UI_FixedX(0) UI_FixedY(0) - UI_Palette(ui_build_palette(ui_top_palette(), .background = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay))) - ui_build_box_from_key(UI_BoxFlag_DrawBackground, ui_key_zero()); - } - if(is_toggler) - { - ui_spacer(ui_pct(1, 0)); - UI_PrefWidth(ui_em(2.5f, 1.f)) - RD_Font(RD_FontSlot_Icons) - UI_Flags(UI_BoxFlag_DrawTextWeak) - ui_label(rd_icon_kind_text_table[is_toggled ? RD_IconKind_CheckFilled : RD_IconKind_CheckHollow]); - } - if(item->kind == RD_SettingsItemKind_ThemePreset && sv->preset_apply_confirm == item->preset) - { - ui_spacer(ui_pct(1, 0)); - UI_PrefWidth(ui_text_dim(10, 1)) - RD_Palette(RD_PaletteCode_NegativePopButton) - UI_CornerRadius(ui_top_font_size()*0.5f) - UI_FontSize(ui_top_font_size()*0.9f) - UI_TextAlignment(UI_TextAlign_Center) - ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DrawBackground, "Click Again To Apply"); - } - } - } - } - - //- rjf: interact - UI_Signal sig = ui_signal_from_box(item_box); - if(item->kind == RD_SettingsItemKind_ThemeColor && ui_pressed(sig)) - { - Vec3F32 rgb = v3f32(rgba.x, rgba.y, rgba.z); - Vec3F32 hsv = hsv_from_rgb(rgb); - Vec4F32 hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); - if(ui_ctx_menu_is_open(color_ctx_menu_keys[item->color])) - { - ui_ctx_menu_close(); - } - else - { - ui_ctx_menu_open(color_ctx_menu_keys[item->color], item_box->key, v2f32(0, dim_2f32(item_box->rect).y)); - } - sv->color_ctx_menu_color = item->color; - sv->color_ctx_menu_color_hsva = v4f32(hsv.x, hsv.y, hsv.z, rgba.w); - rd_cmd(RD_CmdKind_FocusPanel); - } - if((item->kind == RD_SettingsItemKind_GlobalSetting || item->kind == RD_SettingsItemKind_WindowSetting) && - is_toggler && ui_clicked(sig)) - { - val_table[item->code].s32 ^= 1; - val_table[item->code].set = 1; - } - if((item->kind == RD_SettingsItemKind_GlobalSetting || item->kind == RD_SettingsItemKind_WindowSetting) && - is_slider && ui_dragging(sig)) - { - if(ui_pressed(sig)) - { - ui_store_drag_struct(&slider_s32_val); - } - S32 pre_drag_val = *ui_get_drag_struct(S32); - Vec2F32 delta = ui_drag_delta(); - S32 pst_drag_val = pre_drag_val + (S32)(delta.x/(ui_top_font_size()*2.f)); - pst_drag_val = clamp_1s32(s32_range, pst_drag_val); - val_table[item->code].s32 = pst_drag_val; - val_table[item->code].set = 1; - } - if(item->kind == RD_SettingsItemKind_ThemePreset && ui_clicked(sig)) - { - if(sv->preset_apply_confirm == item->preset) - { - Vec4F32 *colors = rd_theme_preset_colors_table[item->preset]; - MemoryCopy(rd_state->cfg_theme_target.colors, colors, sizeof(rd_state->cfg_theme_target.colors)); - sv->preset_apply_confirm = RD_ThemePreset_COUNT; - } - else - { - sv->preset_apply_confirm = item->preset; - } - } - if(item->kind != RD_SettingsItemKind_ThemePreset && ui_pressed(sig)) - { - sv->preset_apply_confirm = RD_ThemePreset_COUNT; - } - if(item->kind != RD_SettingsItemKind_ThemePreset && ui_pressed(sig)) - { - sv->preset_apply_confirm = RD_ThemePreset_COUNT; - } - if(item->kind == RD_SettingsItemKind_CategoryHeader && ui_pressed(sig)) - { - sv->category_opened[item->category] ^= 1; - } - } - } - - rd_store_view_scroll_pos(scroll_pos); - scratch_end(scratch); - ProfEnd(); -} diff --git a/src/raddbg/raddbg_views.h b/src/raddbg/raddbg_views.h index 0b3122fc..5f8d0869 100644 --- a/src/raddbg/raddbg_views.h +++ b/src/raddbg/raddbg_views.h @@ -10,8 +10,8 @@ typedef U32 RD_CodeViewBuildFlags; enum { - RD_CodeViewBuildFlag_Margins = (1<<0), - RD_CodeViewBuildFlag_All = 0xffffffff, + RD_CodeViewBuildFlag_Margins = (1<<0), + RD_CodeViewBuildFlag_All = 0xffffffff, }; typedef struct RD_CodeViewState RD_CodeViewState; @@ -21,11 +21,13 @@ struct RD_CodeViewState B32 initialized; S64 preferred_column; B32 drifted_for_search; + U128 last_hash; // rjf: per-frame command info S64 goto_line_num; B32 center_cursor; B32 contain_cursor; + B32 force_contain_only; B32 watch_expr_at_mouse; Arena *find_text_arena; String8 find_text_fwd; @@ -41,100 +43,97 @@ struct RD_CodeViewBuildResult //////////////////////////////// //~ rjf: Watch View Types -typedef U32 RD_WatchViewFlags; +typedef enum RD_WatchCellKind +{ + RD_WatchCellKind_Eval, // an evaluation cell + RD_WatchCellKind_ViewUI, // an arbitrary user interface, supplied by a hook + RD_WatchCellKind_CallStackFrame, // a slot for a yellow arrow, to show call stack frame selection +} +RD_WatchCellKind; + +typedef U32 RD_WatchCellFlags; enum { - RD_WatchViewFlag_NoHeader = (1<<0), - RD_WatchViewFlag_PrettyNameMembers = (1<<1), - RD_WatchViewFlag_PrettyEntityRows = (1<<2), - RD_WatchViewFlag_DisableCacheLines = (1<<3), + RD_WatchCellFlag_Expr = (1<<0), + RD_WatchCellFlag_NoEval = (1<<1), + RD_WatchCellFlag_Button = (1<<2), + RD_WatchCellFlag_Background = (1<<3), + RD_WatchCellFlag_ActivateWithSingleClick = (1<<4), + RD_WatchCellFlag_IsNonCode = (1<<5), + RD_WatchCellFlag_CanEdit = (1<<6), + RD_WatchCellFlag_IsErrored = (1<<7), + RD_WatchCellFlag_Indented = (1<<8), }; -typedef enum RD_WatchViewColumnKind +typedef struct RD_WatchCell RD_WatchCell; +struct RD_WatchCell { - RD_WatchViewColumnKind_Expr, - RD_WatchViewColumnKind_Value, - RD_WatchViewColumnKind_Type, - RD_WatchViewColumnKind_ViewRule, - RD_WatchViewColumnKind_Member, - RD_WatchViewColumnKind_CallStackFrame, - RD_WatchViewColumnKind_CallStackFrameSelection, - RD_WatchViewColumnKind_Module, - RD_WatchViewColumnKind_COUNT -} -RD_WatchViewColumnKind; - -typedef struct RD_WatchViewColumnParams RD_WatchViewColumnParams; -struct RD_WatchViewColumnParams -{ - String8 string; - String8 display_string; - String8 view_rule; - B32 is_non_code; - B32 dequote_string; - B32 rangify_braces; -}; - -typedef struct RD_WatchViewColumn RD_WatchViewColumn; -struct RD_WatchViewColumn -{ - RD_WatchViewColumn *next; - RD_WatchViewColumn *prev; - RD_WatchViewColumnKind kind; + RD_WatchCell *next; + RD_WatchCellKind kind; + RD_WatchCellFlags flags; + U64 index; + E_Eval eval; + F32 default_pct; F32 pct; - U8 string_buffer[1024]; - U64 string_size; - U8 display_string_buffer[1024]; - U64 display_string_size; - U8 view_rule_buffer[1024]; - U64 view_rule_size; - B32 is_non_code; - B32 dequote_string; - B32 rangify_braces; + F32 px; }; -typedef struct RD_WatchViewRowCtrl RD_WatchViewRowCtrl; -struct RD_WatchViewRowCtrl +typedef struct RD_WatchCellList RD_WatchCellList; +struct RD_WatchCellList { - RD_EntityKind entity_kind; - CTRL_EntityKind ctrl_entity_kind; - RD_CmdKind kind; + RD_WatchCell *first; + RD_WatchCell *last; + U64 count; }; -typedef enum RD_WatchViewRowKind +typedef struct RD_WatchRowInfo RD_WatchRowInfo; +struct RD_WatchRowInfo { - RD_WatchViewRowKind_Normal, - RD_WatchViewRowKind_Header, - RD_WatchViewRowKind_Canvas, - RD_WatchViewRowKind_PrettyEntityControls, -} -RD_WatchViewRowKind; - -typedef struct RD_WatchViewPoint RD_WatchViewPoint; -struct RD_WatchViewPoint -{ - S64 x; - EV_Key parent_key; - EV_Key key; -}; - -typedef struct RD_WatchViewRowInfo RD_WatchViewRowInfo; -struct RD_WatchViewRowInfo -{ - RD_EntityKind collection_entity_kind; - RD_Entity *collection_entity; - CTRL_EntityKind collection_ctrl_entity_kind; - CTRL_Entity *collection_ctrl_entity; + CTRL_Entity *module; + B32 can_expand; + B32 expr_is_editable; + String8 group_cfg_name; + RD_Cfg *group_cfg_parent; + RD_Cfg *group_cfg_child; + CTRL_Entity *group_entity; CTRL_Entity *callstack_thread; U64 callstack_unwind_index; U64 callstack_inline_depth; + U64 callstack_vaddr; + String8 cell_style_key; + RD_WatchCellList cells; + RD_ViewUIRule *view_ui_rule; +}; + +typedef struct RD_WatchRowCellInfo RD_WatchRowCellInfo; +struct RD_WatchRowCellInfo +{ + RD_WatchCellFlags flags; + RD_Cfg *cfg; + CTRL_Entity *entity; + String8 cmd_name; + String8 file_path; + DR_FStrList expr_fstrs; + DR_FStrList eval_fstrs; + String8 description; + String8 error_tooltip; + String8 inheritance_tooltip; + RD_ViewUIRule *view_ui_rule; +}; + +typedef struct RD_WatchPt RD_WatchPt; +struct RD_WatchPt +{ + EV_Key parent_key; + EV_Key key; + U64 cell_id; }; typedef struct RD_WatchViewTextEditState RD_WatchViewTextEditState; struct RD_WatchViewTextEditState { RD_WatchViewTextEditState *pt_hash_next; - RD_WatchViewPoint pt; + RD_WatchPt pt; TxtPt cursor; TxtPt mark; U8 input_buffer[1024]; @@ -148,18 +147,15 @@ struct RD_WatchViewState { B32 initialized; - // rjf: column state - Arena *column_arena; - RD_WatchViewColumn *first_column; - RD_WatchViewColumn *last_column; - RD_WatchViewColumn *free_column; - U64 column_count; + // rjf: filter history + Arena *filter_arena; + String8 last_filter; // rjf; table cursor state - RD_WatchViewPoint cursor; - RD_WatchViewPoint mark; - RD_WatchViewPoint next_cursor; - RD_WatchViewPoint next_mark; + RD_WatchPt cursor; + RD_WatchPt mark; + RD_WatchPt next_cursor; + RD_WatchPt next_mark; // rjf: text input state Arena *text_edit_arena; @@ -178,34 +174,45 @@ internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewStat //////////////////////////////// //~ rjf: Watch View Functions -//- rjf: index -> column -internal RD_WatchViewColumn *rd_watch_view_column_from_x(RD_WatchViewState *wv, S64 index); +//- rjf: cell list building +internal U64 rd_id_from_watch_cell(RD_WatchCell *cell); +internal RD_WatchCell *rd_watch_cell_list_push(Arena *arena, RD_WatchCellList *list); +internal RD_WatchCell *rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell *params); +#define rd_watch_cell_list_push_new(arena, list, kind_, eval_, ...) rd_watch_cell_list_push_new_((arena), (list), &(RD_WatchCell){.kind = (kind_), .eval = (eval_), __VA_ARGS__}) //- rjf: watch view points <-> table coordinates -internal B32 rd_watch_view_point_match(RD_WatchViewPoint a, RD_WatchViewPoint b); -internal RD_WatchViewPoint rd_watch_view_point_from_tbl(EV_BlockRangeList *block_ranges, Vec2S64 tbl); -internal Vec2S64 rd_tbl_from_watch_view_point(EV_BlockRangeList *block_ranges, RD_WatchViewPoint pt); +internal B32 rd_watch_pt_match(RD_WatchPt a, RD_WatchPt b); +internal RD_WatchPt rd_watch_pt_from_tbl(EV_BlockRangeList *block_ranges, Vec2S64 tbl); +internal Vec2S64 rd_tbl_from_watch_pt(EV_BlockRangeList *block_ranges, RD_WatchPt pt); -//- rjf: row -> context info -internal RD_WatchViewRowInfo rd_watch_view_row_info_from_row(EV_Row *row); +//- rjf: row -> info +internal RD_WatchRowInfo rd_watch_row_info_from_row(Arena *arena, EV_Row *row); -//- rjf: watch view flags & row & row info -> row kind -internal RD_WatchViewRowKind rd_watch_view_row_kind_from_flags_row_info(RD_WatchViewFlags flags, EV_Row *row, RD_WatchViewRowInfo *info); - -//- rjf: row/column -> exprs / strings -internal E_Expr *rd_expr_from_watch_view_row_column(Arena *arena, EV_View *ev_view, EV_Row *row, RD_WatchViewColumn *col); -internal String8 rd_string_from_eval_viz_row_column(Arena *arena, EV_View *ev, EV_Row *row, RD_WatchViewColumn *col, EV_StringFlags string_flags, U32 default_radix, FNT_Tag font, F32 font_size, F32 max_size_px); +//- rjf: row * cell -> info +internal RD_WatchRowCellInfo rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_flags, RD_WatchRowInfo *row_info, RD_WatchCell *cell, FNT_Tag font, F32 font_size, F32 max_size_px); //- rjf: table coordinates -> text edit state -internal RD_WatchViewTextEditState *rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchViewPoint pt); +internal RD_WatchViewTextEditState *rd_watch_view_text_edit_state_from_pt(RD_WatchViewState *wv, RD_WatchPt pt); -//- rjf: watch view column state mutation -internal RD_WatchViewColumn *rd_watch_view_column_alloc_(RD_WatchViewState *wv, RD_WatchViewColumnKind kind, F32 pct, RD_WatchViewColumnParams *params); -#define rd_watch_view_column_alloc(wv, kind, pct, ...) rd_watch_view_column_alloc_((wv), (kind), (pct), &(RD_WatchViewColumnParams){.string = str8_zero(), __VA_ARGS__}) -internal void rd_watch_view_column_release(RD_WatchViewState *wv, RD_WatchViewColumn *col); +//////////////////////////////// +//~ rjf: View Hooks -//- rjf: watch view main hooks -internal void rd_watch_view_init(RD_WatchViewState *ewv); -internal void rd_watch_view_build(RD_WatchViewState *ewv, RD_WatchViewFlags flags, String8 root_expr, String8 root_view_rule, B32 modifiable, U32 default_radix, Rng2F32 rect); +// TODO(rjf): eliminate once we are predeclaring these with metacode + +RD_VIEW_UI_FUNCTION_DEF(null); + +EV_EXPAND_RULE_INFO_FUNCTION_DEF(text); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(disasm); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(memory); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(bitmap); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(color); +EV_EXPAND_RULE_INFO_FUNCTION_DEF(geo3d); + +RD_VIEW_UI_FUNCTION_DEF(text); +RD_VIEW_UI_FUNCTION_DEF(disasm); +RD_VIEW_UI_FUNCTION_DEF(memory); +RD_VIEW_UI_FUNCTION_DEF(bitmap); +RD_VIEW_UI_FUNCTION_DEF(color); +RD_VIEW_UI_FUNCTION_DEF(geo3d); #endif // RADDBG_VIEWS_H diff --git a/src/raddbg/raddbg_widgets.c b/src/raddbg/raddbg_widgets.c index 0e2c3355..40eaa452 100644 --- a/src/raddbg/raddbg_widgets.c +++ b/src/raddbg/raddbg_widgets.c @@ -1,13 +1,677 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Title Strings + +internal DR_FStrList +rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg) +{ + DR_FStrList result = {0}; + { + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: unpack config + B32 is_disabled = rd_disabled_from_cfg(cfg); + RD_Location loc = rd_location_from_cfg(cfg); + D_Target target = rd_target_from_cfg(scratch.arena, cfg); + String8 label_string = rd_label_from_cfg(cfg); + String8 expr_string = rd_expr_from_cfg(cfg); + String8 collection_name = {0}; + String8 file_path = rd_path_from_cfg(cfg); + Vec4F32 rgba = rd_color_from_cfg(cfg); + if(rgba.w == 0) + { + rgba = ui_color_from_name(str8_lit("text")); + } + Vec4F32 rgba_secondary = rgba; + UI_TagF("weak") + { + rgba_secondary = ui_color_from_name(str8_lit("text")); + } + RD_IconKind icon_kind = rd_icon_kind_from_code_name(cfg->string); + B32 is_from_command_line = 0; + { + RD_Cfg *cmd_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line")); + for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + { + if(p == cmd_line_root) + { + is_from_command_line = 1; + break; + } + } + } + B32 is_within_window = 0; + { + for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent) + { + if(str8_match(p->string, str8_lit("window"), 0)) + { + is_within_window = 1; + break; + } + } + } + if(expr_string.size != 0) + { + String8 query_name = rd_query_from_eval_string(arena, expr_string); + if(query_name.size != 0) + { + String8 query_code_name = query_name; + String8 query_display_name = rd_display_from_code_name(query_code_name); + collection_name = query_display_name; + if(query_display_name.size == 0) + { + query_code_name = rd_singular_from_code_name_plural(query_name); + collection_name = rd_display_plural_from_code_name(query_code_name); + } + RD_IconKind query_icon_kind = rd_icon_kind_from_code_name(query_code_name); + if(query_icon_kind != RD_IconKind_Null) + { + icon_kind = query_icon_kind; + } + } + else + { + file_path = rd_file_path_from_eval_string(arena, expr_string); + if(file_path.size != 0) + { + icon_kind = RD_IconKind_FileOutline; + } + } + } + + //- rjf: set up color/size for all parts of the title + // + // the "running" part implies that it changes as things are added - + // so if a primary title is pushed, we can make the rest of the title + // more faded/smaller, but only after a primary title is pushed, + // which could be caused by many different potential parts of a cfg. + // + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), rgba, ui_top_font_size()}; + B32 running_is_secondary = 0; +#define start_secondary() if(!running_is_secondary){running_is_secondary = 1; params.color = rgba_secondary; params.size = ui_top_font_size()*0.95f;} + + //- rjf: disabled? -> soften color + if(is_disabled) + { + params.color = rgba_secondary; + } + + //- rjf: [breakpoints] push hit marker + if(str8_match(cfg->string, str8_lit("breakpoint"), 0)) + { + CTRL_Event stop_event = d_ctrl_last_stop_event(); + if(stop_event.cause == CTRL_EventCause_UserBreakpoint) + { + RD_Cfg *bp = rd_cfg_from_id(stop_event.u64_code); + if(bp == cfg) + { + CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, stop_event.entity); + Vec4F32 thread_color = rd_color_from_ctrl_entity(thread); + if(thread_color.w == 0) + { + thread_color = rgba_secondary; + } + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = thread_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + } + } + + //- rjf: push icon + if(icon_kind != RD_IconKind_Null) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push warning icon for command-line entities + if(is_from_command_line) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Info], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push view title, if from window, and no file path, and no label + if(is_within_window && file_path.size == 0 && collection_name.size == 0 && label_string.size == 0) + { + String8 view_display_name = rd_display_from_code_name(cfg->string); + if(view_display_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, view_display_name); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + } + + //- rjf: push bucket name + if(cfg->parent == rd_state->root_cfg) + { + if(str8_match(cfg->string, str8_lit("user"), 0)) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("User"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + else if(str8_match(cfg->string, str8_lit("project"), 0)) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("Project"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + } + + //- rjf: push label + if(label_string.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, label_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push collection name + if(collection_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, collection_name); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: query is file path - do specific file name strings + else if(file_path.size != 0) + { + // rjf: compute disambiguated file name + String8List qualifiers = {0}; + String8 file_name = str8_skip_last_slash(file_path); + if(rd_state->ambiguous_path_slots_count != 0) + { + U64 hash = d_hash_from_string__case_insensitive(file_name); + U64 slot_idx = hash%rd_state->ambiguous_path_slots_count; + RD_AmbiguousPathNode *node = 0; + { + for(RD_AmbiguousPathNode *n = rd_state->ambiguous_path_slots[slot_idx]; + n != 0; + n = n->next) + { + if(str8_match(n->name, file_name, StringMatchFlag_CaseInsensitive)) + { + node = n; + break; + } + } + } + if(node != 0 && node->paths.node_count > 1) + { + // rjf: get all colliding paths + String8Array collisions = str8_array_from_list(scratch.arena, &node->paths); + + // rjf: get all reversed path parts for each collision + String8List *collision_parts_reversed = push_array(scratch.arena, String8List, collisions.count); + for EachIndex(idx, collisions.count) + { + String8List parts = str8_split_path(scratch.arena, collisions.v[idx]); + for(String8Node *n = parts.first; n != 0; n = n->next) + { + str8_list_push_front(scratch.arena, &collision_parts_reversed[idx], n->string); + } + } + + // rjf: get the search path & its reversed parts + String8List parts = str8_split_path(scratch.arena, file_path); + String8List parts_reversed = {0}; + for(String8Node *n = parts.first; n != 0; n = n->next) + { + str8_list_push_front(scratch.arena, &parts_reversed, n->string); + } + + // rjf: iterate all collision part reversed lists, in lock-step with + // search path; disqualify until we only have one path remaining; gather + // qualifiers + { + U64 num_collisions_left = collisions.count; + String8Node **collision_nodes = push_array(scratch.arena, String8Node *, collisions.count); + for EachIndex(idx, collisions.count) + { + collision_nodes[idx] = collision_parts_reversed[idx].first; + } + for(String8Node *n = parts_reversed.first; num_collisions_left > 1 && n != 0; n = n->next) + { + B32 part_is_qualifier = 0; + for EachIndex(idx, collisions.count) + { + if(collision_nodes[idx] != 0 && !str8_match(collision_nodes[idx]->string, n->string, StringMatchFlag_CaseInsensitive)) + { + collision_nodes[idx] = 0; + num_collisions_left -= 1; + part_is_qualifier = 1; + } + else if(collision_nodes[idx] != 0) + { + collision_nodes[idx] = collision_nodes[idx]->next; + } + } + if(part_is_qualifier) + { + str8_list_push_front(scratch.arena, &qualifiers, n->string); + } + } + } + } + } + + // rjf: push qualifiers + if(qualifiers.node_count != 0) UI_TagF("weak") + { + for(String8Node *n = qualifiers.first; n != 0; n = n->next) + { + String8 string = push_str8f(arena, "<%S> ", n->string); + dr_fstrs_push_new(arena, &result, ¶ms, string, .color = ui_color_from_name(str8_lit("text"))); + } + } + + // rjf: push file name + dr_fstrs_push_new(arena, &result, ¶ms, push_str8_copy(arena, str8_skip_last_slash(file_path))); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: cfg has expression attached -> use that + else if(expr_string.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, expr_string, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push text location + if(loc.file_path.size != 0) + { + String8 location_string = push_str8f(arena, "%S:%I64d:%I64d", str8_skip_last_slash(loc.file_path), loc.pt.line, loc.pt.column); + dr_fstrs_push_new(arena, &result, ¶ms, location_string); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push address location + if(loc.expr.size != 0) + { + RD_Font(RD_FontSlot_Code) + { + DR_FStrList fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, params.color, loc.expr); + dr_fstrs_concat_in_place(&result, &fstrs); + } + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push target executable name + if(target.exe.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_skip_last_slash(target.exe)); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + start_secondary(); + } + + //- rjf: push target arguments + if(target.args.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, target.args); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push conditions + { + String8 condition = rd_cfg_child_from_string(cfg, str8_lit("condition"))->first->string; + if(condition.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("if "), .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + RD_Font(RD_FontSlot_Code) + { + DR_FStrList fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, params.color, condition); + dr_fstrs_concat_in_place(&result, &fstrs); + } + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + } + + //- rjf: push disabled marker + if(is_disabled) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Disabled)")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push hit count + { + String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string; + U64 hit_count = 0; + if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count) && hit_count != 0) + { + String8 hit_count_text = push_str8f(arena, "(%I64u hit%s)", hit_count, hit_count == 1 ? "" : "s"); + dr_fstrs_push_new(arena, &result, ¶ms, hit_count_text); + } + } + + //- rjf: special case: type views + if(str8_match(cfg->string, str8_lit("type_view"), 0)) + { + String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("type"))->first->string; + String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("expr"))->first->string; + Vec4F32 src_color = rgba; + Vec4F32 dst_color = rgba; + DR_FStrList src_fstrs = {0}; + DR_FStrList dst_fstrs = {0}; + if(src_string.size == 0) + { + src_string = str8_lit("(type)"); + src_color = rgba_secondary; + dr_fstrs_push_new(arena, &src_fstrs, ¶ms, src_string, .color = src_color); + } + else RD_Font(RD_FontSlot_Code) + { + src_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, src_color, src_string); + } + if(dst_string.size == 0) + { + dst_string = str8_lit("(expression)"); + dst_color = rgba_secondary; + dr_fstrs_push_new(arena, &dst_fstrs, ¶ms, dst_string, .color = dst_color); + } + else RD_Font(RD_FontSlot_Code) + { + dst_fstrs = rd_fstrs_from_code_string(arena, 1.f, 0, dst_color, dst_string); + } + dr_fstrs_concat_in_place(&result, &src_fstrs); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_concat_in_place(&result, &dst_fstrs); + } + + //- rjf: special case: file path maps + if(str8_match(cfg->string, str8_lit("file_path_map"), 0)) + { + String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string; + String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string; + Vec4F32 src_color = rgba; + Vec4F32 dst_color = rgba; + if(src_string.size == 0) + { + src_string = str8_lit("(source path)"); + src_color = rgba_secondary; + } + if(dst_string.size == 0) + { + dst_string = str8_lit("(destination path)"); + dst_color = rgba_secondary; + } + dr_fstrs_push_new(arena, &result, ¶ms, src_string, .color = src_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = rgba_secondary); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, dst_string, .color = dst_color); + } + + //- rjf: special case: colors + if(str8_match(cfg->string, str8_lit("theme_color"), 0)) + { + String8 tags = rd_cfg_child_from_string(cfg, str8_lit("tags"))->first->string; + String8 color_string = rd_cfg_child_from_string(cfg, str8_lit("value"))->first->string; + U32 color_u32 = e_value_from_stringf("(uint32)(%S)", color_string).u32; + Vec4F32 color = linear_from_srgba(rgba_from_u32(color_u32)); + if(tags.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, tags); + } + else + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("Color"), .color = rgba_secondary); + } + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_CircleFilled], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = color); + } + +#undef start_secondary + scratch_end(scratch); + } + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras) +{ + DR_FStrList result = {0}; + + //- rjf: unpack entity info + F32 extras_size = ui_top_font_size()*0.95f; + Vec4F32 color = rd_color_from_ctrl_entity(entity); + if(color.w == 0) + { + color = ui_color_from_name(str8_lit("text")); + } + Vec4F32 secondary_color = color; + UI_TagF("weak") + { + secondary_color = ui_color_from_name(str8_lit("text")); + } + String8 name = rd_name_from_ctrl_entity(arena, entity); + RD_IconKind icon_kind = RD_IconKind_Null; + B32 name_is_code = 0; + switch(entity->kind) + { + default:{}break; + case CTRL_EntityKind_Machine: {icon_kind = RD_IconKind_Machine;}break; + case CTRL_EntityKind_Process: {icon_kind = RD_IconKind_Threads;}break; + case CTRL_EntityKind_Thread: {icon_kind = RD_IconKind_Thread; name_is_code = 1;}break; + case CTRL_EntityKind_Module: {icon_kind = RD_IconKind_Module;}break; + } + + //- rjf: set up drawing params + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Code), rd_raster_flags_from_slot(RD_FontSlot_Code), color, ui_top_font_size()}; + + //- rjf: push icon + if(icon_kind != RD_IconKind_Null) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = secondary_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push frozen icon, if frozen + if((entity->kind == CTRL_EntityKind_Machine || + entity->kind == CTRL_EntityKind_Process || + entity->kind == CTRL_EntityKind_Thread) && + ctrl_entity_tree_is_frozen(entity)) + UI_TagF("bad") + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_Locked], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_color_from_name(str8_lit("text"))); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push selected icon, if selected thread + if(entity->kind == CTRL_EntityKind_Thread) + { + B32 is_selected = ctrl_handle_match(entity->handle, rd_base_regs()->thread); + if(is_selected) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[RD_IconKind_RightArrow], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + } + + //- rjf: push containing process prefix + if(entity->kind == CTRL_EntityKind_Thread || + entity->kind == CTRL_EntityKind_Module) + { + CTRL_EntityArray processes = ctrl_entity_array_from_kind(&d_state->ctrl_entity_store->ctx, CTRL_EntityKind_Process); + if(processes.count > 1) + { + CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); + String8 process_name = rd_name_from_ctrl_entity(arena, process); + Vec4F32 process_color = rd_color_from_ctrl_entity(process); + if(process_color.w == 0) + { + process_color = ui_color_from_name(str8_lit("text")); + } + if(process_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, process_name, .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = process_color); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, "(PID: %I64u)", process->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.9f); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" / "), .color = secondary_color); + } + } + } + + //- rjf: push name + dr_fstrs_push_new(arena, &result, ¶ms, name, + .font = rd_font_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), + .raster_flags = rd_raster_flags_from_slot(name_is_code ? RD_FontSlot_Code : RD_FontSlot_Main), + .color = color); + + //- rjf: push PID + if(entity->kind == CTRL_EntityKind_Process) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, push_str8f(arena, " (PID: %I64u)", entity->id), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .color = secondary_color, .size = ui_top_font_size()*0.85f); + } + + //- rjf: threads get callstack extras + if(entity->kind == CTRL_EntityKind_Thread && include_extras) + { + Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + CTRL_Scope *ctrl_scope = ctrl_scope_open(); + DI_Scope *di_scope = di_scope_open(); + CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process); + Arch arch = entity->arch; + B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread); + CTRL_CallStack call_stack = ctrl_call_stack_from_thread(ctrl_scope, &d_state->ctrl_entity_store->ctx, entity, call_stack_high_priority, call_stack_high_priority ? rd_state->frame_eval_memread_endt_us : 0); + for(U64 idx = 0, limit = 6; idx < call_stack.frames_count && idx < limit; idx += 1) + { + CTRL_CallStackFrame *f = &call_stack.frames[call_stack.frames_count - 1 - idx]; + U64 rip_vaddr = regs_rip_from_arch_block(arch, f->regs); + CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr); + U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + if(rdi != &rdi_parsed_nil) + { + RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff); + String8 name = {0}; + name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &name.size); + name = push_str8_copy(arena, name); + if(name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, name, .size = extras_size, .color = symbol_color); + if(idx+1 < call_stack.frames_count) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" > "), .color = secondary_color, .size = extras_size); + if(idx+1 == limit) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("..."), .color = secondary_color, .size = extras_size); + } + } + } + } + } + di_scope_close(di_scope); + ctrl_scope_close(ctrl_scope); + } + + //- rjf: modules get debug info status extras + if(entity->kind == CTRL_EntityKind_Module && include_extras) + { + DI_Scope *di_scope = di_scope_open(); + DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity); + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 0); + if(rdi->raw_data_size == 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color); + } + di_scope_close(di_scope); + } + + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_code_name(Arena *arena, String8 code_name) +{ + DR_FStrList result = {0}; + { + RD_VocabInfo *info = rd_vocab_info_from_code_name(code_name); + + //- rjf: set up color/size for all parts of the title + // + // the "running" part implies that it changes as things are added - + // so if a primary title is pushed, we can make the rest of the title + // more faded/smaller, but only after a primary title is pushed, + // which could be caused by many different potential parts of a cfg. + // + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + + //- rjf: push icon + if(info->icon_kind != RD_IconKind_Null) UI_Tag(str8_lit("weak")) + { + dr_fstrs_push_new(arena, &result, ¶ms, rd_icon_kind_text_table[info->icon_kind], .font = rd_font_from_slot(RD_FontSlot_Icons), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), .color = ui_color_from_name(str8_lit("text"))); + dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" ")); + } + + //- rjf: push display name + if(info->display_name.size != 0) + { + dr_fstrs_push_new(arena, &result, ¶ms, info->display_name); + } + + //- rjf: push code name as a fallback + else + { + dr_fstrs_push_new(arena, &result, ¶ms, code_name, .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code)); + } + } + return result; +} + +internal DR_FStrList +rd_title_fstrs_from_file_path(Arena *arena, String8 file_path) +{ + DR_FStrList fstrs = {0}; + String8 file_name = str8_skip_last_slash(file_path); + FileProperties props = os_properties_from_file_path(file_path); + RD_IconKind icon_kind = RD_IconKind_FileOutline; + if(props.flags & FilePropertyFlag_IsFolder) + { + icon_kind = RD_IconKind_FolderClosedFilled; + } + if(file_path.size == 0 || str8_match(file_path, str8_lit("/"), StringMatchFlag_SlashInsensitive)) + { + icon_kind = RD_IconKind_Machine; + file_name = str8_lit("File System"); + } + DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + UI_TagF("weak") + { + dr_fstrs_push_new(arena, &fstrs, ¶ms, + rd_icon_kind_text_table[icon_kind], + .font = rd_font_from_slot(RD_FontSlot_Icons), + .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Icons), + .color = ui_color_from_name(str8_lit("text"))); + } + dr_fstrs_push_new(arena, &fstrs, ¶ms, str8_lit(" ")); + dr_fstrs_push_new(arena, &fstrs, ¶ms, file_name); + return fstrs; +} + //////////////////////////////// //~ rjf: UI Widgets: Loading Overlay internal void rd_loading_overlay(Rng2F32 rect, F32 loading_t, U64 progress_v, U64 progress_v_target) { - if(loading_t >= 0.001f) + if(loading_t >= 0.001f) UI_Focus(UI_FocusKind_Off) { // rjf: set up dimensions F32 edge_padding = 30.f; @@ -18,19 +682,8 @@ rd_loading_overlay(Rng2F32 rect, F32 loading_t, U64 progress_v, U64 progress_v_t F32 t = pow_f32(sin_f32((F32)rd_state->time_in_seconds / 1.8f), 2.f); F64 v = 1.f - abs_f32(0.5f - t); - // rjf: colors - Vec4F32 bg_color = rd_rgba_from_theme_color(RD_ThemeColor_BaseBackground); - Vec4F32 bd_color = rd_rgba_from_theme_color(RD_ThemeColor_FloatingBorder); - Vec4F32 hl_color = rd_rgba_from_theme_color(RD_ThemeColor_TextNeutral); - bg_color.w *= loading_t; - bd_color.w *= loading_t; - hl_color.w *= loading_t; - - // rjf: grab animation params - F32 bg_work_indicator_t = 1.f; - // rjf: build indicator - UI_CornerRadius(height/3.f) + UI_CornerRadius(height/3.f) UI_Transparency(1-loading_t) { // rjf: rects Rng2F32 indicator_region_rect = @@ -48,42 +701,35 @@ rd_loading_overlay(Rng2F32 rect, F32 loading_t, U64 progress_v, U64 progress_v_t indicator_rect = pad_2f32(indicator_rect, -1.f); // rjf: does the view have loading *progress* info? -> draw extra progress layer - if(progress_v != progress_v_target) + if(progress_v != progress_v_target) UI_TagF("drop_site") { F64 pct_done_f64 = ((F64)progress_v/(F64)progress_v_target); F32 pct_done = (F32)pct_done_f64; - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = v4f32(1, 1, 1, 0.2f*loading_t))); - ui_set_next_fixed_x(indicator_region_rect.x0); - ui_set_next_fixed_y(indicator_region_rect.y0); - ui_set_next_fixed_width(dim_2f32(indicator_region_rect).x*pct_done); - ui_set_next_fixed_height(dim_2f32(indicator_region_rect).y); - ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + Rng2F32 pct_rect = r2f32p(indicator_region_rect.x0, + indicator_region_rect.y0, + indicator_region_rect.x0 + (indicator_region_rect.x1 - indicator_region_rect.x0)*pct_done, + indicator_region_rect.y1); + UI_Rect(pct_rect) + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_Floating, ui_key_zero()); } // rjf: fill - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = hl_color)); - ui_set_next_fixed_x(indicator_rect.x0); - ui_set_next_fixed_y(indicator_rect.y0); - ui_set_next_fixed_width(dim_2f32(indicator_rect).x); - ui_set_next_fixed_height(dim_2f32(indicator_rect).y); - ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + UI_TagF("pop") UI_Rect(indicator_rect) + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_Floating, ui_key_zero()); // rjf: animated bar - ui_set_next_palette(ui_build_palette(ui_top_palette(), .border = bd_color, .background = bg_color)); - ui_set_next_fixed_x(indicator_region_rect.x0); - ui_set_next_fixed_y(indicator_region_rect.y0); - ui_set_next_fixed_width(dim_2f32(indicator_region_rect).x); - ui_set_next_fixed_height(dim_2f32(indicator_region_rect).y); - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY|UI_BoxFlag_Clickable, "bg_system_status"); - UI_Signal sig = ui_signal_from_box(box); + UI_Rect(indicator_region_rect) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder|UI_BoxFlag_Floating|UI_BoxFlag_Clickable, "bg_system_status"); + UI_Signal sig = ui_signal_from_box(box); + } } // rjf: build background - UI_WidthFill UI_HeightFill + UI_WidthFill UI_HeightFill UI_Transparency(1-loading_t) UI_BlurSize(10.f*loading_t) { - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = bg_color)); ui_set_next_blur_size(10.f*loading_t); - ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, ui_key_zero()); + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_Floating, ui_key_zero()); } } } @@ -92,29 +738,31 @@ rd_loading_overlay(Rng2F32 rect, F32 loading_t, U64 progress_v, U64 progress_v_t //~ rjf: UI Widgets: Fancy Buttons internal void -rd_cmd_binding_buttons(String8 name) +rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new) { Temp scratch = scratch_begin(0, 0); - RD_BindingList bindings = rd_bindings_from_name(scratch.arena, name); + RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_name(scratch.arena, name); //- rjf: build buttons for each binding - for(RD_BindingNode *n = bindings.first; n != 0; n = n->next) + UI_CornerRadius(ui_top_font_size()*0.5f) for(RD_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next) { - RD_Binding binding = n->binding; + ui_spacer(ui_em(1.f, 1.f)); + RD_Binding binding = n->v->binding; B32 rebinding_active_for_this_binding = (rd_state->bind_change_active && str8_match(rd_state->bind_change_cmd_name, name, 0) && - rd_state->bind_change_binding.key == binding.key && - rd_state->bind_change_binding.modifiers == binding.modifiers); + n->v->cfg_id == rd_state->bind_change_binding_id); //- rjf: grab all conflicts - String8List specs_with_binding = rd_cmd_name_list_from_binding(scratch.arena, binding); B32 has_conflicts = 0; - for(String8Node *n = specs_with_binding.first; n != 0; n = n->next) + RD_KeyMapNodePtrList nodes_with_this_binding = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding); { - if(!str8_match(n->string, name, 0)) + for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) { - has_conflicts = 1; - break; + if(!str8_match(n->v->name, n2->v->name, 0)) + { + has_conflicts = 1; + break; + } } } @@ -123,12 +771,7 @@ rd_cmd_binding_buttons(String8 name) { if(binding.key != OS_Key_Null) { - String8List mods = os_string_list_from_modifiers(scratch.arena, binding.modifiers); - String8 key = os_g_key_display_string_table[binding.key]; - str8_list_push(scratch.arena, &mods, key); - StringJoin join = {0}; - join.sep = str8_lit(" + "); - keybinding_str = str8_list_join(scratch.arena, &mods, &join); + keybinding_str = os_string_from_modifiers_key(scratch.arena, binding.modifiers, binding.key); } else { @@ -136,29 +779,16 @@ rd_cmd_binding_buttons(String8 name) } } - //- rjf: form color palette - UI_Palette *palette = ui_top_palette(); - if(has_conflicts || rebinding_active_for_this_binding) + //- rjf: compute fuzzy matches + FuzzyMatchRangeList matches = {0}; + if(filter.size != 0) { - palette = push_array(ui_build_arena(), UI_Palette, 1); - MemoryCopyStruct(palette, ui_top_palette()); - if(has_conflicts) - { - palette->colors[UI_ColorCode_Text] = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative); - palette->colors[UI_ColorCode_TextWeak] = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative); - } - if(rebinding_active_for_this_binding) - { - palette->colors[UI_ColorCode_Border] = rd_rgba_from_theme_color(RD_ThemeColor_Focus); - palette->colors[UI_ColorCode_Background] = rd_rgba_from_theme_color(RD_ThemeColor_Focus); - palette->colors[UI_ColorCode_Background].w *= 0.25f; - } + matches = fuzzy_match_find(scratch.arena, filter, keybinding_str); } //- rjf: build box - ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_tag(has_conflicts ? str8_lit("bad_pop") : rebinding_active_for_this_binding ? str8_lit("pop") : str8_zero()); ui_set_next_text_alignment(UI_TextAlign_Center); - ui_set_next_palette(palette); ui_set_next_group_key(ui_key_zero()); ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*1.f, 1)); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| @@ -168,6 +798,7 @@ rd_cmd_binding_buttons(String8 name) UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBackground, "%S###bind_btn_%S_%x_%x", keybinding_str, name, binding.key, binding.modifiers); + ui_box_equip_fuzzy_match_ranges(box, &matches); //- rjf: interaction UI_Signal sig = ui_signal_from_box(box); @@ -184,7 +815,7 @@ rd_cmd_binding_buttons(String8 name) arena_clear(rd_state->bind_change_arena); rd_state->bind_change_active = 1; rd_state->bind_change_cmd_name = push_str8_copy(rd_state->bind_change_arena, name); - rd_state->bind_change_binding = binding; + rd_state->bind_change_binding_id = n->v->cfg_id; } } else if(rd_state->bind_change_active && ui_clicked(sig)) @@ -196,12 +827,12 @@ rd_cmd_binding_buttons(String8 name) if(ui_hovering(sig) && has_conflicts) UI_Tooltip { UI_PrefWidth(ui_children_sum(1)) rd_error_label(str8_lit("This binding conflicts with those for:")); - for(String8Node *n = specs_with_binding.first; n != 0; n = n->next) + for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next) { - if(!str8_match(n->string, name, 0)) + if(!str8_match(n2->v->name, n->v->name, 0)) { - RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(n->string); - ui_labelf("%S", info->display_name); + String8 display_name = rd_display_from_code_name(n2->v->name); + ui_labelf("%S", display_name); } } } @@ -210,64 +841,51 @@ rd_cmd_binding_buttons(String8 name) //- rjf: delete button if(rebinding_active_for_this_binding) UI_PrefWidth(ui_em(2.5f, 1.f)) - UI_Palette(ui_build_palette(ui_top_palette(), - .background = rd_rgba_from_theme_color(RD_ThemeColor_NegativePopButtonBackground), - .border = rd_rgba_from_theme_color(RD_ThemeColor_NegativePopButtonBorder), - .text = rd_rgba_from_theme_color(RD_ThemeColor_Text))) + UI_TagF("bad_pop") { ui_set_next_group_key(ui_key_zero()); UI_Signal sig = rd_icon_button(RD_IconKind_X, 0, str8_lit("###delete_binding")); if(ui_clicked(sig)) { - rd_unbind_name(name, binding); + rd_cfg_release(rd_cfg_from_id(rd_state->bind_change_binding_id)); rd_state->bind_change_active = 0; } } - - //- rjf: space - ui_spacer(ui_em(1.f, 1.f)); } //- rjf: build "add new binding" button - RD_Font(RD_FontSlot_Icons) + if(add_new) { - UI_Palette *palette = ui_top_palette(); B32 adding_new_binding = (rd_state->bind_change_active && str8_match(rd_state->bind_change_cmd_name, name, 0) && - rd_state->bind_change_binding.key == OS_Key_Null && - rd_state->bind_change_binding.modifiers == 0); - if(adding_new_binding) + rd_state->bind_change_binding_id == 0); + ui_spacer(ui_em(1.f, 1.f)); + RD_Font(RD_FontSlot_Icons) UI_TagF(adding_new_binding ? "pop" : "") UI_CornerRadius(ui_top_font_size()*0.5f) { - palette = ui_build_palette(ui_top_palette()); - palette->colors[UI_ColorCode_Border] = rd_rgba_from_theme_color(RD_ThemeColor_Focus); - palette->colors[UI_ColorCode_Background] = rd_rgba_from_theme_color(RD_ThemeColor_Focus); - palette->colors[UI_ColorCode_Background].w *= 0.25f; - } - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_text_alignment(UI_TextAlign_Center); - ui_set_next_group_key(ui_key_zero()); - ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*1.f, 1)); - ui_set_next_palette(palette); - UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| - UI_BoxFlag_Clickable| - UI_BoxFlag_DrawActiveEffects| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground, - "%S###add_binding", rd_icon_kind_text_table[RD_IconKind_Add]); - UI_Signal sig = ui_signal_from_box(box); - if(ui_clicked(sig)) - { - if(!rd_state->bind_change_active && ui_clicked(sig)) + ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_group_key(ui_key_zero()); + ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*1.5f, 1)); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_Clickable| + UI_BoxFlag_DrawActiveEffects| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground, + "%S###add_binding", rd_icon_kind_text_table[RD_IconKind_Add]); + UI_Signal sig = ui_signal_from_box(box); + if(ui_clicked(sig)) { - arena_clear(rd_state->bind_change_arena); - rd_state->bind_change_active = 1; - rd_state->bind_change_cmd_name = push_str8_copy(rd_state->bind_change_arena, name); - MemoryZeroStruct(&rd_state->bind_change_binding); - } - else if(rd_state->bind_change_active && ui_clicked(sig)) - { - rd_state->bind_change_active = 0; + if(!adding_new_binding && ui_clicked(sig)) + { + arena_clear(rd_state->bind_change_arena); + rd_state->bind_change_active = 1; + rd_state->bind_change_cmd_name = push_str8_copy(rd_state->bind_change_arena, name); + rd_state->bind_change_binding_id = 0; + } + else if(adding_new_binding && ui_clicked(sig)) + { + rd_state->bind_change_active = 0; + } } } } @@ -278,7 +896,6 @@ rd_cmd_binding_buttons(String8 name) internal UI_Signal rd_menu_bar_button(String8 string) { - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects, string); UI_Signal sig = ui_signal_from_box(box); return sig; @@ -288,7 +905,6 @@ internal UI_Signal rd_cmd_spec_button(String8 name) { RD_CmdKindInfo *info = rd_cmd_kind_info_from_string(name); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); ui_set_next_child_layout_axis(Axis2_X); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder| UI_BoxFlag_DrawBackground| @@ -298,13 +914,13 @@ rd_cmd_spec_button(String8 name) "###cmd_%p", info); UI_Parent(box) UI_HeightFill UI_Padding(ui_em(1.f, 1.f)) { - RD_IconKind canonical_icon = info->icon_kind; + RD_IconKind canonical_icon = rd_icon_kind_from_code_name(name); if(canonical_icon != RD_IconKind_Null) { RD_Font(RD_FontSlot_Icons) UI_PrefWidth(ui_em(2.f, 1.f)) UI_TextAlignment(UI_TextAlign_Center) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + UI_TagF("weak") { ui_label(rd_icon_kind_text_table[canonical_icon]); } @@ -313,17 +929,17 @@ rd_cmd_spec_button(String8 name) { UI_Flags(UI_BoxFlag_DrawTextFastpathCodepoint) UI_FastpathCodepoint(box->fastpath_codepoint) - ui_label(info->display_name); + ui_label(rd_display_from_code_name(name)); ui_spacer(ui_pct(1, 0)); ui_set_next_flags(UI_BoxFlag_Clickable); ui_set_next_group_key(ui_key_zero()); UI_PrefWidth(ui_children_sum(1)) UI_FontSize(ui_top_font_size()*0.95f) UI_HeightFill UI_NamedRow(str8_lit("###bindings")) - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) + UI_TagF("weak") UI_FastpathCodepoint(0) { - rd_cmd_binding_buttons(name); + rd_cmd_binding_buttons(name, str8_zero(), 1); } } } @@ -343,8 +959,9 @@ rd_cmd_list_menu_buttons(U64 count, String8 *cmd_names, U32 *fastpath_codepoints { rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_names[idx]); ui_ctx_menu_close(); - RD_Window *window = rd_window_from_handle(rd_regs()->window); - window->menu_bar_focused = 0; + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + ws->menu_bar_focused = 0; } } scratch_end(scratch); @@ -354,7 +971,6 @@ internal UI_Signal rd_icon_button(RD_IconKind kind, FuzzyMatchRangeList *matches, String8 string) { String8 display_string = ui_display_part_from_key_string(string); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); ui_set_next_child_layout_axis(Axis2_X); UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBorder| @@ -376,7 +992,8 @@ rd_icon_button(RD_IconKind kind, FuzzyMatchRangeList *matches, String8 string) RD_Font(RD_FontSlot_Icons) UI_PrefWidth(ui_em(2.f, 1.f)) UI_PrefHeight(ui_pct(1, 0)) - UI_FlagsAdd(UI_BoxFlag_DisableTextTrunc|UI_BoxFlag_DrawTextWeak) + UI_FlagsAdd(UI_BoxFlag_DisableTextTrunc) + UI_TagF("weak") ui_label(rd_icon_kind_text_table[kind]); if(display_string.size != 0) { @@ -464,7 +1081,7 @@ internal UI_BOX_CUSTOM_DRAW(rd_thread_box_draw_extensions) if(u->hover_t > 0.001f) { Vec4F32 weak_thread_color = u->thread_color; - weak_thread_color.w *= 0.5f*u->hover_t; + weak_thread_color.w *= 0.15f*u->hover_t; R_Rect2DInst *inst = dr_rect(r2f32p(box->rect.x0, box->parent->rect.y0, box->rect.x0 + ui_top_font_size()*22.f*u->hover_t, @@ -478,7 +1095,7 @@ internal UI_BOX_CUSTOM_DRAW(rd_thread_box_draw_extensions) if(u->is_selected && u->do_glow) { Vec4F32 weak_thread_color = u->thread_color; - weak_thread_color.w *= 0.3f; + weak_thread_color.w *= 0.1f; R_Rect2DInst *inst = dr_rect(r2f32p(box->rect.x0, box->parent->rect.y0, box->rect.x0 + ui_top_font_size()*22.f*u->alive_t, @@ -489,15 +1106,15 @@ internal UI_BOX_CUSTOM_DRAW(rd_thread_box_draw_extensions) } // rjf: locked icon on frozen threads - if(u->is_frozen) + if(u->is_frozen) UI_TagF("bad") { F32 lock_icon_off = ui_top_font_size()*0.2f; - Vec4F32 lock_icon_color = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative); + Vec4F32 color = ui_color_from_name(str8_lit("text")); dr_text(rd_font_from_slot(RD_FontSlot_Icons), box->font_size, 0, 0, FNT_RasterFlag_Smooth, v2f32((box->rect.x0 + box->rect.x1)/2 + lock_icon_off/2, box->rect.y0 + lock_icon_off/2), - lock_icon_color, + color, rd_icon_kind_text_table[RD_IconKind_Locked]); } } @@ -511,6 +1128,8 @@ struct RD_BreakpointBoxDrawExtData F32 remap_px_delta; B32 do_lines; B32 do_glow; + B32 is_disabled; + B32 is_conditioned; }; internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions) @@ -580,6 +1199,33 @@ internal UI_BOX_CUSTOM_DRAW(rd_bp_box_draw_extensions) remap_color, rd_icon_kind_text_table[RD_IconKind_CircleFilled]); } + + // rjf: draw conditioned marker + if(u->is_conditioned) UI_TagF(u->is_disabled ? "weak" : "") + { + Temp scratch = scratch_begin(0, 0); + Vec4F32 color = ui_color_from_name(str8_lit("text")); + FNT_Run run = fnt_run_from_string(rd_font_from_slot(RD_FontSlot_Code), box->font_size*0.8f, 0, 0, FNT_RasterFlag_Smooth, str8_lit("if")); + Vec2F32 p = center_2f32(box->rect); + p.x -= run.dim.x*0.5f; + p.y += run.descent; + dr_text_run(p, color, run); + scratch_end(scratch); + } + + // rjf: draw disabled marker + if(u->is_disabled) + { + Temp scratch = scratch_begin(0, 0); + Vec4F32 color = ui_color_from_name(str8_lit("breakpoint")); + FNT_Run run = fnt_run_from_string(rd_font_from_slot(RD_FontSlot_Icons), box->font_size*0.95f, 0, 0, FNT_RasterFlag_Smooth, str8_lit("x")); + Vec2F32 box_dim = dim_2f32(box->rect); + Vec2F32 p = center_2f32(box->rect); + p.x += box_dim.x*0.1f; + p.y -= box_dim.y*0.2f; + dr_text_run(p, color, run); + scratch_end(scratch); + } } internal RD_CodeSliceSignal @@ -588,7 +1234,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe RD_CodeSliceSignal result = {0}; ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - CTRL_Entity *selected_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_regs()->thread); + CTRL_Entity *selected_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread); CTRL_Entity *selected_thread_process = ctrl_entity_ancestor_from_kind(selected_thread, CTRL_EntityKind_Process); U64 selected_thread_rip_unwind_vaddr = d_query_cached_rip_from_thread_unwind(selected_thread, rd_regs()->unwind_count); CTRL_Entity *selected_thread_module = ctrl_module_from_process_vaddr(selected_thread_process, selected_thread_rip_unwind_vaddr); @@ -596,22 +1242,93 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe F32 selected_thread_module_alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "###selected_thread_module_alive_t_%p", selected_thread_module), 1.f); F32 selected_thread_arch_alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "###selected_thread_arch_alive_t_%i", selected_thread->arch), 1.f); CTRL_Event stop_event = d_ctrl_last_stop_event(); - CTRL_Entity *stopper_thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, stop_event.entity); + CTRL_Entity *stopper_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, stop_event.entity); B32 is_focused = ui_is_focus_active(); B32 ctrlified = (os_get_modifiers() & OS_Modifier_Ctrl); Vec4F32 code_line_bgs[] = { - rd_rgba_from_theme_color(RD_ThemeColor_LineInfoBackground0), - rd_rgba_from_theme_color(RD_ThemeColor_LineInfoBackground1), - rd_rgba_from_theme_color(RD_ThemeColor_LineInfoBackground2), - rd_rgba_from_theme_color(RD_ThemeColor_LineInfoBackground3), + ui_color_from_name(str8_lit("line_info_0")), + ui_color_from_name(str8_lit("line_info_1")), + ui_color_from_name(str8_lit("line_info_2")), + ui_color_from_name(str8_lit("line_info_3")), }; - UI_Palette *margin_palette = rd_palette_from_code(RD_PaletteCode_Floating); - UI_Palette *margin_contents_palette = ui_build_palette(rd_palette_from_code(RD_PaletteCode_Floating)); - margin_contents_palette->background = v4f32(0, 0, 0, 0); F32 line_num_padding_px = ui_top_font_size()*1.f; - F32 entity_alive_t_rate = (1 - pow_f32(2, (-30.f * rd_state->frame_dt))); - F32 entity_hover_t_rate = rd_setting_val_from_code(RD_SettingCode_HoverAnimations).s32 ? (1 - pow_f32(2, (-20.f * rd_state->frame_dt))) : 1.f; + F32 entity_alive_t_rate = rd_state->entity_alive_animation_rate; + F32 entity_hover_t_rate = rd_state->rich_hover_animation_rate; + B32 do_thread_lines = rd_setting_b32_from_name(str8_lit("thread_lines")); + B32 do_thread_glow = rd_setting_b32_from_name(str8_lit("thread_glow")); + B32 do_bp_lines = rd_setting_b32_from_name(str8_lit("breakpoint_lines")); + B32 do_bp_glow = rd_setting_b32_from_name(str8_lit("breakpoint_glow")); + Vec4F32 pop_color = {0}; + UI_TagF("pop") + { + pop_color = ui_color_from_name(str8_lit("background")); + } + + ////////////////////////////// + //- rjf: produce fancy strings for each line + // + DR_FStrList *lines_fstrs = push_array(scratch.arena, DR_FStrList, dim_1s64(params->line_num_range)+1); + { + DR_FStrParams fstr_params = + { + params->font, + rd_raster_flags_from_slot(RD_FontSlot_Code), + rd_rgba_from_code_color_slot(RD_CodeColorSlot_CodeDefault), + params->font_size, + }; + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) + { + String8 line_string = params->line_text[line_idx]; + Rng1U64 line_range = params->line_ranges[line_idx]; + TXT_TokenArray *line_tokens = ¶ms->line_tokens[line_idx]; + DR_FStrList fstrs = {0}; + if(line_tokens->count == 0) + { + dr_fstrs_push_new(scratch.arena, &fstrs, &fstr_params, line_string); + } + else + { + TXT_Token *line_tokens_first = line_tokens->v; + TXT_Token *line_tokens_opl = line_tokens->v + line_tokens->count; + for(TXT_Token *token = line_tokens_first; token < line_tokens_opl; token += 1) + { + // rjf: token -> token string + String8 token_string = {0}; + { + Rng1U64 token_range = r1u64(0, line_string.size); + if(token->range.min > line_range.min) + { + token_range.min += token->range.min-line_range.min; + } + if(token->range.max < line_range.max) + { + token_range.max = token->range.max-line_range.min; + } + token_string = str8_substr(line_string, token_range); + } + + // rjf: token -> token color + RD_CodeColorSlot token_color_slot = rd_code_color_slot_from_txt_token_kind(token->kind); + RD_CodeColorSlot lookup_color_slot = rd_code_color_slot_from_txt_token_kind_lookup_string(token->kind, token_string); + Vec4F32 token_color = rd_rgba_from_code_color_slot(token_color_slot); + if(lookup_color_slot != RD_CodeColorSlot_CodeDefault) + { + Vec4F32 lookup_color = rd_rgba_from_code_color_slot(lookup_color_slot); + F32 lookup_color_mix_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "%S_lookup", token_string), 1.f); + token_color = mix_4f32(token_color, lookup_color, lookup_color_mix_t); + } + + // rjf: push fancy string + dr_fstrs_push_new(scratch.arena, &fstrs, &fstr_params, token_string, .color = token_color); + } + } + lines_fstrs[line_idx] = fstrs; + } + } ////////////////////////////// //- rjf: build top-level container @@ -633,23 +1350,72 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } } + ////////////////////////////// + //- rjf: dragging cfgs/entities/expressions? -> drop site + // + B32 drop_can_hit_lines = 0; + RD_Cfg *drop_cfg = &rd_nil_cfg; + CTRL_Entity *drop_thread = &ctrl_entity_nil; + String8 drop_expr = {0}; + Vec4F32 drop_color = pop_color; + UI_Key drop_site_key = ui_key_from_stringf(top_container_box->key, "drop_site"); + if(rd_drag_is_active()) + { + RD_Cfg *cfg = rd_cfg_from_id(rd_state->drag_drop_regs->cfg); + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && + (str8_match(cfg->string, str8_lit("breakpoint"), 0) || + str8_match(cfg->string, str8_lit("watch_pin"), 0))) + { + drop_can_hit_lines = 1; + drop_cfg = cfg; + drop_color = linear_from_srgba(rd_color_from_cfg(cfg)); + if(drop_color.w == 0) + { + drop_color = pop_color; + } + } + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Thread) + { + drop_can_hit_lines = 1; + drop_thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_state->drag_drop_regs->thread); + drop_color = rd_color_from_ctrl_entity(drop_thread); + if(drop_color.w == 0) + { + drop_color = pop_color; + } + } + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Expr) + { + drop_can_hit_lines = 1; + drop_expr = rd_state->drag_drop_regs->expr; + } + if(drop_can_hit_lines) UI_WidthFill UI_HeightFill + { + UI_Box *drop_site_box = ui_build_box_from_key(UI_BoxFlag_DropSite|UI_BoxFlag_Floating, drop_site_key); + ui_signal_from_box(drop_site_box); + } + } + ////////////////////////////// //- rjf: build per-line background colors // Vec4F32 *line_bg_colors = push_array(scratch.arena, Vec4F32, dim_1s64(params->line_num_range)+1); { //- rjf: color line with stopper-thread red - U64 line_idx = 0; - for(S64 line_num = params->line_num_range.min; - line_num < params->line_num_range.max; - line_num += 1, line_idx += 1) + UI_TagF("bad_pop") { - CTRL_EntityList threads = params->line_ips[line_idx]; - for(CTRL_EntityNode *n = threads.first; n != 0; n = n->next) + U64 line_idx = 0; + for(S64 line_num = params->line_num_range.min; + line_num < params->line_num_range.max; + line_num += 1, line_idx += 1) { - if(n->v == stopper_thread && (stop_event.cause == CTRL_EventCause_InterruptedByTrap || stop_event.cause == CTRL_EventCause_InterruptedByException)) + CTRL_EntityList threads = params->line_ips[line_idx]; + for(CTRL_EntityNode *n = threads.first; n != 0; n = n->next) { - line_bg_colors[line_idx] = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlayError); + if(n->v == stopper_thread && (stop_event.cause == CTRL_EventCause_InterruptedByTrap || stop_event.cause == CTRL_EventCause_InterruptedByException)) + { + line_bg_colors[line_idx] = ui_color_from_name(str8_lit("background")); + } } } } @@ -659,7 +1425,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe //- rjf: build priority margin // UI_Box *priority_margin_container_box = &ui_nil_box; - if(params->flags & RD_CodeSliceFlag_PriorityMargin) UI_Focus(UI_FocusKind_Off) UI_Parent(top_container_box) UI_Palette(margin_palette) ProfScope("build priority margins") + if(params->flags & RD_CodeSliceFlag_PriorityMargin) UI_Focus(UI_FocusKind_Off) UI_Parent(top_container_box) ProfScope("build priority margins") { if(params->margin_float_off_px != 0) { @@ -672,7 +1438,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_child_layout_axis(Axis2_Y); priority_margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("priority_margin_container")); - UI_Parent(priority_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) UI_Palette(margin_contents_palette) + UI_Parent(priority_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; @@ -681,7 +1447,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { CTRL_EntityList line_ips = params->line_ips[line_idx]; ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); + UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); UI_Parent(line_margin_box) { //- rjf: build margin thread ip ui @@ -701,18 +1467,22 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color - Vec4F32 color = rd_rgba_from_ctrl_entity(thread); + Vec4F32 color = rd_color_from_ctrl_entity(thread); { + if(color.w == 0) + { + color = ui_color_from_name(str8_lit("thread_1")); + } if(unwind_count != 0) { - color = rd_rgba_from_theme_color(RD_ThemeColor_ThreadUnwound); + color = ui_color_from_name(str8_lit("thread_unwound")); } else if(thread == stopper_thread && (stop_event.cause == CTRL_EventCause_InterruptedByHalt || stop_event.cause == CTRL_EventCause_InterruptedByTrap || stop_event.cause == CTRL_EventCause_InterruptedByException)) { - color = rd_rgba_from_theme_color(RD_ThemeColor_ThreadError); + color = ui_color_from_name(str8_lit("thread_error")); } if(d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index()) { @@ -720,7 +1490,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } if(thread != selected_thread) { - color.w *= 0.8f; + color.w *= 0.5f; } } @@ -731,8 +1501,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_text_raster_flags(FNT_RasterFlag_Smooth); ui_set_next_pref_width(ui_pct(1, 0)); ui_set_next_pref_height(ui_pct(1, 0)); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = color)); ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_text_color(color); UI_Key thread_box_key = ui_key_from_stringf(top_container_box->key, "###ip_%I64x_%p", line_num, thread); UI_Box *thread_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc| UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| @@ -744,16 +1514,16 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: custom draw { RD_Regs *hover_regs = rd_get_hover_regs(); - B32 is_hovering = (ctrl_handle_match(hover_regs->thread, thread->handle) && - rd_state->hover_regs_slot == RD_RegSlot_Thread); + B32 is_hovering = (ctrl_handle_match(hover_regs->ctrl_entity, thread->handle) && + rd_state->hover_regs_slot == RD_RegSlot_CtrlEntity); RD_ThreadBoxDrawExtData *u = push_array(ui_build_arena(), RD_ThreadBoxDrawExtData, 1); u->thread_color = color; - u->alive_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###thread_alive_t_%p", thread), 1.f, .rate = entity_alive_t_rate); - u->hover_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###thread_hover_t_%p", thread), (F32)!!is_hovering, .rate = entity_hover_t_rate); + u->alive_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###entity_alive_t_%p", thread), 1.f, .rate = entity_alive_t_rate); + u->hover_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###entity_hover_t_%p", thread), (F32)!!is_hovering, .rate = entity_hover_t_rate); u->is_selected = (thread == selected_thread); u->is_frozen = !!thread->is_frozen; - u->do_lines = rd_setting_val_from_code(RD_SettingCode_ThreadLines).s32; - u->do_glow = rd_setting_val_from_code(RD_SettingCode_ThreadGlow).s32; + u->do_lines = do_thread_lines; + u->do_glow = do_thread_glow; ui_box_equip_custom_draw(thread_box, rd_thread_box_draw_extensions, u); // rjf: fill out progress t (progress into range of current line's @@ -785,11 +1555,13 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: interactions if(ui_hovering(thread_sig) && !rd_drag_is_active()) { - RD_RegsScope(.thread = thread->handle) rd_set_hover_regs(RD_RegSlot_Thread); + RD_RegsScope(.ctrl_entity = thread->handle) rd_set_hover_regs(RD_RegSlot_CtrlEntity); } if(ui_right_clicked(thread_sig)) { - RD_RegsScope(.thread = thread->handle) rd_open_ctx_menu(thread_box->key, v2f32(0, thread_box->rect.y1-thread_box->rect.y0), RD_RegSlot_Thread); + rd_cmd(RD_CmdKind_PushQuery, + .ui_key = thread_box->key, + .expr = push_str8f(scratch.arena, "query:control.%S", ctrl_string_from_handle(scratch.arena, thread->handle))); } if(ui_dragging(thread_sig) && !contains_2f32(thread_box->rect, ui_mouse())) { @@ -805,7 +1577,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe //- rjf: build catchall margin // UI_Box *catchall_margin_container_box = &ui_nil_box; - if(params->flags & RD_CodeSliceFlag_CatchallMargin) UI_Focus(UI_FocusKind_Off) UI_Palette(margin_palette) UI_Parent(top_container_box) ProfScope("build catchall margins") + if(params->flags & RD_CodeSliceFlag_CatchallMargin) UI_Focus(UI_FocusKind_Off) UI_Parent(top_container_box) ProfScope("build catchall margins") + UI_TagF("floating") { if(params->margin_float_off_px != 0) { @@ -817,8 +1590,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_pref_width(ui_px(params->catchall_margin_width_px, 1)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); ui_set_next_child_layout_axis(Axis2_Y); - catchall_margin_container_box = ui_build_box_from_string(UI_BoxFlag_DrawSideLeft|UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("catchall_margin_container")); - UI_Parent(catchall_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) UI_Palette(margin_contents_palette) + catchall_margin_container_box = ui_build_box_from_string(UI_BoxFlag_DrawSideRight|UI_BoxFlag_DrawSideLeft|UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable), str8_lit("catchall_margin_container")); + UI_Parent(catchall_margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; @@ -826,9 +1599,10 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num += 1, line_idx += 1) { CTRL_EntityList line_ips = params->line_ips[line_idx]; - RD_EntityList line_bps = params->line_bps[line_idx]; - RD_EntityList line_pins = params->line_pins[line_idx]; + RD_CfgList line_bps = params->line_bps[line_idx]; + RD_CfgList line_pins = params->line_pins[line_idx]; ui_set_next_hover_cursor(OS_Cursor_HandPoint); + ui_set_next_background_color(v4f32(0, 0, 0, 0)); UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); UI_Parent(line_margin_box) { @@ -849,18 +1623,22 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 thread_rip_voff = ctrl_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color - Vec4F32 color = rd_rgba_from_ctrl_entity(thread); + Vec4F32 color = rd_color_from_ctrl_entity(thread); { + if(color.w == 0) + { + color = ui_color_from_name(str8_lit("thread_1")); + } if(unwind_count != 0) { - color = rd_rgba_from_theme_color(RD_ThemeColor_ThreadUnwound); + color = ui_color_from_name(str8_lit("thread_unwound")); } else if(thread == stopper_thread && (stop_event.cause == CTRL_EventCause_InterruptedByHalt || stop_event.cause == CTRL_EventCause_InterruptedByTrap || stop_event.cause == CTRL_EventCause_InterruptedByException)) { - color = rd_rgba_from_theme_color(RD_ThemeColor_ThreadError); + color = ui_color_from_name(str8_lit("thread_error")); } if(d_ctrl_targets_running() && d_ctrl_last_run_frame_idx() < d_frame_index()) { @@ -879,8 +1657,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_text_raster_flags(FNT_RasterFlag_Smooth); ui_set_next_pref_width(ui_pct(1, 0)); ui_set_next_pref_height(ui_pct(1, 0)); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = color)); ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_text_color(color); UI_Key thread_box_key = ui_key_from_stringf(top_container_box->key, "###ip_%I64x_catchall_%p", line_num, thread); UI_Box *thread_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc| UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| @@ -892,12 +1670,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: custom draw { RD_Regs *hover_regs = rd_get_hover_regs(); - B32 is_hovering = (ctrl_handle_match(hover_regs->thread, thread->handle) && - rd_state->hover_regs_slot == RD_RegSlot_Thread); + B32 is_hovering = (ctrl_handle_match(hover_regs->ctrl_entity, thread->handle) && + rd_state->hover_regs_slot == RD_RegSlot_CtrlEntity); RD_ThreadBoxDrawExtData *u = push_array(ui_build_arena(), RD_ThreadBoxDrawExtData, 1); u->thread_color = color; - u->alive_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###thread_alive_t_%p", thread), 1.f, .rate = entity_alive_t_rate); - u->hover_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###thread_hover_t_%p", thread), (F32)!!is_hovering, .rate = entity_hover_t_rate); + u->alive_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###entity_alive_t_%p", thread), 1.f, .rate = entity_alive_t_rate); + u->hover_t = ui_anim(ui_key_from_stringf(top_container_box->key, "###entity_hover_t_%p", thread), (F32)!!is_hovering, .rate = entity_hover_t_rate); u->is_selected = (thread == selected_thread); u->is_frozen = !!thread->is_frozen; ui_box_equip_custom_draw(thread_box, rd_thread_box_draw_extensions, u); @@ -931,11 +1709,13 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: interactions if(ui_hovering(thread_sig) && !rd_drag_is_active()) { - RD_RegsScope(.thread = thread->handle) rd_set_hover_regs(RD_RegSlot_Thread); + RD_RegsScope(.ctrl_entity = thread->handle) rd_set_hover_regs(RD_RegSlot_CtrlEntity); } if(ui_right_clicked(thread_sig)) { - RD_RegsScope(.thread = thread->handle) rd_open_ctx_menu(thread_box->key, v2f32(0, thread_box->rect.y1-thread_box->rect.y0), RD_RegSlot_Thread); + rd_cmd(RD_CmdKind_PushQuery, + .ui_key = thread_box->key, + .expr = push_str8f(scratch.arena, "query:control.%S", ctrl_string_from_handle(scratch.arena, thread->handle))); } if(ui_dragging(thread_sig) && !contains_2f32(thread_box->rect, ui_mouse())) { @@ -949,29 +1729,32 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } //- rjf: build margin breakpoint ui - for(RD_EntityNode *n = line_bps.first; n != 0; n = n->next) + for(RD_CfgNode *n = line_bps.first; n != 0; n = n->next) { - RD_Entity *bp = n->entity; - Vec4F32 bp_color = rd_rgba_from_theme_color(RD_ThemeColor_Breakpoint); - if(bp->flags & RD_EntityFlag_HasColor) + RD_Cfg *bp = n->v; + Vec4F32 bp_rgba = rd_color_from_cfg(bp); + if(bp_rgba.w == 0) { - bp_color = rd_rgba_from_entity(bp); + bp_rgba = ui_color_from_name(str8_lit("breakpoint")); } - if(bp->disabled) + B32 bp_is_disabled = rd_disabled_from_cfg(bp); + if(bp_is_disabled) { - bp_color = v4f32(bp_color.x * 0.6f, bp_color.y * 0.6f, bp_color.z * 0.6f, bp_color.w * 0.6f); + bp_rgba = v4f32(bp_rgba.x*0.45f, bp_rgba.y*0.45f, bp_rgba.z*0.45f, bp_rgba.w*0.45f); } // rjf: prep custom rendering data RD_BreakpointBoxDrawExtData *bp_draw = push_array(ui_build_arena(), RD_BreakpointBoxDrawExtData, 1); { RD_Regs *hover_regs = rd_get_hover_regs(); - B32 is_hovering = (rd_entity_from_handle(hover_regs->entity) == bp && rd_state->hover_regs_slot == RD_RegSlot_Entity); - bp_draw->color = bp_color; - bp_draw->alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "bp_alive_t_%p", bp), 1.f, .rate = entity_alive_t_rate); - bp_draw->hover_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "bp_hover_t_%p", bp), (F32)!!is_hovering, .rate = entity_hover_t_rate); - bp_draw->do_lines = rd_setting_val_from_code(RD_SettingCode_BreakpointLines).s32; - bp_draw->do_glow = rd_setting_val_from_code(RD_SettingCode_BreakpointGlow).s32; + B32 is_hovering = (rd_cfg_from_id(hover_regs->cfg) == bp && rd_state->hover_regs_slot == RD_RegSlot_Cfg); + bp_draw->color = bp_rgba; + bp_draw->alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_alive_t_%p", bp), 1.f, .rate = entity_alive_t_rate); + bp_draw->hover_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_hover_t_%p", bp), (F32)!!is_hovering, .rate = entity_hover_t_rate); + bp_draw->do_lines = do_bp_lines; + bp_draw->do_glow = do_bp_glow; + bp_draw->is_disabled = bp_is_disabled; + bp_draw->is_conditioned = (rd_cfg_child_from_string(bp, str8_lit("condition"))->first->string.size != 0); if(params->line_vaddrs[line_idx] == 0) { D_LineList *lines = ¶ms->line_infos[line_idx]; @@ -991,9 +1774,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ui_set_next_font(rd_font_from_slot(RD_FontSlot_Icons)); ui_set_next_font_size(params->font_size * 1.f); ui_set_next_text_raster_flags(FNT_RasterFlag_Smooth); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = bp_color)); ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_text_color(bp_rgba); UI_Box *bp_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| UI_BoxFlag_DisableTextTrunc, @@ -1006,51 +1788,52 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: bp hovering if(ui_hovering(bp_sig) && !rd_drag_is_active()) { - RD_RegsScope(.entity = rd_handle_from_entity(bp)) rd_set_hover_regs(RD_RegSlot_Entity); + RD_RegsScope(.cfg = bp->id) rd_set_hover_regs(RD_RegSlot_Cfg); + } + + // rjf: bp right-click => open query + if(ui_right_clicked(bp_sig)) + { + rd_cmd(RD_CmdKind_PushQuery, + .ui_key = bp_box->key, + .expr = push_str8f(scratch.arena, "query:config.$%I64x", bp->id)); } // rjf: shift+click => enable breakpoint if(ui_clicked(bp_sig) && bp_sig.event_flags & OS_Modifier_Shift) { - rd_cmd(bp->disabled ? RD_CmdKind_EnableEntity : RD_CmdKind_DisableEntity, .entity = rd_handle_from_entity(bp)); + rd_cmd(bp_is_disabled ? RD_CmdKind_EnableCfg : RD_CmdKind_DisableCfg, .cfg = bp->id); } // rjf: click => remove breakpoint if(ui_clicked(bp_sig) && bp_sig.event_flags == 0) { - rd_cmd(RD_CmdKind_RemoveEntity, .entity = rd_handle_from_entity(bp)); + rd_cmd(RD_CmdKind_RemoveCfg, .cfg = bp->id); } // rjf: drag start if(ui_dragging(bp_sig) && !contains_2f32(bp_box->rect, ui_mouse())) { - RD_RegsScope(.entity = rd_handle_from_entity(bp)) rd_drag_begin(RD_RegSlot_Entity); - } - - // rjf: bp right-click menu - if(ui_right_clicked(bp_sig)) - { - RD_RegsScope(.entity = rd_handle_from_entity(bp)) rd_open_ctx_menu(bp_box->key, v2f32(0, bp_box->rect.y1-bp_box->rect.y0), RD_RegSlot_Entity); + RD_RegsScope(.cfg = bp->id) rd_drag_begin(RD_RegSlot_Cfg); } } //- rjf: build margin watch pin ui - for(RD_EntityNode *n = line_pins.first; n != 0; n = n->next) + for(RD_CfgNode *n = line_pins.first; n != 0; n = n->next) { - RD_Entity *pin = n->entity; - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_Text); - if(pin->flags & RD_EntityFlag_HasColor) + RD_Cfg *pin = n->v; + Vec4F32 color = rd_color_from_cfg(pin); + if(color.w == 0) { - color = rd_rgba_from_entity(pin); + color = ui_color_from_name(str8_lit("code_default")); } // rjf: build box for watch ui_set_next_font(rd_font_from_slot(RD_FontSlot_Icons)); ui_set_next_font_size(params->font_size * 1.f); ui_set_next_text_raster_flags(FNT_RasterFlag_Smooth); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = color)); ui_set_next_text_alignment(UI_TextAlign_Center); + ui_set_next_text_color(color); UI_Box *pin_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| UI_BoxFlag_DisableTextTrunc, @@ -1062,25 +1845,27 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // rjf: watch hovering if(ui_hovering(pin_sig) && !rd_drag_is_active()) { - RD_RegsScope(.entity = rd_handle_from_entity(pin)) rd_set_hover_regs(RD_RegSlot_Entity); + RD_RegsScope(.cfg = pin->id) rd_set_hover_regs(RD_RegSlot_Cfg); + } + + // rjf: pin right-click => open query + if(ui_right_clicked(pin_sig)) + { + rd_cmd(RD_CmdKind_PushQuery, + .ui_key = pin_box->key, + .expr = push_str8f(scratch.arena, "query:config.$%I64x", pin->id)); } // rjf: click => remove pin if(ui_clicked(pin_sig)) { - rd_cmd(RD_CmdKind_RemoveEntity, .entity = rd_handle_from_entity(pin)); + rd_cmd(RD_CmdKind_RemoveCfg, .cfg = pin->id); } // rjf: drag start if(ui_dragging(pin_sig) && !contains_2f32(pin_box->rect, ui_mouse())) { - RD_RegsScope(.entity = rd_handle_from_entity(pin)) rd_drag_begin(RD_RegSlot_Entity); - } - - // rjf: watch right-click menu - if(ui_right_clicked(pin_sig)) - { - RD_RegsScope(.entity = rd_handle_from_entity(pin)) rd_open_ctx_menu(pin_box->key, v2f32(0, pin_box->rect.y1-pin_box->rect.y0), RD_RegSlot_Entity); + RD_RegsScope(.cfg = pin->id) rd_drag_begin(RD_RegSlot_Cfg); } } } @@ -1102,14 +1887,13 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe //- rjf: build line numbers // if(params->flags & RD_CodeSliceFlag_LineNums) UI_Parent(top_container_box) ProfScope("build line numbers") UI_Focus(UI_FocusKind_Off) + UI_TagF("floating") { TxtRng select_rng = txt_rng(*cursor, *mark); - Vec4F32 active_color = rd_rgba_from_theme_color(RD_ThemeColor_CodeLineNumbersSelected); - Vec4F32 inactive_color = rd_rgba_from_theme_color(RD_ThemeColor_CodeLineNumbers); ui_set_next_fixed_x(floor_f32(params->margin_float_off_px + params->priority_margin_width_px + params->catchall_margin_width_px)); ui_set_next_pref_width(ui_px(params->line_num_width_px, 1.f)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); - ui_set_next_flags(UI_BoxFlag_DrawSideLeft|UI_BoxFlag_DrawSideRight); + ui_set_next_flags(UI_BoxFlag_DrawSideRight); UI_Column UI_PrefHeight(ui_px(params->line_height_px, 1.f)) RD_Font(RD_FontSlot_Code) @@ -1121,7 +1905,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num <= params->line_num_range.max; line_num += 1, line_idx += 1) { - Vec4F32 text_color = (select_rng.min.line <= line_num && line_num <= select_rng.max.line) ? active_color : inactive_color; + B32 line_is_selected = (select_rng.min.line <= line_num && line_num <= select_rng.max.line); Vec4F32 bg_color = v4f32(0, 0, 0, 0); // rjf: line info on this line -> adjust bg color to visualize @@ -1150,8 +1934,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe } // rjf: build line num box - ui_set_next_palette(ui_build_palette(ui_top_palette(), .text = text_color, .background = bg_color)); - ui_build_box_from_stringf(UI_BoxFlag_DrawText|(UI_BoxFlag_DrawBackground*!!has_line_info), "%I64u##line_num", line_num); + UI_TagF(line_is_selected ? "" : "weak") UI_BackgroundColor(bg_color) + ui_build_box_from_stringf(UI_BoxFlag_DrawText|(UI_BoxFlag_DrawBackground*!!has_line_info), "%I64u##line_num", line_num); } } } @@ -1160,7 +1944,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe //- rjf: build background for line numbers & margins // { - UI_Parent(top_container_box) RD_Palette(RD_PaletteCode_Floating) + UI_Parent(top_container_box) UI_TagF("floating") { ui_set_next_pref_width(ui_px(params->priority_margin_width_px + params->catchall_margin_width_px + params->line_num_width_px, 1)); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); @@ -1190,9 +1974,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num < params->line_num_range.max; line_num += 1, line_idx += 1) { - String8 line_text = params->line_text[line_idx]; - F32 line_text_dim = fnt_dim_from_tag_size_string(params->font, params->font_size, 0, params->tab_size, line_text).x + params->line_num_width_px; - line_extras_off[line_idx] = Max(line_text_dim, params->font_size*50); + DR_FStrList line_fstrs = lines_fstrs[line_idx]; + F32 line_text_dim = dr_dim_from_fstrs(params->tab_size, &line_fstrs).x + params->line_num_width_px + params->catchall_margin_width_px + params->priority_margin_width_px; + line_extras_off[line_idx] = Max(line_text_dim, params->font_size*30); } } @@ -1231,12 +2015,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe (stop_event.cause == CTRL_EventCause_InterruptedByException || stop_event.cause == CTRL_EventCause_InterruptedByTrap)) { - DR_FancyStringList explanation_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &stop_event); - UI_Parent(line_extras_boxes[line_idx]) UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) - UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative))) + DR_FStrList explanation_fstrs = rd_stop_explanation_fstrs_from_ctrl_event(scratch.arena, &stop_event); + UI_Parent(line_extras_boxes[line_idx]) UI_PrefWidth(ui_text_dim(10, 1)) UI_TextAlignment(UI_TextAlign_Center) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + UI_TagF("bad_pop") { UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "###exception_info"); - ui_box_equip_display_fancy_strings(box, &explanation_fstrs); + ui_box_equip_display_fstrs(box, &explanation_fstrs); } } } @@ -1254,60 +2038,129 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_num < params->line_num_range.max; line_num += 1, line_idx += 1) { - RD_EntityList pins = params->line_pins[line_idx]; - if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx]) - RD_Font(RD_FontSlot_Code) - UI_FontSize(params->font_size) - UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + RD_CfgList immediate_pins = {0}; + String8 line_text = params->line_text[line_idx]; + for(U64 off = 0, next_off = line_text.size; + off < line_text.size; + off = next_off) { - for(RD_EntityNode *n = pins.first; n != 0; n = n->next) + // rjf: find next opener + String8 markup_opener = str8_lit("raddbg_pin("); + next_off = str8_find_needle(line_text, off, markup_opener, 0); + next_off += markup_opener.size; + + // rjf: extract contents of markup + String8 contents = {0}; + S32 nest = 1; + for(U64 off2 = next_off; off2 < line_text.size; off2 += 1) { - RD_Entity *pin = n->entity; - String8 pin_expr = pin->string; - E_Eval eval = e_eval_from_string(scratch.arena, pin_expr); - String8 eval_string = {0}; - if(!e_type_key_match(e_type_key_zero(), eval.type_key)) + if(line_text.str[off2] == '(') { - EV_ViewRuleList view_rules = {0}; - eval_string = rd_value_string_from_eval(scratch.arena, EV_StringFlag_ReadOnlyDisplayRules, 10, params->font, params->font_size, params->font_size*60.f, eval, &e_member_nil, &view_rules); + nest += 1; } - ui_spacer(ui_em(1.5f, 1.f)); - ui_set_next_pref_width(ui_children_sum(1)); - UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin); - UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos| - UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawBorder, pin_box_key); - UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1)) + else if(line_text.str[off2] == ')') { - Vec4F32 pin_color = rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault); - if(pin->flags & RD_EntityFlag_HasColor) + nest -= 1; + if(nest == 0) { - pin_color = rd_rgba_from_entity(pin); + contents = str8_substr(line_text, r1u64(next_off, off2)); + break; } - UI_PrefWidth(ui_em(1.5f, 1.f)) - RD_Font(RD_FontSlot_Icons) - UI_Palette(ui_build_palette(ui_top_palette(), .text = pin_color)) - UI_TextAlignment(UI_TextAlign_Center) - UI_Flags(UI_BoxFlag_DisableTextTrunc) + } + } + + // rjf: gather arguments + String8List args = {0}; + { + S32 nest = 0; + U64 arg_start_off = 0; + for(U64 contents_off = 0; contents_off <= contents.size; contents_off += 1) + { + if(nest == 0 && (contents_off == contents.size || contents.str[contents_off] == ',')) { - UI_Signal sig = ui_buttonf("%S###pin_nub", rd_icon_kind_text_table[RD_IconKind_Pin]); - if(ui_dragging(sig) && !contains_2f32(sig.box->rect, ui_mouse())) + String8 arg = str8_substr(contents, r1u64(arg_start_off, contents_off)); + arg = str8_skip_chop_whitespace(arg); + str8_list_push(scratch.arena, &args, arg); + arg_start_off = contents_off+1; + } + if(contents_off < contents.size) + { + if(contents.str[contents_off] == '(') { - RD_RegsScope(.entity = rd_handle_from_entity(pin)) rd_drag_begin(RD_RegSlot_Entity); + nest += 1; } - if(ui_right_clicked(sig)) + else if(contents.str[contents_off] == ')') { - RD_RegsScope(.entity = rd_handle_from_entity(pin)) rd_open_ctx_menu(sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0), RD_RegSlot_Entity); + nest -= 1; } } - rd_code_label(0.8f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), pin_expr); - rd_code_label(0.6f, 1, rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), eval_string); } - UI_Signal pin_sig = ui_signal_from_box(pin_box); - if(ui_key_match(pin_box_key, ui_hot_key())) + } + + // rjf: extract fixed arguments + String8 expr_string = {0}; + if(args.first != 0) + { + expr_string = args.first->string; + } + + // rjf: build immediate pin for this markup + if(expr_string.size != 0) + { + RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off); + RD_Cfg *pin = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("watch_pin")); + RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(pin, str8_lit("expression")); + rd_cfg_new_replace(expr, expr_string); + rd_cfg_list_push(scratch.arena, &immediate_pins, pin); + } + } + RD_CfgList pin_lists[] = + { + params->line_pins[line_idx], + immediate_pins, + }; + for EachElement(list_idx, pin_lists) + { + RD_CfgList pins = pin_lists[list_idx]; + if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx]) + RD_Font(RD_FontSlot_Code) + UI_FontSize(params->font_size) + UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + { + for(RD_CfgNode *n = pins.first; n != 0; n = n->next) { - rd_set_hover_eval(v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), str8_zero(), txt_pt(1, 1), 0, pin_expr); + RD_Cfg *pin = n->v; + String8 pin_expr = rd_expr_from_cfg(pin); + E_Eval eval = e_eval_from_string(pin_expr); + String8 eval_string = {0}; + if(!e_type_key_match(e_type_key_zero(), eval.irtree.type_key)) + { + EV_StringParams string_params = {.flags = EV_StringFlag_ReadOnlyDisplayRules, .radix = 10}; + eval_string = rd_value_string_from_eval(scratch.arena, str8_zero(), &string_params, params->font, params->font_size, params->font_size*60.f, eval); + } + ui_spacer(ui_em(1.5f, 1.f)); + ui_set_next_pref_width(ui_children_sum(1)); + UI_Key pin_box_key = ui_key_from_stringf(ui_key_zero(), "###pin_%p", pin); + UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos| + UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder, pin_box_key); + UI_Parent(pin_box) UI_PrefWidth(ui_text_dim(10, 1)) + { + Vec4F32 pin_color = rd_color_from_cfg(pin); + if(pin_color.w == 0) + { + pin_color = ui_color_from_name(str8_lit("text")); + } + Vec4F32 default_code_color = ui_color_from_name(str8_lit("code_default")); + rd_code_label(0.8f, 1, default_code_color, pin_expr); + rd_code_label(0.6f, 1, default_code_color, eval_string); + } + UI_Signal pin_sig = ui_signal_from_box(pin_box); + if(ui_key_match(pin_box_key, ui_hot_key())) + { + rd_set_hover_eval(v2f32(pin_box->rect.x0, pin_box->rect.y1-2.f), pin_expr); + } } } } @@ -1380,13 +2233,10 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe ////////////////////////////// //- rjf: interact with margin box & text box // + B32 search_query_invalidated = 0; UI_Signal priority_margin_container_sig = ui_signal_from_box(priority_margin_container_box); UI_Signal catchall_margin_container_sig = ui_signal_from_box(catchall_margin_container_box); UI_Signal text_container_sig = ui_signal_from_box(text_container_box); - B32 line_drag_drop = 0; - RD_Entity *line_drag_entity = &rd_nil_entity; - CTRL_Entity *line_drag_ctrl_entity = &ctrl_entity_nil; - Vec4F32 line_drag_drop_color = rd_rgba_from_theme_color(RD_ThemeColor_DropSiteOverlay); { //- rjf: determine mouse drag range TxtRng mouse_drag_rng = txt_rng(mouse_pt, mouse_pt); @@ -1430,6 +2280,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe *preferred_column = cursor->column; } + //- rjf: dragging will invalidate the search string, so we don't want to draw it while dragging/releasing + if(ui_dragging(text_container_sig) || ui_released(text_container_sig)) + { + search_query_invalidated = 1; + } + //- rjf: right-click => code context menu if(ui_right_clicked(text_container_sig)) { @@ -1444,70 +2300,57 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe vaddr = params->line_vaddrs[cursor->line - params->line_num_range.min]; lines = params->line_infos[cursor->line - params->line_num_range.min]; } - RD_RegsScope(.cursor = *cursor, - .mark = *mark, - .vaddr = vaddr, - .lines = lines) - { - rd_open_ctx_menu(ui_key_zero(), sub_2f32(ui_mouse(), v2f32(2, 2)), RD_RegSlot_Cursor); - } - } - - //- rjf: dragging threads, breakpoints, or watch pins over this slice -> - // drop target - if(rd_drag_is_active() && contains_2f32(clipped_top_container_rect, ui_mouse())) - { - CTRL_Entity *thread = ctrl_entity_from_handle(d_state->ctrl_entity_store, rd_state->drag_drop_regs->thread); - RD_Entity *entity = rd_entity_from_handle(rd_state->drag_drop_regs->entity); - if(rd_state->drag_drop_regs_slot == RD_RegSlot_Entity && - (entity->kind == RD_EntityKind_WatchPin || - entity->kind == RD_EntityKind_Breakpoint)) - { - line_drag_drop = 1; - line_drag_entity = entity; - if(entity->flags & RD_EntityFlag_HasColor) - { - line_drag_drop_color = rd_rgba_from_entity(entity); - line_drag_drop_color.w *= 0.5f; - } - } - if(rd_state->drag_drop_regs_slot == RD_RegSlot_Thread) - { - line_drag_drop = 1; - line_drag_ctrl_entity = thread; - line_drag_drop_color = rd_rgba_from_ctrl_entity(thread); - line_drag_drop_color.w *= 0.5f; - } + rd_cmd(RD_CmdKind_PushQuery, + .expr = txt_pt_match(*cursor, *mark) ? str8_lit("query:text_pt_commands") : str8_lit("query:text_range_commands"), + .do_implicit_root = 1, + .do_lister = 1, + .ui_key = ui_get_selected_state()->root->key, + .off_px = ui_mouse(), + .cursor = *cursor, + .mark = *mark, + .vaddr = vaddr, + .lines = lines); } //- rjf: drop target is dropped -> process + if(drop_can_hit_lines && ui_key_match(ui_drop_hot_key(), drop_site_key) && rd_drag_drop()) { - if(!rd_entity_is_nil(line_drag_entity) && rd_drag_drop() && contains_1s64(params->line_num_range, mouse_pt.line)) + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Expr) { - RD_Entity *dropped_entity = line_drag_entity; S64 line_num = mouse_pt.line; U64 line_idx = line_num - params->line_num_range.min; U64 line_vaddr = params->line_vaddrs[line_idx]; - rd_cmd(RD_CmdKind_RelocateEntity, - .entity = rd_handle_from_entity(dropped_entity), + rd_cmd(RD_CmdKind_AddWatchPin, + .expr = rd_state->drag_drop_regs->expr, .file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(), .cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0), .vaddr = line_vaddr); } - if(line_drag_ctrl_entity != &ctrl_entity_nil && rd_drag_drop() && contains_1s64(params->line_num_range, mouse_pt.line)) + if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &rd_nil_cfg) { S64 line_num = mouse_pt.line; U64 line_idx = line_num - params->line_num_range.min; U64 line_vaddr = params->line_vaddrs[line_idx]; - CTRL_Entity *thread = line_drag_ctrl_entity; + rd_cmd(RD_CmdKind_RelocateCfg, + .cfg = drop_cfg->id, + .file_path = line_vaddr == 0 ? rd_regs()->file_path : str8_zero(), + .cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0), + .vaddr = line_vaddr); + } + if(drop_thread != &ctrl_entity_nil) + { + S64 line_num = mouse_pt.line; + U64 line_idx = line_num - params->line_num_range.min; + U64 line_vaddr = params->line_vaddrs[line_idx]; + CTRL_Entity *thread = drop_thread; U64 new_rip_vaddr = line_vaddr; if(params->line_vaddrs[line_idx] == 0) { D_LineList *lines = ¶ms->line_infos[line_idx]; for(D_LineNode *n = lines->first; n != 0; n = n->next) { - CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, d_state->ctrl_entity_store, &n->v.dbgi_key); - CTRL_Entity *module = ctrl_module_from_thread_candidates(d_state->ctrl_entity_store, thread, &modules); + CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key); + CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules); if(module != &ctrl_entity_nil) { new_rip_vaddr = ctrl_vaddr_from_voff(module, n->v.voff_range.min); @@ -1590,8 +2433,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe // if(!ui_dragging(text_container_sig) && text_container_sig.event_flags == 0 && mouse_expr.size != 0) { - E_Eval eval = e_eval_from_string(scratch.arena, mouse_expr); - if(eval.msgs.max_kind == E_MsgKind_Null && (eval.mode != E_Mode_Null || mouse_expr_is_explicit)) + E_Eval eval = e_eval_from_string(mouse_expr); + if(eval.msgs.max_kind == E_MsgKind_Null && (eval.irtree.mode != E_Mode_Null || mouse_expr_is_explicit)) { U64 line_vaddr = 0; if(contains_1s64(params->line_num_range, mouse_pt.line)) @@ -1599,24 +2442,25 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe U64 line_idx = mouse_pt.line-params->line_num_range.min; line_vaddr = params->line_vaddrs[line_idx]; } - rd_set_hover_eval(mouse_expr_baseline_pos, rd_regs()->file_path, mouse_pt, line_vaddr, mouse_expr); + rd_set_hover_eval(mouse_expr_baseline_pos, mouse_expr); } } ////////////////////////////// //- rjf: dragging/dropping which applies to lines over this slice -> visualize // - if(line_drag_drop && contains_2f32(clipped_top_container_rect, ui_mouse())) + if(drop_can_hit_lines && ui_key_match(drop_site_key, ui_drop_hot_key())) { DR_Bucket *bucket = dr_bucket_make(); DR_BucketScope(bucket) { - Vec4F32 color = line_drag_drop_color; + Vec4F32 color = drop_color; + color.w *= 0.2f; Rng2F32 drop_line_rect = r2f32p(top_container_box->rect.x0, top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min) * params->line_height_px, top_container_box->rect.x1, top_container_box->rect.y0 + (mouse_pt.line - params->line_num_range.min + 1) * params->line_height_px); - R_Rect2DInst *inst = dr_rect(pad_2f32(drop_line_rect, 8.f), color, 0, 0, 4.f); + R_Rect2DInst *inst = dr_rect(drop_line_rect, color, 0, 0, 1.f); inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(color.x, color.y, color.z, 0); } ui_box_equip_draw_bucket(text_container_box, bucket); @@ -1639,16 +2483,17 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); n->rng = txt_rng(*cursor, *mark); - n->color = ui_top_palette()->colors[UI_ColorCode_Selection]; + n->color = ui_color_from_name(str8_lit("selection")); SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); } // rjf: push for ctrlified mouse expr - if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) + if(ctrlified && !txt_pt_match(result.mouse_expr_rng.max, result.mouse_expr_rng.min)) UI_Tag(str8_lit("pop")) { TxtRngColorPairNode *n = push_array(scratch.arena, TxtRngColorPairNode, 1); n->rng = result.mouse_expr_rng; - n->color = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); + n->color = ui_color_from_name(str8_lit("background")); + n->color.w *= 0.2f; SLLQueuePush(first_txt_rng_color_pair, last_txt_rng_color_pair, n); } } @@ -1672,7 +2517,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe Rng1U64 hover_voff_range = hover_regs->voff_range; if(hover_voff_range.min == 0 && hover_voff_range.max == 0) { - CTRL_Entity *module = ctrl_entity_from_handle(d_state->ctrl_entity_store, hover_regs->module); + CTRL_Entity *module = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, hover_regs->module); hover_voff_range = ctrl_voff_range_from_vaddr_range(module, hover_regs->vaddr_range); } ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); @@ -1689,88 +2534,23 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe { String8 line_string = params->line_text[line_idx]; Rng1U64 line_range = params->line_ranges[line_idx]; - TXT_TokenArray *line_tokens = ¶ms->line_tokens[line_idx]; + DR_FStrList line_fstrs = lines_fstrs[line_idx]; ui_set_next_text_padding(line_num_padding_px); UI_Key line_key = ui_key_from_stringf(top_container_box->key, "ln_%I64x", line_num); Vec4F32 line_bg_color = line_bg_colors[line_idx]; if(line_bg_color.w != 0) { ui_set_next_flags(UI_BoxFlag_DrawBackground); - ui_set_next_palette(ui_build_palette(ui_top_palette(), .background = line_bg_color)); + ui_set_next_background_color(line_bg_color); } ui_set_next_tab_size(params->tab_size); UI_Box *line_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc|UI_BoxFlag_DrawText|UI_BoxFlag_DisableIDString, line_key); DR_Bucket *line_bucket = dr_bucket_make(); dr_push_bucket(line_bucket); - - // rjf: string * tokens -> fancy string list - DR_FancyStringList line_fancy_strings = {0}; - { - if(line_tokens->count == 0) - { - DR_FancyString fstr = - { - params->font, - line_string, - rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault), - params->font_size, - 0, - 0, - }; - dr_fancy_string_list_push(scratch.arena, &line_fancy_strings, &fstr); - } - else - { - TXT_Token *line_tokens_first = line_tokens->v; - TXT_Token *line_tokens_opl = line_tokens->v + line_tokens->count; - for(TXT_Token *token = line_tokens_first; token < line_tokens_opl; token += 1) - { - // rjf: token -> token string - String8 token_string = {0}; - { - Rng1U64 token_range = r1u64(0, line_string.size); - if(token->range.min > line_range.min) - { - token_range.min += token->range.min-line_range.min; - } - if(token->range.max < line_range.max) - { - token_range.max = token->range.max-line_range.min; - } - token_string = str8_substr(line_string, token_range); - } - - // rjf: token -> token color - RD_ThemeColor token_theme_color = rd_theme_color_from_txt_token_kind(token->kind); - RD_ThemeColor lookup_theme_color = rd_theme_color_from_txt_token_kind_lookup_string(token->kind, token_string); - Vec4F32 token_color = rd_rgba_from_theme_color(token_theme_color); - if(lookup_theme_color != RD_ThemeColor_CodeDefault) - { - Vec4F32 lookup_color = rd_rgba_from_theme_color(lookup_theme_color); - F32 lookup_color_mix_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "%S_lookup", token_string), 1.f); - token_color = mix_4f32(token_color, lookup_color, lookup_color_mix_t); - } - - // rjf: push fancy string - DR_FancyString fstr = - { - params->font, - token_string, - token_color, - params->font_size, - 0, - 0, - }; - dr_fancy_string_list_push(scratch.arena, &line_fancy_strings, &fstr); - } - } - } - - // rjf: equip fancy strings to line box - ui_box_equip_display_fancy_strings(line_box, &line_fancy_strings); + ui_box_equip_display_fstrs(line_box, &line_fstrs); // rjf: extra rendering for strings that are currently being searched for - if(params->search_query.size != 0) + if(!search_query_invalidated && params->search_query.size != 0) { for(U64 needle_pos = 0; needle_pos < line_string.size;) { @@ -1790,18 +2570,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe line_box->rect.x0+line_num_padding_px+match_column_pixel_off_range.max+2.f, line_box->rect.y1, }; - Vec4F32 color = rd_rgba_from_theme_color(RD_ThemeColor_HighlightOverlay); - if(cursor->line == line_num && needle_pos+1 <= cursor->column && cursor->column < needle_pos+params->search_query.size+1) - { - color.x += (1.f - color.x) * 0.5f; - color.y += (1.f - color.y) * 0.5f; - color.z += (1.f - color.z) * 0.5f; - color.w += (1.f - color.w) * 0.5f; - } + Vec4F32 color = pop_color; if(!is_focused) { color.w *= 0.5f; } + color.w *= 0.2f; dr_rect(match_rect, color, 4.f, 0, 1.f); needle_pos += 1; } @@ -1866,15 +2640,20 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe S64 column = cursor->column; Vec2F32 advance = fnt_dim_from_tag_size_string(line_box->font, line_box->font_size, 0, params->tab_size, str8_prefix(line_string, column-1)); F32 cursor_off_pixels = advance.x; - F32 cursor_thickness = ClampBot(4.f, line_box->font_size/6.f); + F32 cursor_thickness = ClampBot(1.f, floor_f32(line_box->font_size/10.f)); Rng2F32 cursor_rect = { - ui_box_text_position(line_box).x+cursor_off_pixels-cursor_thickness/2.f, - line_box->rect.y0-params->font_size*0.25f, - ui_box_text_position(line_box).x+cursor_off_pixels+cursor_thickness/2.f, - line_box->rect.y1+params->font_size*0.25f, + ui_box_text_position(line_box).x+cursor_off_pixels, + line_box->rect.y0-params->font_size*0.125f, + ui_box_text_position(line_box).x+cursor_off_pixels+cursor_thickness, + line_box->rect.y1+params->font_size*0.125f, }; - dr_rect(cursor_rect, rd_rgba_from_theme_color(is_focused ? RD_ThemeColor_Cursor : RD_ThemeColor_CursorInactive), 1.f, 0, 1.f); + Vec4F32 cursor_color = ui_color_from_name(str8_lit("cursor")); + if(!is_focused) + { + cursor_color.w *= 0.5f; + } + dr_rect(cursor_rect, cursor_color, 1.f, 0, 0.f); } // rjf: extra rendering for lines with line-info that match the hovered @@ -1899,7 +2678,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe if(matches) { Vec4F32 highlight_color = code_line_bgs[line_info_line_num % ArrayCount(code_line_bgs)]; - highlight_color.w *= 0.25f; + highlight_color.w *= 0.2f; dr_rect(line_box->rect, highlight_color, 0, 0, 0); } } @@ -2115,10 +2894,10 @@ rd_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, Tx //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels -internal UI_Signal -rd_label(String8 string) +internal DR_FStrList +rd_fstrs_from_rich_string(Arena *arena, String8 string) { - Temp scratch = scratch_begin(0, 0); + Temp scratch = scratch_begin(&arena, 1); typedef U32 StringPartFlags; enum { @@ -2156,25 +2935,36 @@ rd_label(String8 string) active_part_flags ^= StringPartFlag_Code; } } - DR_FancyStringList fstrs = {0}; + DR_FStrList fstrs = {0}; for(StringPart *p = first_part; p != 0; p = p->next) { - DR_FancyString fstr = {0}; + DR_FStr fstr = {0}; { - fstr.font = ui_top_font(); fstr.string = p->string; - fstr.color = ui_top_palette()->colors[UI_ColorCode_Text]; - fstr.size = ui_top_font_size(); + fstr.params.font = ui_top_font(); + fstr.params.color = ui_color_from_name(str8_lit("text")); + fstr.params.size = ui_top_font_size(); + fstr.params.raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main); if(p->flags & StringPartFlag_Code) { - fstr.font = rd_font_from_slot(RD_FontSlot_Code); - fstr.color = rd_rgba_from_theme_color(RD_ThemeColor_CodeDefault); + fstr.params.font = rd_font_from_slot(RD_FontSlot_Code); + fstr.params.raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code); + fstr.params.color = rd_rgba_from_code_color_slot(RD_CodeColorSlot_CodeDefault); } } - dr_fancy_string_list_push(scratch.arena, &fstrs, &fstr); + dr_fstrs_push(arena, &fstrs, &fstr); } + scratch_end(scratch); + return fstrs; +} + +internal UI_Signal +rd_label(String8 string) +{ + Temp scratch = scratch_begin(0, 0); + DR_FStrList fstrs = rd_fstrs_from_rich_string(scratch.arena, string); UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &fstrs); + ui_box_equip_display_fstrs(box, &fstrs); UI_Signal sig = ui_signal_from_box(box); scratch_end(scratch); return sig; @@ -2185,13 +2975,12 @@ rd_error_label(String8 string) { UI_Box *box = ui_build_box_from_key(0, ui_key_zero()); UI_Signal sig = ui_signal_from_box(box); - UI_Parent(box) UI_Palette(ui_build_palette(ui_top_palette(), .text = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative), .text_weak = rd_rgba_from_theme_color(RD_ThemeColor_TextNegative))) + UI_Parent(box) { ui_set_next_font(rd_font_from_slot(RD_FontSlot_Icons)); ui_set_next_text_raster_flags(FNT_RasterFlag_Smooth); ui_set_next_text_alignment(UI_TextAlign_Center); - ui_set_next_flags(UI_BoxFlag_DrawTextWeak); - UI_PrefWidth(ui_em(2.25f, 1.f)) ui_label(rd_icon_kind_text_table[RD_IconKind_WarningBig]); + UI_TagF("weak") UI_PrefWidth(ui_em(2.25f, 1.f)) ui_label(rd_icon_kind_text_table[RD_IconKind_WarningBig]); UI_PrefWidth(ui_text_dim(10, 0)) rd_label(string); } return sig; @@ -2223,20 +3012,20 @@ rd_help_label(String8 string) return result; } -internal DR_FancyStringList -rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string) +internal DR_FStrList +rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - DR_FancyStringList fancy_strings = {0}; + DR_FStrList fstrs = {0}; TXT_TokenArray tokens = txt_token_array_from_string__c_cpp(scratch.arena, 0, string); TXT_Token *tokens_opl = tokens.v+tokens.count; S32 indirection_counter = 0; indirection_size_change = 0; for(TXT_Token *token = tokens.v; token < tokens_opl; token += 1) { - RD_ThemeColor token_color = rd_theme_color_from_txt_token_kind(token->kind); - Vec4F32 token_color_rgba = rd_rgba_from_theme_color(token_color); + RD_CodeColorSlot token_color_slot = rd_code_color_slot_from_txt_token_kind(token->kind); + Vec4F32 token_color_rgba = rd_rgba_from_code_color_slot(token_color_slot); token_color_rgba.w *= alpha; String8 token_string = str8_substr(string, token->range); if(str8_match(token_string, str8_lit("{"), 0)) { indirection_counter += 1; } @@ -2246,37 +3035,43 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s { default: { - DR_FancyString fancy_string = + DR_FStr fstr = { - ui_top_font(), token_string, - token_color_rgba, - ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)), + { + ui_top_font(), + ui_top_text_raster_flags(), + token_color_rgba, + ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)), + } }; - dr_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + dr_fstrs_push(arena, &fstrs, &fstr); }break; case TXT_TokenKind_Identifier: case TXT_TokenKind_Keyword: { - RD_ThemeColor lookup_theme_color = rd_theme_color_from_txt_token_kind_lookup_string(token->kind, token_string); - if(lookup_theme_color != RD_ThemeColor_CodeDefault) + RD_CodeColorSlot lookup_theme_color_slot = rd_code_color_slot_from_txt_token_kind_lookup_string(token->kind, token_string); + if(lookup_theme_color_slot != RD_CodeColorSlot_CodeDefault) { - Vec4F32 lookup_color = rd_rgba_from_theme_color(lookup_theme_color); + Vec4F32 lookup_color = rd_rgba_from_code_color_slot(lookup_theme_color_slot); F32 lookup_color_mix_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "%S_lookup", token_string), 1.f); token_color_rgba = mix_4f32(token_color_rgba, lookup_color, lookup_color_mix_t); } - DR_FancyString fancy_string = + DR_FStr fstr = { - ui_top_font(), token_string, - token_color_rgba, - ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)), + { + ui_top_font(), + ui_top_text_raster_flags(), + token_color_rgba, + ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)), + }, }; - dr_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + dr_fstrs_push(arena, &fstrs, &fstr); }break; case TXT_TokenKind_Numeric: { - Vec4F32 token_color_rgba_alt = rd_rgba_from_theme_color(RD_ThemeColor_CodeNumericAltDigitGroup); + Vec4F32 token_color_rgba_alt = rd_rgba_from_code_color_slot(RD_CodeColorSlot_CodeNumericAltDigitGroup); token_color_rgba_alt.w *= alpha; F32 font_size = ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)); @@ -2318,14 +3113,17 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s // rjf: push prefix { - DR_FancyString fancy_string = + DR_FStr fstr = { - ui_top_font(), prefix, - token_color_rgba, - font_size, + { + ui_top_font(), + ui_top_text_raster_flags(), + token_color_rgba, + font_size, + }, }; - dr_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + dr_fstrs_push(arena, &fstrs, &fstr); } // rjf: push digit groups @@ -2341,14 +3139,17 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s num_digits_passed = 0; if(start_idx < idx) { - DR_FancyString fancy_string = + DR_FStr fstr = { - ui_top_font(), str8_substr(whole, r1u64(start_idx, idx)), - odd ? token_color_rgba_alt : token_color_rgba, - font_size, + { + ui_top_font(), + ui_top_text_raster_flags(), + odd ? token_color_rgba_alt : token_color_rgba, + font_size, + }, }; - dr_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + dr_fstrs_push(arena, &fstrs, &fstr); start_idx = idx; odd ^= 1; } @@ -2362,14 +3163,17 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s // rjf: push decimal { - DR_FancyString fancy_string = + DR_FStr fstr = { - ui_top_font(), decimal, - token_color_rgba, - font_size, + { + ui_top_font(), + ui_top_text_raster_flags(), + token_color_rgba, + font_size, + }, }; - dr_fancy_string_list_push(arena, &fancy_strings, &fancy_string); + dr_fstrs_push(arena, &fstrs, &fstr); } }break; @@ -2380,16 +3184,16 @@ rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s } scratch_end(scratch); ProfEnd(); - return fancy_strings; + return fstrs; } internal UI_Box * rd_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string) { Temp scratch = scratch_begin(0, 0); - DR_FancyStringList fancy_strings = rd_fancy_string_list_from_code_string(scratch.arena, alpha, indirection_size_change, base_color, string); + DR_FStrList fstrs = rd_fstrs_from_code_string(scratch.arena, alpha, indirection_size_change, base_color, string); UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); - ui_box_equip_display_fancy_strings(box, &fancy_strings); + ui_box_equip_display_fstrs(box, &fstrs); scratch_end(scratch); return box; } @@ -2398,17 +3202,24 @@ rd_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String //~ rjf: UI Widgets: Line Edit internal UI_Signal -rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, String8 string) +rd_cell(RD_CellParams *params, String8 string) { ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + ////////////////////////////// //- rjf: unpack visual metrics - F32 expander_size_px = ui_top_font_size()*2.f; + // + F32 expander_size_px = floor_f32(ui_top_font_size()*2.f); + ////////////////////////////// //- rjf: make key + // UI_Key key = ui_key_from_string(ui_active_seed_key(), string); + ////////////////////////////// //- rjf: calculate & push focus + // B32 is_auto_focus_hot = ui_is_key_auto_focus_hot(key); B32 is_auto_focus_active = ui_is_key_auto_focus_active(key); if(is_auto_focus_hot) { ui_push_focus_hot(UI_FocusKind_On); } @@ -2418,64 +3229,449 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx B32 is_focus_hot_disabled = (!is_focus_hot && ui_top_focus_hot() == UI_FocusKind_On); B32 is_focus_active_disabled = (!is_focus_active && ui_top_focus_active() == UI_FocusKind_On); + ////////////////////////////// + //- rjf: determine which sub-cell components we'll build + // + // (the base line edit textual label / editor is always built, but this can be enriched + // with extra widgets & metadata) + // + B32 build_toggle_switch = !!(params->flags & RD_CellFlag_ToggleSwitch) && !is_focus_active; + B32 build_slider = !!(params->flags & RD_CellFlag_Slider) && !is_focus_active; + B32 build_bindings = !!(params->flags & RD_CellFlag_Bindings) && !is_focus_active; + B32 build_lhs_name_desc = (params->meta_fstrs.node_count != 0 || params->description.size != 0); + B32 build_line_edit = (params->pre_edit_value.size != 0 || params->value_fstrs.node_count != 0); + DR_FStrList lhs_name_fstrs = params->meta_fstrs; + DR_FStrList value_name_fstrs = params->value_fstrs; + + ////////////////////////////// + //- rjf: determine autocompletion string + // + String8 autocomplete_hint_string = {0}; + if(is_focus_active) + { + autocomplete_hint_string = ui_autocomplete_string(); + } + + ////////////////////////////// //- rjf: build top-level box + // if(is_focus_active || is_focus_active_disabled) { ui_set_next_hover_cursor(OS_Cursor_IBar); } UI_Box *box = ui_build_box_from_key(UI_BoxFlag_MouseClickable| - (!!(flags & RD_LineEditFlag_KeyboardClickable)*UI_BoxFlag_KeyboardClickable)| + (!!build_lhs_name_desc*UI_BoxFlag_DisableFocusBorder)| + (!!(params->flags & RD_CellFlag_KeyboardClickable)*UI_BoxFlag_KeyboardClickable)| UI_BoxFlag_ClickToFocus| - UI_BoxFlag_DrawHotEffects| - (!(flags & RD_LineEditFlag_NoBackground)*UI_BoxFlag_DrawBackground)| - (!!(flags & RD_LineEditFlag_Border)*UI_BoxFlag_DrawBorder)| + (!!(params->flags & RD_CellFlag_Button)*UI_BoxFlag_DrawHotEffects)| + (!!(params->flags & RD_CellFlag_SingleClickActivate)*UI_BoxFlag_DrawActiveEffects)| + (!(params->flags & RD_CellFlag_NoBackground)*UI_BoxFlag_DrawBackground)| + (!!(params->flags & RD_CellFlag_Border)*UI_BoxFlag_DrawBorder)| ((is_auto_focus_hot || is_auto_focus_active)*UI_BoxFlag_KeyboardClickable)| (is_focus_active || is_focus_active_disabled)*(UI_BoxFlag_Clip), key); + ////////////////////////////// //- rjf: build indent - UI_Parent(box) for(S32 idx = 0; idx < depth; idx += 1) + // + UI_Parent(box) for(S32 idx = 0; idx < params->depth; idx += 1) { ui_set_next_flags(UI_BoxFlag_DrawSideLeft); ui_spacer(ui_em(1.f, 1.f)); } - //- rjf: build expander - if(flags & RD_LineEditFlag_Expander) UI_PrefWidth(ui_px(expander_size_px, 1.f)) UI_Parent(box) - UI_Flags(UI_BoxFlag_DrawSideLeft) - UI_Focus(UI_FocusKind_Off) + ////////////////////////////// + //- rjf: build expander (or placeholder, or space) + // { - UI_Signal expander_sig = ui_expanderf(*expanded_out, "expander"); - if(ui_pressed(expander_sig)) + //- rjf: build expander + if(params->flags & RD_CellFlag_Expander) UI_PrefWidth(ui_px(expander_size_px, 1.f)) UI_Parent(box) + UI_Flags(UI_BoxFlag_DrawSideLeft) + UI_Focus(UI_FocusKind_Off) { - *expanded_out ^= 1; + UI_Signal expander_sig = ui_expanderf(params->expanded_out[0], "expander"); + if(ui_pressed(expander_sig)) + { + params->expanded_out[0] ^= 1; + } + } + + //- rjf: build expander placeholder + else if(params->flags & RD_CellFlag_ExpanderPlaceholder) UI_Parent(box) UI_PrefWidth(ui_px(expander_size_px, 1.f)) UI_Focus(UI_FocusKind_Off) + { + UI_TagF("weak") + UI_Flags(UI_BoxFlag_DrawSideLeft) + RD_Font(RD_FontSlot_Icons) + UI_TextAlignment(UI_TextAlign_Center) + ui_label(rd_icon_kind_text_table[RD_IconKind_Dot]); + } + + //- rjf: build expander space + else if(params->flags & RD_CellFlag_ExpanderSpace) UI_Parent(box) UI_Focus(UI_FocusKind_Off) + { + UI_Flags(UI_BoxFlag_DrawSideLeft) ui_spacer(ui_px(expander_size_px, 1.f)); } } - //- rjf: build expander placeholder - else if(flags & RD_LineEditFlag_ExpanderPlaceholder) UI_Parent(box) UI_PrefWidth(ui_px(expander_size_px, 1.f)) UI_Focus(UI_FocusKind_Off) + ////////////////////////////// + //- rjf: build left-hand-side container box + // + UI_Box *lhs_box = &ui_nil_box; + if(build_lhs_name_desc) { - UI_FlagsAdd(UI_BoxFlag_DrawTextWeak) - UI_Flags(UI_BoxFlag_DrawSideLeft) - RD_Font(RD_FontSlot_Icons) - UI_TextAlignment(UI_TextAlign_Center) - ui_label(rd_icon_kind_text_table[RD_IconKind_Dot]); + UI_Parent(box) UI_WidthFill UI_ChildLayoutAxis(Axis2_Y) + { + if(ui_top_text_alignment() == UI_TextAlign_Left && (params->flags & (RD_CellFlag_Expander|RD_CellFlag_ExpanderSpace|RD_CellFlag_ExpanderPlaceholder)) == 0) + { + ui_spacer(ui_em(1.f, 1.f)); + } + lhs_box = ui_build_box_from_stringf(0, "lhs_box"); + } } - //- rjf: build expander space - else if(flags & RD_LineEditFlag_ExpanderSpace) UI_Parent(box) UI_Focus(UI_FocusKind_Off) + ////////////////////////////// + //- rjf: build left-hand-side name/desc box + // + if(build_lhs_name_desc) UI_Parent(lhs_box) UI_Padding(ui_em(3.f, 0.f)) UI_WidthFill UI_HeightFill { - UI_Flags(UI_BoxFlag_DrawSideLeft) ui_spacer(ui_px(expander_size_px, 1.f)); + FuzzyMatchRangeList fuzzy_matches = {0}; + if(params->search_needle.size != 0) + { + fuzzy_matches = dr_fuzzy_match_find_from_fstrs(scratch.arena, &lhs_name_fstrs, params->search_needle); + } + UI_Row + { + UI_Box *name_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); + ui_box_equip_display_fstrs(name_box, &lhs_name_fstrs); + ui_box_equip_fuzzy_match_ranges(name_box, &fuzzy_matches); + } + if(params->description.size != 0) RD_Font(RD_FontSlot_Main) UI_FontSize(ui_top_font_size()*0.85f) + { + UI_Row + { + UI_Box *desc_box = ui_label(params->description).box; + FuzzyMatchRangeList desc_fuzzy_matches = fuzzy_match_find(scratch.arena, params->search_needle, params->description); + ui_box_equip_fuzzy_match_ranges(desc_box, &desc_fuzzy_matches); + } + } } + ////////////////////////////// + //- rjf: build line edit container box + // + UI_Box *edit_box = &ui_nil_box; + if((is_focus_active || is_focus_active_disabled) || build_line_edit) + UI_Parent(box) + { + B32 is_editing = (is_focus_active || is_focus_active_disabled); + UI_Size edit_box_size = ui_pct(1, 0); + if(build_lhs_name_desc) + { + if(is_editing) + { + edit_box_size = ui_px(floor_f32(dim_2f32(box->rect).x*0.5f), 1.f); + } + else + { + edit_box_size = ui_children_sum(1); + } + } + UI_PrefWidth(edit_box_size) + { + if(ui_top_px_height() > ui_top_font_size()*3.f) + { + ui_set_next_pref_width(ui_children_sum(1)); + UI_Column UI_Padding(ui_em(1, 0)) UI_Focus(UI_FocusKind_On) + { + UI_PrefHeight(ui_em(3.f, 1.f)) UI_CornerRadius(ui_top_font_size()*0.5f) + edit_box = ui_build_box_from_stringf((!!is_editing*UI_BoxFlag_DrawBorder)| + UI_BoxFlag_Clickable| + UI_BoxFlag_DisableFocusOverlay, + "edit_box"); + if(params->line_edit_key_out) + { + params->line_edit_key_out[0] = edit_box->key; + } + } + if(ui_top_text_alignment() == UI_TextAlign_Left) + { + ui_spacer(ui_em(1.f, 1.f)); + } + } + else + { + edit_box = ui_build_box_from_stringf(0, "edit_box"); + if(params->line_edit_key_out) + { + params->line_edit_key_out[0] = edit_box->key; + } + } + } + } + + ////////////////////////////// + //- rjf: build edit-button, if line edit is embedded, and has no string + // + B32 edit_started = 0; + if(params->flags & RD_CellFlag_EmptyEditButton && !is_focus_active && !is_focus_active_disabled && build_lhs_name_desc && build_line_edit && value_name_fstrs.total_size == 0) + { + UI_TagF(".") + UI_TagF("weak") + UI_TagF("implicit") + UI_Parent(box) + UI_PrefWidth(ui_em(2.f, 1.f)) + { + UI_Column + UI_Padding(ui_pct(1, 0)) + UI_PrefHeight(ui_em(2.f, 1.f)) + UI_CornerRadius(ui_top_font_size()*0.5f) + RD_Font(RD_FontSlot_Icons) + UI_TextAlignment(UI_TextAlign_Center) + { + UI_Box *edit_start_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DisableFocusBorder| + UI_BoxFlag_Clickable, + "%S##edit", rd_icon_kind_text_table[RD_IconKind_Pencil]); + UI_Signal sig = ui_signal_from_box(edit_start_box); + if(ui_pressed(sig)) + { + edit_started = 1; + } + } + ui_spacer(ui_em(1.f, 1.f)); + } + } + + ////////////////////////////// //- rjf: build scrollable container box + // UI_Box *scrollable_box = &ui_nil_box; - UI_Parent(box) UI_PrefWidth(ui_children_sum(0)) + if(edit_box != &ui_nil_box) { - scrollable_box = ui_build_box_from_stringf(is_focus_active*(UI_BoxFlag_AllowOverflowX), "scroll_box_%p", edit_buffer); + UI_Parent(edit_box) UI_PrefWidth(ui_children_sum(0)) + { + scrollable_box = ui_build_box_from_stringf(is_focus_active*(UI_BoxFlag_AllowOverflowX), "scroll_box_%p", params->edit_buffer); + } } + ////////////////////////////// + //- rjf: build revert-button + // + if(params->flags & RD_CellFlag_RevertButton && !is_focus_active && !is_focus_active_disabled) + { + UI_Parent(edit_box) + UI_PrefWidth(ui_em(2.f, 1.f)) + { + UI_TagF(".") + UI_TagF("weak") + UI_TagF("implicit") + UI_Column + UI_Padding(ui_pct(1, 0)) + UI_PrefHeight(ui_em(2.f, 1.f)) + UI_CornerRadius(ui_top_font_size()*0.5f) + RD_Font(RD_FontSlot_Icons) + UI_TextAlignment(UI_TextAlign_Center) + { + UI_Box *revert_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DisableFocusOverlay| + UI_BoxFlag_DisableFocusBorder| + UI_BoxFlag_Clickable, + "%S##revert", rd_icon_kind_text_table[RD_IconKind_Undo]); + UI_Signal sig = ui_signal_from_box(revert_box); + if(ui_pressed(sig) && params->revert_out) + { + params->revert_out[0] = 1; + } + } + // TODO(rjf): @hack + if(build_toggle_switch || build_slider) + { + ui_spacer(ui_em(1.f, 1.f)); + } + } + } + + ////////////////////////////// + //- rjf: build toggle-switch + // + if(build_toggle_switch) UI_Parent(box) + { + B32 is_toggled = !!params->toggled_out[0]; + F32 toggle_t = ui_anim(ui_key_from_stringf(key, "toggled"), (F32)is_toggled, .initial = (F32)is_toggled, .rate = rd_state->menu_animation_rate); + F32 height_px = ceil_f32(ui_top_font_size() * 1.75f); + F32 padding_px = ceil_f32((ui_top_px_height() - height_px) / 2.f); + UI_PrefWidth(ui_children_sum(1.f)) + UI_HeightFill + UI_Column UI_Padding(ui_px(padding_px, 1.f)) + UI_Row + { + if(ui_top_text_alignment() == UI_TextAlign_Center) + { + ui_spacer(ui_em(1.f, 0.f)); + } + UI_PrefWidth(ui_em(3.5f, 1.f)) + UI_PrefHeight(ui_px(height_px, 1.f)) + UI_CornerRadius(floor_f32(height_px/2.f - 1.f)) + UI_TagF(is_toggled ? "good_pop" : "") + UI_GroupKey(ui_key_from_stringf(ui_key_zero(), "toggle_switch_group_key")) + { + UI_Box *switch_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "toggle_switch"); + UI_Parent(switch_box) + { + RD_Font(RD_FontSlot_Icons) UI_PrefWidth(ui_pct(toggle_t, 0)) UI_Transparency(1.f - toggle_t) + { + ui_build_box_from_stringf(UI_BoxFlag_DisableTextTrunc | (toggle_t > 0.001f ? UI_BoxFlag_DrawText : 0), + "%S", rd_icon_kind_text_table[RD_IconKind_Check]); + } + UI_BackgroundColor(ui_color_from_name(str8_lit("text"))) + UI_PrefWidth(ui_px(height_px, 1.f)) + { + F32 extratoggler_padding_px = floor_f32(ui_top_font_size()*0.35f); + F32 toggler_size_px = ceil_f32(height_px - extratoggler_padding_px*2.f) - 1.f; + UI_Column UI_Padding(ui_px(extratoggler_padding_px, 1.f)) + UI_Row UI_Padding(ui_px(extratoggler_padding_px, 1.f)) + UI_PrefWidth(ui_px(toggler_size_px, 1.f)) + UI_PrefHeight(ui_px(toggler_size_px, 1.f)) + UI_CornerRadius(floor_f32(toggler_size_px/2.f - 1.f)) + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, ui_key_zero()); + } + } + ui_spacer(ui_pct(1.f-toggle_t, 0)); + } + UI_Signal switch_sig = ui_signal_from_box(switch_box); + + // rjf: press -> toggle, & gather this key + if(ui_pressed(switch_sig)) + { + if(ui_dragging(switch_sig)) + { + ui_store_drag_struct(&switch_box->key); + } + params->toggled_out[0] ^= 1; + } + + // rjf: dragging -> check if key is in batch of touched keys. if so, do nothing, otherwise, toggle. + // always store this new key if not in batch + if(ui_dragging(switch_sig)) + { + String8 all_keys_data = ui_get_drag_data(sizeof(UI_Key)); + UI_Key *keys = (UI_Key *)all_keys_data.str; + U64 keys_count = all_keys_data.size / sizeof(UI_Key); + B32 key_is_touched = 0; + for EachIndex(idx, keys_count) + { + if(ui_key_match(keys[idx], switch_box->key)) + { + key_is_touched = 1; + break; + } + } + if(!key_is_touched) + { + params->toggled_out[0] ^= 1; + UI_Key *new_keys = push_array(scratch.arena, UI_Key, keys_count+1); + MemoryCopy(new_keys, keys, sizeof(UI_Key)*keys_count); + new_keys[keys_count] = switch_box->key; + ui_store_drag_data(str8((U8 *)new_keys, sizeof(UI_Key) * (keys_count+1))); + } + } + } + if(ui_top_text_alignment() == UI_TextAlign_Center) + { + ui_spacer(ui_em(1.f, 0.f)); + } + } + if(ui_top_text_alignment() == UI_TextAlign_Left) + { + ui_spacer(ui_em(1.f, 1.f)); + } + } + + ////////////////////////////// + //- rjf: build slider + // + if(build_slider) UI_Parent(box) + { + F32 height_px = ceil_f32(ui_top_font_size() * 1.75f); + F32 padding_px = ceil_f32((ui_top_px_height() - height_px) / 2.f); + UI_PrefWidth(ui_children_sum(1.f)) + UI_HeightFill + UI_Column UI_Padding(ui_px(padding_px, 1.f)) + UI_Row + UI_PrefWidth(ui_pct(0.5f - 0.2f*(!!build_lhs_name_desc), 0.f)) + UI_PrefHeight(ui_px(height_px, 1.f)) + UI_CornerRadius(floor_f32(height_px/2.f - 1.f)) + { + F32 extratoggler_padding_px = floor_f32(ui_top_font_size()*0.35f); + F32 toggler_size_px = ceil_f32(height_px - extratoggler_padding_px*2.f) - 1.f; + ui_set_next_hover_cursor(OS_Cursor_LeftRight); + UI_Box *slider_box = ui_build_box_from_stringf(UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "slider"); + UI_Parent(slider_box) UI_TagF("pop") + { + UI_Signal sig = ui_signal_from_box(slider_box); + if(ui_dragging(sig)) + { + if(ui_pressed(sig)) + { + ui_store_drag_struct(params->slider_value_out); + } + F32 draggable_region_size_px = dim_2f32(slider_box->rect).x - (extratoggler_padding_px*2 + toggler_size_px); + F32 initial_pct = *ui_get_drag_struct(F32); + F32 current_pct = initial_pct + (ui_drag_delta().x / draggable_region_size_px); + params->slider_value_out[0] = current_pct; + } + + UI_Box *fill_box = &ui_nil_box; + UI_PrefWidth(ui_children_sum(0)) + UI_MinWidth(toggler_size_px + extratoggler_padding_px*2) + fill_box = ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, ui_key_zero()); + UI_Parent(fill_box) + { + ui_spacer(ui_pct(Clamp(0, params->slider_value_out[0], 1), 0.f)); + UI_BackgroundColor(ui_color_from_name(str8_lit("text"))) + UI_PrefWidth(ui_px(height_px, 1.f)) + { + UI_Column UI_Padding(ui_px(extratoggler_padding_px, 1.f)) + UI_Row UI_Padding(ui_px(extratoggler_padding_px, 1.f)) + UI_PrefWidth(ui_px(toggler_size_px, 1.f)) + UI_PrefHeight(ui_px(toggler_size_px, 1.f)) + UI_CornerRadius(floor_f32(toggler_size_px/2.f - 1.f)) + { + ui_build_box_from_key(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawDropShadow, ui_key_zero()); + } + } + } + ui_spacer(ui_pct(1-Clamp(0, params->slider_value_out[0], 1), 0.f)); + } + } + ui_spacer(ui_em(1.f, 1.f)); + } + + ////////////////////////////// + //- rjf: build bindings + // + if(build_bindings) UI_Parent(box) RD_Font(RD_FontSlot_Main) UI_PermissionFlags(UI_PermissionFlag_Clicks) + { + UI_PrefWidth(ui_children_sum(1)) UI_Column UI_Padding(ui_px(ui_top_px_height()*0.2f, 1.f)) UI_HeightFill + { + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_Padding(ui_em(1.f, 1.f)) + { + rd_cmd_binding_buttons(params->bindings_name, params->search_needle, 1); + } + } + } + + ////////////////////////////// //- rjf: do non-textual edits (delete, copy, cut) + // B32 commit = 0; if(!is_focus_active && is_focus_hot) { @@ -2483,24 +3679,28 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx { if(evt->flags & UI_EventFlag_Copy) { - os_set_clipboard_text(pre_edit_value); + os_set_clipboard_text(params->pre_edit_value); } if(evt->flags & UI_EventFlag_Delete) { commit = 1; - edit_string_size_out[0] = 0; + params->edit_string_size_out[0] = 0; } } } + ////////////////////////////// //- rjf: get signal + // UI_Signal sig = ui_signal_from_box(box); if(commit) { sig.f |= UI_SignalFlag_Commit; } + ////////////////////////////// //- rjf: do start/end editing interaction + // B32 focus_started = 0; if(!is_focus_active) { @@ -2523,14 +3723,17 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx } if(start_editing_via_sig || start_editing_via_typing) { - String8 edit_string = pre_edit_value; - edit_string.size = Min(edit_buffer_size, pre_edit_value.size); - MemoryCopy(edit_buffer, edit_string.str, edit_string.size); - edit_string_size_out[0] = edit_string.size; + String8 edit_string = params->pre_edit_value; + edit_string.size = Min(params->edit_buffer_size, params->pre_edit_value.size); + MemoryCopy(params->edit_buffer, edit_string.str, edit_string.size); + params->edit_string_size_out[0] = edit_string.size; ui_set_auto_focus_active_key(key); - ui_kill_action(); - *cursor = txt_pt(1, edit_string.size+1); - *mark = txt_pt(1, 1); + if(!(params->flags & RD_CellFlag_Button)) + { + ui_kill_action(); + } + params->cursor[0] = txt_pt(1, edit_string.size+1); + params->mark[0] = txt_pt(1, 1); focus_started = 1; } } @@ -2540,49 +3743,47 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx sig.f |= UI_SignalFlag_Commit; } - //- rjf: determine autocompletion string - String8 autocomplete_hint_string = {0}; - { - for(UI_Event *evt = 0; ui_next_event(&evt);) - { - if(evt->kind == UI_EventKind_AutocompleteHint) - { - autocomplete_hint_string = evt->string; - } - } - } - + ////////////////////////////// //- rjf: take navigation actions for editing + // B32 changes_made = 0; - if(!(flags & RD_LineEditFlag_DisableEdit) && (is_focus_active || focus_started)) + if(!(params->flags & RD_CellFlag_DisableEdit) && (is_focus_active || focus_started)) { Temp scratch = scratch_begin(0, 0); rd_state->text_edit_mode = 1; for(UI_Event *evt = 0; ui_next_event(&evt);) { - String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); + String8 edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); // rjf: do not consume anything that doesn't fit a single-line's operations - if((evt->kind != UI_EventKind_Edit && evt->kind != UI_EventKind_Navigate && evt->kind != UI_EventKind_Text) || evt->delta_2s32.y != 0) + B32 is_autocompletion_completion = (autocomplete_hint_string.size != 0 && + evt->kind == UI_EventKind_Press && + evt->slot == UI_EventActionSlot_Accept); + if(!is_autocompletion_completion && + ((evt->kind != UI_EventKind_Edit && + evt->kind != UI_EventKind_Navigate && + evt->kind != UI_EventKind_Text) || + evt->delta_2s32.y != 0)) { continue; } // rjf: map this action to an op - UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, *cursor, *mark); + UI_TxtOp op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); - // rjf: any valid op & autocomplete hint? -> perform autocomplete first, then re-compute op - if(autocomplete_hint_string.size != 0) + // rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op + if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0) { - String8 word_query = rd_autocomp_query_word_from_input_string_off(edit_string, cursor->column-1); - U64 word_off = (U64)(word_query.str - edit_string.str); - String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(word_off+1, word_off+1+word_query.size), autocomplete_hint_string); - new_string.size = Min(edit_buffer_size, new_string.size); - MemoryCopy(edit_buffer, new_string.str, new_string.size); - edit_string_size_out[0] = new_string.size; - *cursor = *mark = txt_pt(1, word_off+1+autocomplete_hint_string.size); - edit_string = str8(edit_buffer, edit_string_size_out[0]); - op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, *cursor, *mark); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; + String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_hint_string); + new_string.size = Min(params->edit_buffer_size, new_string.size); + MemoryCopy(params->edit_buffer, new_string.str, new_string.size); + params->edit_string_size_out[0] = new_string.size; + params->cursor[0] = params->mark[0] = txt_pt(1, 1+autocomp_cursor_info->replaced_range.min+autocomplete_hint_string.size); + edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); + op = ui_single_line_txt_op_from_event(scratch.arena, evt, edit_string, params->cursor[0], params->mark[0]); MemoryZeroStruct(&autocomplete_hint_string); } @@ -2590,9 +3791,9 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx if(!txt_pt_match(op.range.min, op.range.max) || op.replace.size != 0) { String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(op.range.min.column, op.range.max.column), op.replace); - new_string.size = Min(edit_buffer_size, new_string.size); - MemoryCopy(edit_buffer, new_string.str, new_string.size); - edit_string_size_out[0] = new_string.size; + new_string.size = Min(params->edit_buffer_size, new_string.size); + MemoryCopy(params->edit_buffer, new_string.str, new_string.size); + params->edit_string_size_out[0] = new_string.size; } // rjf: perform copy @@ -2602,87 +3803,83 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx } // rjf: commit op's changed cursor & mark to caller-provided state - *cursor = op.cursor; - *mark = op.mark; + params->cursor[0] = op.cursor; + params->mark[0] = op.mark; // rjf: consume event { - ui_eat_event(evt); + if(!is_autocompletion_completion) + { + ui_eat_event(evt); + } changes_made = 1; } } scratch_end(scratch); } - //- rjf: build scrolled contents - TxtPt mouse_pt = {0}; - F32 cursor_off = 0; - UI_Parent(scrollable_box) + ////////////////////////////// + //- rjf: click-driven "start editing" + // + if(edit_started) { - if(!is_focus_active && !is_focus_active_disabled && flags & RD_LineEditFlag_CodeContents) + sig.f |= UI_SignalFlag_DoubleClicked; + } + + ////////////////////////////// + //- rjf: compute editable fancy strings + // + DR_FStrList fstrs = {0}; + { + //- rjf: (not editing) + if(!is_focus_active && !is_focus_active_disabled && value_name_fstrs.total_size != 0) { - String8 display_string = ui_display_part_from_key_string(string); - if(!(flags & RD_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0) + fstrs = value_name_fstrs; + } + else if(!is_focus_active && !is_focus_active_disabled && params->flags & RD_CellFlag_CodeContents && params->pre_edit_value.size != 0) + { + String8 display_string = params->pre_edit_value; + fstrs = rd_fstrs_from_code_string(scratch.arena, 1, 0, ui_color_from_name(str8_lit("text")), display_string); + } + else if(!is_focus_active && !is_focus_active_disabled) + { + String8 display_string = params->pre_edit_value; + if(params->pre_edit_value.size == 0) { - display_string = pre_edit_value; - UI_Box *box = rd_code_label(1.f, 1, ui_top_palette()->text, display_string); - if(matches != 0) - { - ui_box_equip_fuzzy_match_ranges(box, matches); - } + display_string = ui_display_part_from_key_string(string); } - else if(flags & RD_LineEditFlag_DisplayStringIsCode) + UI_TagF("weak") { - UI_Box *box = rd_code_label(1.f, 1, ui_top_palette()->text, display_string); - if(matches != 0) - { - ui_box_equip_fuzzy_match_ranges(box, matches); - } + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + dr_fstrs_push_new(scratch.arena, &fstrs, ¶ms, display_string); + } + } + + //- rjf: (editing) + else if(is_focus_active || is_focus_active_disabled) + { + String8 edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); + DR_FStrList edit_string_fstrs = {0}; + if(params->flags & RD_CellFlag_CodeContents) + { + edit_string_fstrs = rd_fstrs_from_code_string(scratch.arena, 1.f, 0, ui_color_from_name(str8_lit("text")), edit_string); } else { - ui_set_next_flags(UI_BoxFlag_DrawTextWeak); - UI_Box *box = ui_label(display_string).box; - if(matches != 0) - { - ui_box_equip_fuzzy_match_ranges(box, matches); - } + String8 edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); + DR_FStrParams params = {ui_top_font(), ui_top_text_raster_flags(), ui_color_from_name(str8_lit("text")), ui_top_font_size()}; + dr_fstrs_push_new(scratch.arena, &edit_string_fstrs, ¶ms, edit_string); } - } - else if(!is_focus_active && !is_focus_active_disabled && !(flags & RD_LineEditFlag_CodeContents)) - { - String8 display_string = ui_display_part_from_key_string(string); - if(!(flags & RD_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0) - { - display_string = pre_edit_value; - } - else - { - ui_set_next_flags(UI_BoxFlag_DrawTextWeak); - } - UI_Box *box = ui_label(display_string).box; - if(matches != 0) - { - ui_box_equip_fuzzy_match_ranges(box, matches); - } - } - else if((is_focus_active || is_focus_active_disabled) && flags & RD_LineEditFlag_CodeContents) - { - String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); - Temp scratch = scratch_begin(0, 0); - F32 total_text_width = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), edit_string).x; - F32 total_editstr_width = total_text_width - !!(flags & (RD_LineEditFlag_Expander|RD_LineEditFlag_ExpanderSpace|RD_LineEditFlag_ExpanderPlaceholder)) * expander_size_px; - ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); - UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); - DR_FancyStringList code_fancy_strings = rd_fancy_string_list_from_code_string(scratch.arena, 1.f, 0, ui_top_palette()->text, edit_string); if(autocomplete_hint_string.size != 0) { - String8 query_word = rd_autocomp_query_word_from_input_string_off(edit_string, cursor->column-1); - String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, query_word.size); + RD_Cfg *window = rd_cfg_from_id(rd_regs()->window); + RD_WindowState *ws = rd_window_state_from_cfg(window); + RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info; + String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor->column-1 - autocomp_cursor_info->replaced_range.min); U64 off = 0; - U64 cursor_off = cursor->column-1; - DR_FancyStringNode *prev_n = 0; - for(DR_FancyStringNode *n = code_fancy_strings.first; n != 0; n = n->next) + U64 cursor_off = params->cursor->column-1; + DR_FStrNode *prev_n = 0; + for(DR_FStrNode *n = edit_string_fstrs.first; n != 0; n = n->next) { if(off <= cursor_off && cursor_off <= off+n->v.string.size) { @@ -2692,13 +3889,14 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx off += n->v.string.size; } { - DR_FancyStringNode *autocomp_fstr_n = push_array(scratch.arena, DR_FancyStringNode, 1); - DR_FancyString *fstr = &autocomp_fstr_n->v; - fstr->font = ui_top_font(); + DR_FStrNode *autocomp_fstr_n = push_array(scratch.arena, DR_FStrNode, 1); + DR_FStr *fstr = &autocomp_fstr_n->v; fstr->string = autocomplete_append_string; - fstr->color = ui_top_palette()->text; - fstr->color.w *= 0.5f; - fstr->size = ui_top_font_size(); + fstr->params.font = ui_top_font(); + fstr->params.raster_flags = ui_top_text_raster_flags(); + fstr->params.color = ui_color_from_name(str8_lit("text")); + fstr->params.color.w *= 0.5f; + fstr->params.size = ui_top_font_size(); autocomp_fstr_n->next = prev_n ? prev_n->next : 0; if(prev_n != 0) { @@ -2706,87 +3904,113 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx } if(prev_n == 0) { - code_fancy_strings.first = code_fancy_strings.last = autocomp_fstr_n; + edit_string_fstrs.first = edit_string_fstrs.last = autocomp_fstr_n; } if(prev_n != 0 && prev_n->next == 0) { - code_fancy_strings.last = autocomp_fstr_n; + edit_string_fstrs.last = autocomp_fstr_n; } - code_fancy_strings.node_count += 1; - code_fancy_strings.total_size += autocomplete_hint_string.size; + edit_string_fstrs.node_count += 1; + edit_string_fstrs.total_size += autocomplete_hint_string.size; if(prev_n != 0 && cursor_off - off < prev_n->v.string.size) { String8 full_string = prev_n->v.string; U64 chop_amt = full_string.size - (cursor_off - off); prev_n->v.string = str8_chop(full_string, chop_amt); - code_fancy_strings.total_size -= chop_amt; + edit_string_fstrs.total_size -= chop_amt; if(chop_amt != 0) { String8 post_cursor = str8_skip(full_string, cursor_off - off); - DR_FancyStringNode *post_fstr_n = push_array(scratch.arena, DR_FancyStringNode, 1); - DR_FancyString *post_fstr = &post_fstr_n->v; + DR_FStrNode *post_fstr_n = push_array(scratch.arena, DR_FStrNode, 1); + DR_FStr *post_fstr = &post_fstr_n->v; MemoryCopyStruct(post_fstr, &prev_n->v); post_fstr->string = post_cursor; if(autocomp_fstr_n->next == 0) { - code_fancy_strings.last = post_fstr_n; + edit_string_fstrs.last = post_fstr_n; } post_fstr_n->next = autocomp_fstr_n->next; autocomp_fstr_n->next = post_fstr_n; - code_fancy_strings.node_count += 1; - code_fancy_strings.total_size += post_cursor.size; + edit_string_fstrs.node_count += 1; + edit_string_fstrs.total_size += post_cursor.size; } } } } - ui_box_equip_display_fancy_strings(editstr_box, &code_fancy_strings); - UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); - draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); - draw_data->cursor = *cursor; - draw_data->mark = *mark; - ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); - mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); - cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, cursor->column-1)).x; - scratch_end(scratch); - } - else if((is_focus_active || is_focus_active_disabled) && !(flags & RD_LineEditFlag_CodeContents)) - { - String8 edit_string = str8(edit_buffer, edit_string_size_out[0]); - F32 total_text_width = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), edit_string).x; - F32 total_editstr_width = total_text_width - !!(flags & (RD_LineEditFlag_Expander|RD_LineEditFlag_ExpanderSpace|RD_LineEditFlag_ExpanderPlaceholder)) * expander_size_px; - ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); - UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); - UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); - draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); - draw_data->cursor = *cursor; - draw_data->mark = *mark; - ui_box_equip_display_string(editstr_box, edit_string); - ui_box_equip_custom_draw(editstr_box, ui_line_edit_draw, draw_data); - mouse_pt = txt_pt(1, 1+ui_box_char_pos_from_xy(editstr_box, ui_mouse())); - cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, cursor->column-1)).x; + fstrs = edit_string_fstrs; } } + ////////////////////////////// + //- rjf: build scrolled contents + // + TxtPt mouse_pt = {0}; + F32 cursor_off = 0; + if(scrollable_box != &ui_nil_box) UI_Parent(scrollable_box) + { + FuzzyMatchRangeList fuzzy_matches = {0}; + if(params->search_needle.size != 0) + { + fuzzy_matches = dr_fuzzy_match_find_from_fstrs(scratch.arena, &fstrs, params->search_needle); + } + if(ui_top_text_alignment() == UI_TextAlign_Left && (params->flags & (RD_CellFlag_Expander|RD_CellFlag_ExpanderSpace|RD_CellFlag_ExpanderPlaceholder)) == 0) + { + ui_spacer(ui_em(0.5f, 1.f)); + } + if(is_focus_active) + { + ui_set_next_flags(UI_BoxFlag_DisableTextTrunc); + } + ui_set_next_pref_width(ui_text_dim(ui_top_font_size()*0.5f, 0)); + UI_Box *text_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "###text_box"); + ui_box_equip_display_fstrs(text_box, &fstrs); + ui_box_equip_fuzzy_match_ranges(text_box, &fuzzy_matches); + if(is_focus_active || is_focus_active_disabled) + { + String8 edit_string = str8(params->edit_buffer, params->edit_string_size_out[0]); + UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); + draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); + draw_data->cursor = params->cursor[0]; + draw_data->mark = params->mark[0]; + ui_box_equip_custom_draw(text_box, ui_line_edit_draw, draw_data); + Vec2F32 text2mouse = sub_2f32(ui_mouse(), ui_box_text_position(text_box)); + FNT_Tag font = ui_top_font(); + F32 font_size = ui_top_font_size(); + if(params->flags & RD_CellFlag_CodeContents) + { + font = rd_font_from_slot(RD_FontSlot_Code); + } + U64 mouse_pt_off = fnt_char_pos_from_tag_size_string_p(font, font_size, 0, ui_top_tab_size(), edit_string, text2mouse.x); + mouse_pt = txt_pt(1, 1+mouse_pt_off); + cursor_off = fnt_dim_from_tag_size_string(ui_top_font(), ui_top_font_size(), 0, ui_top_tab_size(), str8_prefix(edit_string, params->cursor->column-1)).x; + } + } + + ////////////////////////////// //- rjf: click+drag + // if(is_focus_active && ui_dragging(sig)) { if(ui_pressed(sig)) { - *mark = mouse_pt; + params->mark[0] = mouse_pt; } - *cursor = mouse_pt; + params->cursor[0] = mouse_pt; } if(!is_focus_active && is_focus_active_disabled && ui_pressed(sig)) { - *cursor = *mark = mouse_pt; + params->cursor[0] = params->mark[0] = mouse_pt; } + ////////////////////////////// //- rjf: focus cursor + // + if(scrollable_box != &ui_nil_box) { - F32 visible_dim_px = dim_2f32(box->rect).x - expander_size_px - ui_top_font_size()*depth; + F32 visible_dim_px = dim_2f32(box->rect).x - expander_size_px - ui_top_font_size()*params->depth; if(visible_dim_px > 0) { - Rng1F32 cursor_range_px = r1f32(cursor_off-ui_top_font_size()*2.f, cursor_off+ui_top_font_size()*2.f); + Rng1F32 cursor_range_px = r1f32(cursor_off-ui_top_font_size()*2.f, cursor_off+ui_top_font_size()*1.f); Rng1F32 visible_range_px = r1f32(scrollable_box->view_off_target.x, scrollable_box->view_off_target.x + visible_dim_px); cursor_range_px.min = ClampBot(0, cursor_range_px.min); cursor_range_px.max = ClampBot(0, cursor_range_px.max); @@ -2803,23 +4027,26 @@ rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx } } + ////////////////////////////// //- rjf: pop focus + // if(is_auto_focus_hot) { ui_pop_focus_hot(); } if(is_auto_focus_active) { ui_pop_focus_active(); } ProfEnd(); + scratch_end(scratch); return sig; } internal UI_Signal -rd_line_editf(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, char *fmt, ...) +rd_cellf(RD_CellParams *params, char *fmt, ...) { Temp scratch = scratch_begin(0, 0); va_list args; va_start(args, fmt); String8 string = push_str8fv(scratch.arena, fmt, args); va_end(args); - UI_Signal sig = rd_line_edit(flags, depth, matches, cursor, mark, edit_buffer, edit_buffer_size, edit_string_size_out, expanded_out, pre_edit_value, string); + UI_Signal sig = rd_cell(params, string); scratch_end(scratch); return sig; } diff --git a/src/raddbg/raddbg_widgets.h b/src/raddbg/raddbg_widgets.h index 9048161e..36014bad 100644 --- a/src/raddbg/raddbg_widgets.h +++ b/src/raddbg/raddbg_widgets.h @@ -5,21 +5,77 @@ #define RADDBG_WIDGETS_H //////////////////////////////// -//~ rjf: Line Edit Types +//~ rjf: Cell Types -typedef U32 RD_LineEditFlags; +typedef U32 RD_CellFlags; enum { - RD_LineEditFlag_Expander = (1<<0), - RD_LineEditFlag_ExpanderSpace = (1<<1), - RD_LineEditFlag_ExpanderPlaceholder = (1<<2), - RD_LineEditFlag_DisableEdit = (1<<3), - RD_LineEditFlag_CodeContents = (1<<4), - RD_LineEditFlag_KeyboardClickable = (1<<5), - RD_LineEditFlag_Border = (1<<6), - RD_LineEditFlag_NoBackground = (1<<7), - RD_LineEditFlag_PreferDisplayString = (1<<8), - RD_LineEditFlag_DisplayStringIsCode = (1<<9), + //- rjf: expander + RD_CellFlag_Expander = (1<<0), + RD_CellFlag_ExpanderSpace = (1<<1), + RD_CellFlag_ExpanderPlaceholder = (1<<2), + + //- rjf: toggle switch extension + RD_CellFlag_ToggleSwitch = (1<<3), + + //- rjf: slider extension + RD_CellFlag_Slider = (1<<4), + + //- rjf: bindings extension + RD_CellFlag_Bindings = (1<<5), + + //- rjf: extra button extensions + RD_CellFlag_EmptyEditButton = (1<<6), + RD_CellFlag_RevertButton = (1<<7), + + //- rjf: behavior + RD_CellFlag_DisableEdit = (1<<8), + RD_CellFlag_KeyboardClickable = (1<<9), + RD_CellFlag_SingleClickActivate = (1<<10), + + //- rjf: contents description + RD_CellFlag_CodeContents = (1<<11), + + //- rjf: appearance + RD_CellFlag_Border = (1<<12), + RD_CellFlag_NoBackground = (1<<13), + RD_CellFlag_Button = (1<<14), +}; + +typedef struct RD_CellParams RD_CellParams; +struct RD_CellParams +{ + //- rjf: catchall parameters + RD_CellFlags flags; + S32 depth; + String8 pre_edit_value; + DR_FStrList meta_fstrs; + DR_FStrList value_fstrs; + String8 search_needle; + String8 description; + + //- rjf: expander r/w info + B32 *expanded_out; + + //- rjf: toggle-switch r/w info + B32 *toggled_out; + + //- rjf: slider info r/w info + F32 *slider_value_out; + + //- rjf: bindings name w info + String8 bindings_name; + + //- rjf: revert out + B32 *revert_out; + + //- rjf: text editing r/w info + TxtPt *cursor; + TxtPt *mark; + U8 *edit_buffer; + U64 edit_buffer_size; + U64 *edit_string_size_out; + UI_Key *line_edit_key_out; }; //////////////////////////////// @@ -43,9 +99,9 @@ struct RD_CodeSliceParams String8 *line_text; Rng1U64 *line_ranges; TXT_TokenArray *line_tokens; - RD_EntityList *line_bps; + RD_CfgList *line_bps; CTRL_EntityList *line_ips; - RD_EntityList *line_pins; + RD_CfgList *line_pins; U64 *line_vaddrs; D_LineList *line_infos; DI_KeyList relevant_dbgi_keys; @@ -74,9 +130,16 @@ struct RD_CodeSliceSignal //////////////////////////////// //~ rjf: UI Building Helpers -#define RD_Palette(code) UI_Palette(rd_palette_from_code(code)) #define RD_Font(slot) UI_Font(rd_font_from_slot(slot)) UI_TextRasterFlags(rd_raster_flags_from_slot((slot))) +//////////////////////////////// +//~ rjf: UI Widgets: Fancy Title Strings + +internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg); +internal DR_FStrList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras); +internal DR_FStrList rd_title_fstrs_from_code_name(Arena *arena, String8 code_name); +internal DR_FStrList rd_title_fstrs_from_file_path(Arena *arena, String8 file_path); + //////////////////////////////// //~ rjf: UI Widgets: Loading Overlay @@ -85,7 +148,7 @@ internal void rd_loading_overlay(Rng2F32 rect, F32 loading_t, U64 progress_v, U6 //////////////////////////////// //~ rjf: UI Widgets: Fancy Buttons -internal void rd_cmd_binding_buttons(String8 name); +internal void rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new); internal UI_Signal rd_menu_bar_button(String8 string); internal UI_Signal rd_cmd_spec_button(String8 name); internal void rd_cmd_list_menu_buttons(U64 count, String8 *cmd_names, U32 *fastpath_codepoints); @@ -105,16 +168,17 @@ internal B32 rd_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels +internal DR_FStrList rd_fstrs_from_rich_string(Arena *arena, String8 string); internal UI_Signal rd_label(String8 string); internal UI_Signal rd_error_label(String8 string); internal B32 rd_help_label(String8 string); -internal DR_FancyStringList rd_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string); +internal DR_FStrList rd_fstrs_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string); internal UI_Box *rd_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string); //////////////////////////////// //~ rjf: UI Widgets: Line Edit -internal UI_Signal rd_line_edit(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, String8 string); -internal UI_Signal rd_line_editf(RD_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, U64 *edit_string_size_out, B32 *expanded_out, String8 pre_edit_value, char *fmt, ...); +internal UI_Signal rd_cell(RD_CellParams *params, String8 string); +internal UI_Signal rd_cellf(RD_CellParams *params, char *fmt, ...); #endif // RADDBG_WIDGETS_H diff --git a/src/raddump/raddump.c b/src/raddump/raddump.c index 479ffe1e..b3ecb678 100644 --- a/src/raddump/raddump.c +++ b/src/raddump/raddump.c @@ -42,78 +42,21 @@ rd_stderr(char *fmt, ...) scratch_end(scratch); } -internal String8 -rd_invoke_rdi_converter(Arena *arena, String8 exe_name, String8 exe_data, String8 pdb_path) -{ - Temp scratch = scratch_begin(0,0); - - P2R_User2Convert user2convert = {0}; - user2convert.input_pdb_name = pdb_path; - user2convert.input_pdb_data = os_data_from_file_path(scratch.arena, pdb_path); - user2convert.input_exe_name = exe_name; - user2convert.input_exe_data = exe_data; - user2convert.output_name = str8_zero(); - user2convert.flags = P2R_ConvertFlag_All; - - P2R_Convert2Bake *convert2bake = p2r_convert(scratch.arena, &user2convert); - P2R_Bake2Serialize *bake2srlz = p2r_bake(scratch.arena, convert2bake); - RDIM_SerializedSectionBundle bundle = rdim_serialized_section_bundle_from_bake_results(&bake2srlz->bake_results); - String8List rdi_blobs = rdim_file_blobs_from_section_bundle(scratch.arena, &bundle); - String8 raw_rdi = str8_list_join(arena, &rdi_blobs, 0); - - scratch_end(scratch); - return raw_rdi; -} - internal RDI_Parsed * -rd_rdi_from_pe(Arena *arena, String8 data_path, String8 raw_data) +rd_rdi_from_pe(Arena *arena, String8 pe_path) { Temp scratch = scratch_begin(&arena, 1); + // make command line for converter + String8List cmdl_string = {0}; + str8_list_pushf(scratch.arena, &cmdl_string, "-pe:%S", pe_path); + CmdLine cmdl = cmd_line_from_string_list(scratch.arena, cmdl_string); + + // run converter + String8 raw_rdi = rc_rdi_from_cmd_line(scratch.arena, &cmdl); + + // load RDI RDI_Parsed *rdi = 0; - - PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, raw_data); - String8 raw_debug_dir = str8_substr(raw_data, pe.data_dir_franges[PE_DataDirectoryIndex_DEBUG]); - PE_DebugInfoList dbg_list = pe_parse_debug_directory(scratch.arena, raw_data, raw_debug_dir); - - String8 raw_rdi = {0}; - Guid rdi_guid = {0}; - for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) { - PE_DebugInfo *v = &n->v; - if (v->header.type == PE_DebugDirectoryType_CODEVIEW) { - if (v->u.codeview.magic == PE_CODEVIEW_RDI_MAGIC) { - if (raw_rdi.size) { - rd_warningf("multiple RDI paths defined in %S"); - } else { - raw_rdi = os_data_from_file_path(arena, v->u.codeview.rdi.path); - rdi_guid = v->u.codeview.rdi.header.guid; - if (raw_rdi.size == 0) { - rd_errorf("unable to open RDI: %S", v->u.codeview.rdi.path); - } - } - } - } - } - - if (!raw_rdi.size) { - String8 pdb_path = str8_zero(); - Guid pdb_guid = {0}; - B32 convert_pdb = 0; - for (PE_DebugInfoNode *n = dbg_list.first; n != 0; n = n->next) { - PE_DebugInfo *v = &n->v; - if (v->header.type == PE_DebugDirectoryType_CODEVIEW) { - pdb_path = v->u.codeview.pdb70.path; - pdb_guid = v->u.codeview.pdb70.header.guid; - convert_pdb = 1; - break; - } - } - - if (convert_pdb) { - raw_rdi = rd_invoke_rdi_converter(scratch.arena, data_path, raw_data, pdb_path); - } - } - if (raw_rdi.size) { rdi = push_array(arena, RDI_Parsed, 1); @@ -214,14 +157,6 @@ rd_format_line_from_voff(Arena *arena, RDI_Parsed *rdi, U64 voff, PathStyle path return result; } -internal B32 -rd_is_pe(String8 raw_data) -{ - PE_DosHeader header = {0}; - str8_deserial_read_struct(raw_data, 0, &header); - return header.magic == PE_DOS_MAGIC; -} - internal B32 rd_is_rdi(String8 raw_data) { @@ -233,6 +168,18 @@ rd_is_rdi(String8 raw_data) return is_rdi; } +internal String8 +rd_string_from_reg_off(Arena *arena, String8 reg_str, S64 reg_off) +{ + String8 result; + if (reg_off > 0) { + result = push_str8f(arena, "%S%+lld", reg_str, reg_off); + } else { + result = push_str8f(arena, "%S", reg_str); + } + return result; +} + internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags) { @@ -263,6 +210,19 @@ rd_string_from_array_u32(Arena *arena, U32 *v, U64 count) return result; } +internal String8 +rd_string_from_hex_u8(Arena *arena, U8 *v, U64 count) +{ + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + for (U64 i = 0; i < count; ++i) { + str8_list_pushf(scratch.arena, &list, "%#x", v[i]); + } + String8 result = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); + scratch_end(scratch); + return result; +} + internal String8 rd_string_from_array_hex_u32(Arena *arena, U32 *v, U64 count) { @@ -307,28 +267,30 @@ rd_format_preamble(Arena *arena, String8List *out, String8 indent, String8 input { Temp scratch = scratch_begin(&arena, 1); - char *input_type_string = "???"; + String8 input_type_string = str8_lit("???"); if (coff_is_regular_archive(raw_data)) { - input_type_string = "Archive"; + input_type_string = str8_lit("Archive"); } else if (coff_is_thin_archive(raw_data)) { - input_type_string = "Thin Archive"; + input_type_string = str8_lit("Thin Archive"); } else if (coff_is_big_obj(raw_data)) { - input_type_string = "Big Obj"; + input_type_string = str8_lit("Big Obj"); } else if (coff_is_obj(raw_data)) { - input_type_string = "Obj"; - } else if (rd_is_pe(raw_data)) { - input_type_string = "COFF/PE"; + input_type_string = str8_lit("Obj"); + } else if (pe_check_magic(raw_data)) { + input_type_string = str8_lit("COFF/PE"); } else if (rd_is_rdi(raw_data)) { - input_type_string = "RDI"; - } else if (pe_is_res(raw_data)) { - input_type_string = "RES"; + input_type_string = str8_lit("RDI"); + } else if (elf_check_magic(raw_data)) { + U8 sig[ELF_Identifier_Max] = {0}; + str8_deserial_read(raw_data, 0, &sig[0], sizeof(sig), 1); + input_type_string = push_str8f(scratch.arena, "ELF (Class: %S)", elf_string_from_class(scratch.arena, sig[ELF_Identifier_Class])); } DateTime universal_dt = os_now_universal_time(); DateTime local_dt = os_local_time_from_universal(&universal_dt); String8 time = push_date_time_string(scratch.arena, &local_dt); String8 full_path = os_full_path_from_path(scratch.arena, input_path); - rd_printf("# %S, [%s] %S", time, input_type_string, full_path); + rd_printf("# %S, [%S] %S", time, input_type_string, full_path); scratch_end(scratch); } @@ -434,7 +396,7 @@ rd_section_markers_from_rdi(Arena *arena, RDI_Parsed *rdi) } internal RD_MarkerArray * -rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols) +rd_section_markers_from_coff_symbol_table(Arena *arena, String8 string_table, U64 section_count, COFF_Symbol32Array symbols) { Temp scratch = scratch_begin(&arena, 1); @@ -449,7 +411,7 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st (symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static); if (is_marker) { - String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + String8 name = coff_read_symbol_name(string_table, &symbol->name); RD_MarkerNode *n = push_array(scratch.arena, RD_MarkerNode, 1); n->v.off = symbol->value; @@ -482,47 +444,6 @@ rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 st return result; } -internal DW_SectionArray -rd_dw_sections_from_coff_section_table(Arena *arena, - String8 raw_image, - U64 string_table_off, - U64 section_count, - COFF_SectionHeader *sections) -{ - DW_SectionArray result = {0}; - B32 sect_status[ArrayCount(result.v)] = {0}; - - for (U64 i = 0; i < section_count; ++i) { - COFF_SectionHeader *header = §ions[i]; - Rng1U64 raw_data_range = rng_1u64(header->foff, header->foff + header->fsize); - String8 name = coff_name_from_section_header(raw_image, header, string_table_off); - - DW_SectionKind s = DW_Section_Null; - B32 is_dwo = 0; - #define X(_K,_L,_M,_W) \ - if (str8_match_lit(_L, name, 0)) { s = DW_Section_##_K; } \ - if (str8_match_lit(_M, name, 0)) { s = DW_Section_##_K; } \ - if (str8_match_lit(_W, name, 0)) { s = DW_Section_##_K; is_dwo = 1; } - DW_SectionKind_XList(X) - #undef X - - if (s != DW_Section_Null) { - if (sect_status[s]) { - rd_warningf("file contains multiple %S sections, picking first", name); - } else { - sect_status[s] = 1; - DW_Section *d = &result.v[s]; - d->name = push_str8_copy(arena, name); - d->data = str8_substr(raw_image, raw_data_range); - d->mode = dim_1u64(raw_data_range) > max_U32 ? DW_Mode_64Bit : DW_Mode_32Bit; - d->is_dwo = is_dwo; - } - } - } - - return result; -} - internal RD_DisasmResult rd_disasm_next_instruction(Arena *arena, Arch arch, U64 addr, String8 raw_code) { @@ -744,19 +665,6 @@ rdi_string_from_local_kind(Arena *arena, RDI_LocalKind v) return result; } -internal String8 -rdi_string_from_type_kind(Arena *arena, RDI_TypeKind v) -{ - String8 result; - switch (v) { - default: { result = push_str8f(arena, "%u", v); } break; -#define X(name) case RDI_TypeKind_##name: { result = str8_lit(#name); } break; - RDI_TypeKind_XList -#undef X - } - return result; -} - internal String8 rdi_string_from_member_kind(Arena *arena, RDI_MemberKind v) { @@ -804,6 +712,78 @@ rdi_string_from_reg_code(Arena *arena, RDI_Arch arch, U64 reg_code) return push_str8f(arena, "??? (%llu)", reg_code); } +internal String8 +rdi_string_from_eval_op(Arena *arena, RDI_EvalOp op) +{ + switch (op) { + case RDI_EvalOp_Stop: return str8_lit("Stop"); + case RDI_EvalOp_Noop: return str8_lit("Noop"); + case RDI_EvalOp_Cond: return str8_lit("Cond"); + case RDI_EvalOp_Skip: return str8_lit("Skip"); + case RDI_EvalOp_MemRead: return str8_lit("MemRead"); + case RDI_EvalOp_RegRead: return str8_lit("RegRead"); + case RDI_EvalOp_RegReadDyn: return str8_lit("RegReadDyn"); + case RDI_EvalOp_FrameOff: return str8_lit("FrameOff"); + case RDI_EvalOp_ModuleOff: return str8_lit("ModuleOff"); + case RDI_EvalOp_TLSOff: return str8_lit("TLSOff"); + case RDI_EvalOp_ObjectOff: return str8_lit("ObjectOff"); + case RDI_EvalOp_CFA: return str8_lit("CFA"); + case RDI_EvalOp_ConstU8: return str8_lit("ConstU8"); + case RDI_EvalOp_ConstU16: return str8_lit("ConstU16"); + case RDI_EvalOp_ConstU32: return str8_lit("ConstU32"); + case RDI_EvalOp_ConstU64: return str8_lit("ConstU64"); + case RDI_EvalOp_ConstU128: return str8_lit("ConstU128"); + case RDI_EvalOp_ConstString: return str8_lit("ConstString"); + case RDI_EvalOp_Abs: return str8_lit("Abs"); + case RDI_EvalOp_Neg: return str8_lit("Neg"); + case RDI_EvalOp_Add: return str8_lit("Add"); + case RDI_EvalOp_Sub: return str8_lit("Sub"); + case RDI_EvalOp_Mul: return str8_lit("Mul"); + case RDI_EvalOp_Div: return str8_lit("Div"); + case RDI_EvalOp_Mod: return str8_lit("Mod"); + case RDI_EvalOp_LShift: return str8_lit("LShift"); + case RDI_EvalOp_RShift: return str8_lit("RShift"); + case RDI_EvalOp_BitAnd: return str8_lit("BitAnd"); + case RDI_EvalOp_BitOr: return str8_lit("BitOr"); + case RDI_EvalOp_BitXor: return str8_lit("BitXor"); + case RDI_EvalOp_BitNot: return str8_lit("BitNot"); + case RDI_EvalOp_LogAnd: return str8_lit("LogAnd"); + case RDI_EvalOp_LogOr: return str8_lit("LogOr"); + case RDI_EvalOp_LogNot: return str8_lit("LogNot"); + case RDI_EvalOp_EqEq: return str8_lit("EqEq"); + case RDI_EvalOp_NtEq: return str8_lit("NtEq"); + case RDI_EvalOp_LsEq: return str8_lit("LsEq"); + case RDI_EvalOp_GrEq: return str8_lit("GrEq"); + case RDI_EvalOp_Less: return str8_lit("Less"); + case RDI_EvalOp_Grtr: return str8_lit("Grtr"); + case RDI_EvalOp_Trunc: return str8_lit("Trunc"); + case RDI_EvalOp_TruncSigned: return str8_lit("TruncSigned"); + case RDI_EvalOp_Convert: return str8_lit("Convert"); + case RDI_EvalOp_Pick: return str8_lit("Pick"); + case RDI_EvalOp_Pop: return str8_lit("Pop"); + case RDI_EvalOp_Insert: return str8_lit("Insert"); + case RDI_EvalOp_ValueRead: return str8_lit("ValueRead"); + case RDI_EvalOp_ByteSwap: return str8_lit("ByteSwap"); + case RDI_EvalOp_CallSiteValue: return str8_lit("CallSiteValue"); + case RDI_EvalOp_PartialValue: return str8_lit("PartialValue"); + case RDI_EvalOp_PartialValueBit: return str8_lit("PartialValueBit"); + } + return push_str8f(arena, "%#x", op); +} + +internal String8 +rdi_string_from_eval_type_group(Arena *arena, RDI_EvalTypeGroup x) +{ + switch (x) { + case RDI_EvalTypeGroup_Other: return str8_lit("Other"); + case RDI_EvalTypeGroup_U: return str8_lit("U"); + case RDI_EvalTypeGroup_S: return str8_lit("S"); + case RDI_EvalTypeGroup_F32: return str8_lit("F32"); + case RDI_EvalTypeGroup_F64: return str8_lit("F64"); + } + return push_str8f(arena, "%#x", x); +} + internal String8 rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags) { @@ -1008,7 +988,10 @@ rdi_print_type_node(Arena *arena, String8List *out, String8 indent, RDI_Parsed * { Temp scratch = scratch_begin(&arena, 1); - rd_printf("kind =%S", rdi_string_from_type_kind(scratch.arena, type->kind)); + String8 type_kind_str = {0}; + type_kind_str.str = rdi_string_from_type_kind(type->kind, &type_kind_str.size); + + rd_printf("kind =%S", type_kind_str); if (type->kind == RDI_TypeKind_Modifier) { rd_printf("flags =%S", rdi_string_from_type_modifier_flags(scratch.arena, type->flags)); } else { @@ -1027,6 +1010,7 @@ rdi_print_type_node(Arena *arena, String8List *out, String8 indent, RDI_Parsed * U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); String8 param_idx_str = rd_string_from_array_u32(scratch.arena, param_idx_array, param_idx_count); rd_printf("constructed.params =%S", param_idx_str); + rd_printf("return type =%u", type->constructed.direct_type_idx); } else if (type->kind == RDI_TypeKind_Method) { U32 param_idx_count = 0; U32 *param_idx_array = rdi_idx_run_from_first_count(rdi, type->constructed.param_idx_run_first, type->constructed.count, ¶m_idx_count); @@ -1039,6 +1023,7 @@ rdi_print_type_node(Arena *arena, String8List *out, String8 indent, RDI_Parsed * String8 param_idx_str = rd_string_from_array_u32(scratch.arena, param_idx_array, param_idx_count); rd_printf("constructed.this_type =%S", this_type_str); rd_printf("constructed.params =%S", param_idx_str); + rd_printf("return type =%u", type->constructed.direct_type_idx); } else if (RDI_TypeKind_FirstConstructed <= type->kind && type->kind <= RDI_TypeKind_LastConstructed) { rd_printf("constructed.direct_type =%u", type->constructed.direct_type_idx); @@ -1107,6 +1092,250 @@ rdi_print_udt(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, R scratch_end(scratch); } +internal String8 +rdi_string_from_bytecode(Arena *arena, RDI_Arch arch, String8 bc) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8List fmt = {0}; + for (U64 cursor = 0; cursor < bc.size; ) { + RDI_EvalOp op = RDI_EvalOp_Stop; + cursor += str8_deserial_read_struct(bc, cursor, &op); + + U16 ctrlbits = rdi_eval_op_ctrlbits_table[op]; + U32 imm_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + + String8 imm = {0}; + cursor += str8_deserial_read_block(bc, cursor, imm_size, &imm); + if (imm.size != imm_size) { + str8_list_pushf(scratch.arena, &fmt, "(ERROR: not enough bytes to read immediate)"); + break; + } + + String8 imm_fmt = {0}; + switch (op) { + case RDI_EvalOp_Stop: goto exit; + case RDI_EvalOp_Noop: break; + case RDI_EvalOp_Cond: break; + case RDI_EvalOp_Skip: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U16 *)imm.str); + } break; + case RDI_EvalOp_MemRead: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U8 *)imm.str); + } break; + case RDI_EvalOp_RegRead: { + U32 regread = *(U32 *)imm.str; + RDI_RegCode reg_code = Extract8(regread, 0); + U8 byte_size = Extract8(regread, 1); + U8 byte_off = Extract8(regread, 2); + String8 reg_str = rdi_string_from_reg_code(scratch.arena, arch, reg_code); + imm_fmt = push_str8f(scratch.arena, "%S, Size: %u", rd_string_from_reg_off(scratch.arena, reg_str, byte_off), byte_size); + } break; + case RDI_EvalOp_RegReadDyn: break; + case RDI_EvalOp_FrameOff: { + imm_fmt = push_str8f(scratch.arena, "%+lld", *(S64 *)imm.str); + } break; + case RDI_EvalOp_ModuleOff: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U32 *)imm.str); + } break; + case RDI_EvalOp_TLSOff: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U32 *)imm.str); + } break; + case RDI_EvalOp_ConstU8: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U8 *)imm.str); + } break; + case RDI_EvalOp_ConstU16: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U16 *)imm.str); + } break; + case RDI_EvalOp_ConstU32: { + imm_fmt = push_str8f(scratch.arena, "%u", *(U32 *)imm.str); + } break; + case RDI_EvalOp_ConstU64: { + imm_fmt = push_str8f(scratch.arena, "%llu", *(U64 *)imm.str); + } break; + case RDI_EvalOp_ConstU128: { + imm_fmt = push_str8f(scratch.arena, "Lo: %llu, Hi: %llu", *(U64 *)imm.str, *((U64 *)imm.str + 1)); + } break; + case RDI_EvalOp_ConstString: { + U8 size = *(U8 *)imm.str; + String8 string = {0}; + cursor += str8_deserial_read_block(bc, cursor, size, &string); + + imm_fmt = push_str8f(scratch.arena, "(%u) \"%S\"", size, string); + } break; + case RDI_EvalOp_Abs: + case RDI_EvalOp_Neg: + case RDI_EvalOp_Add: + case RDI_EvalOp_Sub: + case RDI_EvalOp_Mul: + case RDI_EvalOp_Div: + case RDI_EvalOp_Mod: + case RDI_EvalOp_LShift: + case RDI_EvalOp_RShift: + case RDI_EvalOp_BitAnd: + case RDI_EvalOp_BitOr: + case RDI_EvalOp_BitXor: + case RDI_EvalOp_BitNot: + case RDI_EvalOp_LogAnd: + case RDI_EvalOp_LogOr: + case RDI_EvalOp_LogNot: + case RDI_EvalOp_EqEq: + case RDI_EvalOp_NtEq: + case RDI_EvalOp_LsEq: + case RDI_EvalOp_GrEq: + case RDI_EvalOp_Less: + case RDI_EvalOp_Grtr: { + U8 eval_type_group = *(U8 *)imm.str; + imm_fmt = rdi_string_from_eval_type_group(scratch.arena, eval_type_group); + } break; + case RDI_EvalOp_Trunc: + case RDI_EvalOp_TruncSigned: { + U8 trunc = *(U8 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", trunc); + } break; + case RDI_EvalOp_Convert: { + U16 convert = *(U16 *)imm.str; + U8 in = Extract8(convert, 0); + U8 out = Extract8(convert, 1); + String8 in_str = rdi_string_from_eval_type_group(scratch.arena, in); + String8 out_str = rdi_string_from_eval_type_group(scratch.arena, out); + imm_fmt = push_str8f(scratch.arena, "in: %S out: %S", in_str, out_str); + } break; + case RDI_EvalOp_Pick: { + U8 pick = *(U8 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", pick); + } break; + case RDI_EvalOp_Pop: break; + case RDI_EvalOp_Insert: { + U8 insert = *(U8 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", insert); + } break; + case RDI_EvalOp_ValueRead: { + U8 bytes_to_read = *(U8 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", bytes_to_read); + } break; + case RDI_EvalOp_ByteSwap: { + U8 byte_size = *(U8 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", byte_size); + } break; + case RDI_EvalOp_CallSiteValue: { + U32 call_site_bc_size = *(U32 *)imm.str; + String8 call_site_bc = {0}; + cursor += str8_deserial_read_block(bc, cursor, call_site_bc_size, &call_site_bc); + + String8 call_site_str = rdi_string_from_bytecode(scratch.arena, arch, call_site_bc); + imm_fmt = push_str8f(scratch.arena, "%S", call_site_str); + } break; + case RDI_EvalOp_PartialValue: { + U32 partial_value_size = *(U32 *)imm.str; + imm_fmt = push_str8f(scratch.arena, "%u", partial_value_size); + } break; + case RDI_EvalOp_PartialValueBit: { + U64 partial_value = *(U64 *)imm.str; + U32 bit_size = Extract32(partial_value, 0); + U32 bit_off = Extract32(partial_value, 1); + imm_fmt = push_str8f(scratch.arena, "Off: %u, Size: %u", bit_size, bit_off); + } break; + } + + String8 op_str = rdi_string_from_eval_op(scratch.arena, op); + if (imm_fmt.size) { + str8_list_pushf(scratch.arena, &fmt, "RDI_EvalOp_%S(%S)", op_str, imm_fmt); + } else { + str8_list_pushf(scratch.arena, &fmt, "RDI_EvalOp_%S", op_str); + } + } + exit:; + + String8 result = str8_list_join(arena, &fmt, &(StringJoin){.sep = str8_lit(", ")}); + + scratch_end(scratch); + return result; +} + +internal void +rdi_print_locations(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Arch arch, U64 block_lo, U64 block_hi) +{ + Temp scratch = scratch_begin(&arena, 1); + + U64 location_block_count = 0; + U64 location_data_size = 0; + RDI_LocationBlock *location_block_array = rdi_table_from_name(rdi, LocationBlocks, &location_block_count); + RDI_U8 *location_data = rdi_table_from_name(rdi, LocationData, &location_data_size); + + block_lo = ClampTop(block_lo, location_block_count); + block_hi = ClampTop(block_hi, location_block_count); + + for (U32 block_idx = block_lo; block_idx < block_hi; ++block_idx) { + RDI_LocationBlock *block_ptr = &location_block_array[block_idx]; + + String8List fmt = {0}; + + if (block_ptr->scope_off_first == 0 && block_ptr->scope_off_opl == max_U32) { + str8_list_pushf(scratch.arena, &fmt, "*always*:"); + } else { + str8_list_pushf(scratch.arena, &fmt, "[%#08x, %#08x):", block_ptr->scope_off_first, block_ptr->scope_off_opl); + } + + if (block_ptr->location_data_off >= location_data_size) { + str8_list_pushf(scratch.arena, &fmt, "", block_ptr->location_data_off); + } else { + U8 *loc_data_opl = location_data + location_data_size; + U8 *loc_base_ptr = location_data + block_ptr->location_data_off; + RDI_LocationKind kind = *(RDI_LocationKind*)loc_base_ptr; + switch (kind) { + default: { + str8_list_pushf(scratch.arena, &fmt, "\?\?\?: %u", kind); + } break; + + case RDI_LocationKind_AddrBytecodeStream: { + String8 bc = str8_range(loc_base_ptr + 1, loc_data_opl); + String8 bc_str = rdi_string_from_bytecode(scratch.arena, arch, bc); + str8_list_pushf(scratch.arena, &fmt, "AddrBytecodeStream(%S)", bc_str); + } break; + + case RDI_LocationKind_ValBytecodeStream: { + String8 bc = str8_range(loc_base_ptr + 1, loc_data_opl); + String8 bc_str = rdi_string_from_bytecode(scratch.arena, arch, bc); + str8_list_pushf(scratch.arena, &fmt, "ValBytecodeStream(%S)", bc_str); + } break; + + case RDI_LocationKind_AddrRegPlusU16: { + if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl) { + str8_list_pushf(scratch.arena, &fmt, "AddrRegPlusU16(\?\?\?)"); + } else { + RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; + str8_list_pushf(scratch.arena, &fmt, "AddrRegPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); + } + } break; + + case RDI_LocationKind_AddrAddrRegPlusU16: { + if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ + str8_list_pushf(scratch.arena, &fmt, "AddrAddrRegPlusU16(\?\?\?)"); + } else { + RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16 *)loc_base_ptr; + str8_list_pushf(scratch.arena, &fmt, "AddrAddrRegisterPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); + } + } break; + + case RDI_LocationKind_ValReg: { + if (loc_base_ptr + sizeof(RDI_LocationReg) > loc_data_opl) { + str8_list_pushf(scratch.arena, &fmt, "ValReg(\?\?\?)"); + } else { + RDI_LocationReg *loc = (RDI_LocationReg*)loc_base_ptr; + str8_list_pushf(scratch.arena, &fmt, "ValReg(reg: %S)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code)); + } + } break; + } + } + + String8 print_string = str8_list_join(scratch.arena, &fmt, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", print_string); + } + + scratch_end(scratch); +} + internal void rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar) { @@ -1132,15 +1361,20 @@ rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Pa } internal void -rdi_print_procedure(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc) +rdi_print_procedure(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc, RDI_Arch arch) { Temp scratch = scratch_begin(&arena, 1); - rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, proc->name_string_idx)); - rd_printf("link_name ='%S'", str8_from_rdi_string_idx(rdi, proc->link_name_string_idx)); - rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, proc->link_flags)); - rd_printf("type_idx =%u", proc->type_idx); - rd_printf("root_scope_idx=%u", proc->root_scope_idx); - rd_printf("container_idx =%u", proc->container_idx); + rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, proc->name_string_idx)); + rd_printf("link_name ='%S'", str8_from_rdi_string_idx(rdi, proc->link_name_string_idx)); + rd_printf("link_flags =%S", rdi_string_from_link_flags(scratch.arena, proc->link_flags)); + rd_printf("type_idx =%u", proc->type_idx); + rd_printf("root_scope_idx =%u", proc->root_scope_idx); + rd_printf("container_idx =%u", proc->container_idx); + rd_printf("frame_base (first=%u, opl=%u)", proc->frame_base_location_first, proc->frame_base_location_opl); + rd_indent(); + rdi_print_locations(arena, out, indent, rdi, arch, proc->frame_base_location_first, proc->frame_base_location_opl); + rd_unindent(); + scratch_end(scratch); } @@ -1152,24 +1386,22 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, U64 scope_count = 0; U64 scope_voff_count = 0; U64 local_count = 0; - U64 location_block_count = 0; - U64 location_data_size = 0; U64 proc_count = 0; + U64 inline_site_count = 0; RDI_Scope *scope_array = rdi_table_from_name(rdi, Scopes, &scope_count); U64 *scope_voff_array = rdi_table_from_name(rdi, ScopeVOffData, &scope_voff_count); RDI_Local *local_array = rdi_table_from_name(rdi, Locals, &local_count); - RDI_LocationBlock *location_block_array = rdi_table_from_name(rdi, LocationBlocks, &location_block_count); - RDI_U8 *location_data = rdi_table_from_name(rdi, LocationData, &location_data_size); - RDI_Procedure *proc_array = rdi_table_from_name(rdi, Procedures, &proc_count); + RDI_Procedure *proc_array = rdi_table_from_name(rdi, Procedures, &proc_count); + RDI_InlineSite *inline_site_array = rdi_table_from_name(rdi, InlineSites, &inline_site_count); U32 voff_range_lo = ClampTop(scope->voff_range_first, scope_voff_count); U32 voff_range_hi = ClampTop(scope->voff_range_opl, scope_voff_count); - U32 voff_range_count = (voff_range_hi - voff_range_lo) / 2; + U32 voff_range_count = (voff_range_hi - voff_range_lo); U64 *voff_ptr = scope_voff_array + voff_range_lo; String8 voff_str = rd_string_from_range_array_u64_hex(scratch.arena, voff_ptr, voff_range_count); - U64 this_idx = (U64)(scope - scope_array); - rd_printf("[%llu]", this_idx); + U64 scope_idx = (U64)(scope - scope_array); + rd_printf("scope[%llu]", scope_idx); rd_indent(); String8 proc_name = str8_lit("???"); @@ -1178,9 +1410,22 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, proc_name = str8_from_rdi_string_idx(rdi, proc->name_string_idx); } - rd_printf("proc_idx =%u '%S'", scope->proc_idx, proc_name); - rd_printf("inline_site_idx=%u", scope->inline_site_idx); - rd_printf("voff_ranges =%S", voff_str); + String8 inline_site_name = str8_lit(""); + if (scope->inline_site_idx != 0) { + if (scope->inline_site_idx < inline_site_count) { + RDI_InlineSite *inline_site = &inline_site_array[scope->inline_site_idx]; + inline_site_name = str8_from_rdi_string_idx(rdi, inline_site->name_string_idx); + } else { + inline_site_name = str8_lit("???"); + } + inline_site_name = push_str8f(scratch.arena, " '%S'", inline_site_name); + } + + rd_printf("proc_idx =%u '%S'", scope->proc_idx, proc_name); + rd_printf("first_child_scope_idx =%u", scope->first_child_scope_idx); + rd_printf("next_sibling_scope_idx=%u", scope->next_sibling_scope_idx); + rd_printf("inline_site_idx =%u%S", scope->inline_site_idx, inline_site_name); + rd_printf("voff_ranges =%S", voff_str); // local_array { @@ -1196,74 +1441,10 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, local_ptr->name_string_idx)); rd_printf("type_idx=%u", local_ptr->type_idx); - U32 block_lo = ClampTop(local_ptr->location_first, location_block_count); - U32 block_hi = ClampTop(local_ptr->location_opl, location_block_count); - if (block_lo < block_hi) { + if (local_ptr->location_first < local_ptr->location_opl) { rd_printf("locations:"); rd_indent(); - for (U32 block_idx = block_lo; block_idx < block_hi; ++block_idx) { - RDI_LocationBlock *block_ptr = &location_block_array[block_idx]; - - if (block_ptr->scope_off_first == 0 && block_ptr->scope_off_opl == max_U32) { - rd_printf("case *always*:"); - } else { - rd_printf("case [%#08x, %#08x):", block_ptr->scope_off_first, block_ptr->scope_off_opl); - } - - if (block_ptr->location_data_off >= location_data_size) { - rd_printf("", block_ptr->location_data_off); - } else { - U8 *loc_data_opl = location_data + location_data_size; - U8 *loc_base_ptr = location_data + block_ptr->location_data_off; - RDI_LocationKind kind = *(RDI_LocationKind*)loc_base_ptr; - switch (kind) { - default: { - rd_printf("\?\?\?: %u", kind); - } break; - - case RDI_LocationKind_AddrBytecodeStream: { - Temp temp = temp_begin(scratch.arena); - String8 raw_bytes = str8_cstring_capped(loc_base_ptr + 1, loc_data_opl); - rd_printf("AddrBytecodeStream: %S", rd_format_hex_array(temp.arena, raw_bytes.str, raw_bytes.size)); - temp_end(temp); - } break; - - case RDI_LocationKind_ValBytecodeStream: { - Temp temp = temp_begin(scratch.arena); - String8 raw_bytes = str8_cstring_capped(loc_base_ptr + 1, loc_data_opl); - rd_printf("ValBytecodeStream: %S", rd_format_hex_array(temp.arena, raw_bytes.str, raw_bytes.size)); - temp_end(temp); - } break; - - case RDI_LocationKind_AddrRegPlusU16: { - if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl) { - rd_printf("AddrRegPlusU16(\?\?\?)"); - } else { - RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; - rd_printf("AddrRegPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); - } - } break; - - case RDI_LocationKind_AddrAddrRegPlusU16: { - if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ - rd_printf("AddrAddrRegPlusU16(\?\?\?)"); - } else { - RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16 *)loc_base_ptr; - rd_printf("AddrAddrRegisterPlusU16(reg: %S, off: %u)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); - } - } break; - - case RDI_LocationKind_ValReg: { - if (loc_base_ptr + sizeof(RDI_LocationReg) > loc_data_opl) { - rd_printf("ValReg(\?\?\?)"); - } else { - RDI_LocationReg *loc = (RDI_LocationReg*)loc_base_ptr; - rd_printf("ValReg(reg: %S)", rdi_string_from_reg_code(scratch.arena, arch, loc->reg_code)); - } - } break; - } - } - } + rdi_print_locations(arena, out, indent, rdi, arch, local_ptr->location_first, local_ptr->location_opl); rd_unindent(); } rd_unindent(); @@ -1287,18 +1468,31 @@ rdi_print_scope(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, } rd_unindent(); - rd_printf("[/%llu]", this_idx); + rd_printf("[/%llu]", scope_idx); scratch_end(scratch); } internal void -rdi_print_inline_site(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site) +rdi_print_inline_site(Arena *arena, + String8List *out, + String8 indent, + RDI_Parsed *rdi, + U64 idx, + RDI_InlineSite *inline_site) { - rd_printf("name ='%S'", str8_from_rdi_string_idx(rdi, inline_site->name_string_idx)); - rd_printf("type_idx =%u", inline_site->type_idx); - rd_printf("owner_type_idx=%u", inline_site->owner_type_idx); - rd_printf("line_table_idx=%u", inline_site->line_table_idx); + Temp scratch = scratch_begin(&arena, 1); + String8 inline_site_idx = push_str8f(scratch.arena, "inline_site[%u]", idx); + String8 type_idx = push_str8f(scratch.arena, "type_idx = %u,", inline_site->type_idx); + String8 owner_type_idx = push_str8f(scratch.arena, "owner_type_idx = %u,", inline_site->owner_type_idx); + String8 line_table_idx = push_str8f(scratch.arena, "line_table_idx = %u,", inline_site->line_table_idx); + rd_printf("%-20S = { %-25S %-25S %-25S name = '%-20S' }", + inline_site_idx, + type_idx, + owner_type_idx, + line_table_idx, + str8_from_rdi_string_idx(rdi, inline_site->name_string_idx)); + scratch_end(scratch); } internal void @@ -1495,7 +1689,7 @@ rdi_print(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RD_Op for (U64 i = 0; i < proc_count; ++i) { rd_printf("procedure[%llu]:", i); rd_indent(); - rdi_print_procedure(arena, out, indent, rdi, &proc_array[i]); + rdi_print_procedure(arena, out, indent, rdi, &proc_array[i], tli->arch); rd_unindent(); } rd_unindent(); @@ -1531,10 +1725,7 @@ rdi_print(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RD_Op rd_printf("# INLINE SITES"); rd_indent(); for (U64 i = 0; i < inline_site_count; ++i) { - rd_printf("inline_site[%llu]:", i); - rd_indent(); - rdi_print_inline_site(arena, out, indent, rdi, &inline_site_array[i]); - rd_unindent(); + rdi_print_inline_site(arena, out, indent, rdi, i, &inline_site_array[i]); } rd_unindent(); rd_newline(); @@ -1596,8 +1787,20 @@ rdi_print(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RD_Op } } +internal String8 +dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 reg_str = dw_string_from_register(scratch.arena, arch, reg_idx); + String8 result = rd_string_from_reg_off(arena, reg_str, reg_off); + scratch_end(scratch); + return result; +} + +B32 is_global_var = 0; + internal String8List -dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { Temp scratch = scratch_begin(&arena, 1); String8List result = {0}; @@ -1634,15 +1837,16 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, case DW_ExprOp_Const8S:size_param = 8; is_signed = 1; goto const_n; const_n: { - U64 x = 0; - cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); - if (is_signed){ - U64 bit_shift = (size_param << 3) - 1; - if ((x >> bit_shift) != 0){ - x |= ~((1 << bit_shift) - 1); - } + if (is_signed) { + S64 x = 0; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + x = extend_sign64(x, size_param); + op_value = push_str8f(scratch.arena, "%lld", x); + } else { + U64 x = 0; + cursor += str8_deserial_read(raw_data, cursor, &x, size_param, 1); + op_value = push_str8f(scratch.arena, "%llu", x); } - op_value = push_str8f(scratch.arena, "%llu", x); } break; case DW_ExprOp_Addr: { @@ -1675,19 +1879,24 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { U64 reg_idx = op - DW_ExprOp_Reg0; - op_value = push_str8f(scratch.arena, "%S", dw_string_from_register(scratch.arena, arch, reg_idx)); + op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, 0); } break; case DW_ExprOp_RegX: { U64 reg_idx = 0; cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); - op_value = push_str8f(scratch.arena, "register %llu (%S)", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx)); + op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, 0); } break; case DW_ExprOp_ImplicitValue: { - U64 size = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, &size); - op_value = push_str8f(scratch.arena, "block @ %#llx with size %u", cursor, size); + U64 value_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &value_size); + Rng1U64 value_range = rng_1u64(cursor, cursor + value_size); + String8 value_data = str8_substr(raw_data, value_range); + cursor += value_size; + + String8 value_str = rd_string_from_hex_u8(scratch.arena, value_data.str, value_data.size); + op_value = push_str8f(scratch.arena, "{ %S }", value_str); } break; case DW_ExprOp_Piece: { @@ -1718,20 +1927,13 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, case DW_ExprOp_Skip: { S16 x = 0; cursor += str8_deserial_read_struct(raw_data, cursor, &x); - - S64 new_offset = (S64)cursor + x; - if (new_offset >= 0) { - cursor = (U64)new_offset; - op_value = push_str8f(scratch.arena, "constant %lld", x); - } else { - op_value = push_str8f(scratch.arena, "ERROR: negative read offset %lld", new_offset); - } + op_value = push_str8f(scratch.arena, "%+d bytes", x); } break; case DW_ExprOp_Bra: { S16 x = 0; cursor += str8_deserial_read_struct(raw_data, cursor, &x); - op_value = push_str8f(scratch.arena, "%d", x); + op_value = push_str8f(scratch.arena, "%+d", x); } break; case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: @@ -1748,7 +1950,7 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, U64 reg_idx = op - DW_ExprOp_BReg0; S64 reg_off = 0; cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - op_value = push_str8f(scratch.arena, "%S offset %lld", dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off); } break; case DW_ExprOp_FBReg: { @@ -1762,7 +1964,7 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, S64 reg_off = 0; cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - op_value = push_str8f(scratch.arena, "register %u (%S) offset %lld", reg_idx, dw_string_from_register(scratch.arena, arch, reg_idx), reg_off); + op_value = dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off); } break; case DW_ExprOp_XDerefSize: @@ -1784,13 +1986,72 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, } break; case DW_ExprOp_CallRef: { U64 x = 0; - if (is_dwarf64) { - cursor += str8_deserial_read(raw_data, cursor, &x, 8, 1); - } else { - cursor += str8_deserial_read(raw_data, cursor, &x, 4, 1); - } + cursor += str8_deserial_read_dwarf_uint(raw_data, cursor, format, &x); op_value = push_str8f(scratch.arena, "%llu", x); } break; + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + U64 info_off = 0; + cursor += str8_deserial_read_dwarf_uint(raw_data, cursor, format, &info_off); + S64 ptr = 0; + cursor += str8_deserial_read_sleb128(raw_data, cursor, &ptr); + + op_value = push_str8f(scratch.arena, ".debug_info+%#llx, ptr %llx", info_off, ptr); + } break; + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + U64 type_cu_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off); + op_value = push_str8f(scratch.arena, "TypeCuOff %#llx", cu_base + type_cu_off); + } break; + case DW_ExprOp_GNU_ParameterRef: { + // TODO: always 4 bytes? + U32 cu_off = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &cu_off); + op_value = push_str8f(scratch.arena, "CuOff %#x", cu_base + cu_off); + } break; + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { + U8 deref_size = 0; + U64 type_cu_off = 0; + cursor += str8_deserial_read_struct(raw_data, cursor, &deref_size); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off); + op_value = push_str8f(scratch.arena, "%#x, TypeCuOff %#llx", deref_size, cu_base + type_cu_off); + } break; + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { + U64 type_cu_off = 0; + U8 const_value_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off); + cursor += str8_deserial_read_struct(raw_data, cursor, &const_value_size); + Rng1U64 const_value_range = rng_1u64(cursor, cursor + const_value_size); + String8 const_value_data = str8_substr(raw_data, const_value_range); + String8 const_value_str = rd_string_from_hex_u8(scratch.arena, const_value_data.str, const_value_data.size); + op_value = push_str8f(scratch.arena, "TypeCuOff %#llx, Const Value { %S }", cu_base + type_cu_off, const_value_str); + cursor += const_value_size; + } break; + case DW_ExprOp_RegvalType: + case DW_ExprOp_GNU_RegvalType: { + U64 reg_idx = 0, type_cu_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_uleb128(raw_data, cursor, &type_cu_off); + op_value = push_str8f(scratch.arena, "%S, TypeCuOff %#llx", dw_string_from_register(scratch.arena, arch, reg_idx), cu_base + type_cu_off); + } break; + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + U64 block_size = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &block_size); + Rng1U64 block_range = rng_1u64(cursor, cursor + block_size); + String8 block_data = str8_substr(raw_data, block_range); + String8List block_expr = dw_string_list_from_expression(scratch.arena, block_data, cu_base, address_size, arch, ver, ext, format); + op_value = str8_list_join(scratch.arena, &block_expr, &(StringJoin){.pre = str8_lit("{ "), .sep = str8_lit(","), .post = str8_lit(" }")}); + cursor += block_size; + } break; + case DW_ExprOp_Addrx: { + U64 addr = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, &addr); + op_value = push_str8f(scratch.arena, "%#llx", addr); + } break; case DW_ExprOp_CallFrameCfa: case DW_ExprOp_FormTlsAddress: @@ -1827,7 +2088,7 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, // no operands } break; } - + String8 opcode_str = dw_string_from_expr_op(scratch.arena, ver, ext, op); if (op_value.size == 0) { str8_list_pushf(arena, &result, "DW_OP_%S", opcode_str); @@ -1840,17 +2101,17 @@ dw_string_list_from_expression(Arena *arena, String8 raw_data, U64 address_size, } internal String8 -dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { Temp scratch = scratch_begin(&arena, 1); - String8List list = dw_string_list_from_expression(scratch.arena, raw_data, address_size, arch, ver, ext, is_dwarf64); + String8List list = dw_string_list_from_expression(scratch.arena, raw_data, cu_base, address_size, arch, ver, ext, format); String8 expression = str8_list_join(arena, &list, &(StringJoin){.sep=str8_lit(", ")}); scratch_end(scratch); return expression; } internal void -dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64) +dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format) { Temp scratch = scratch_begin(&arena, 1); @@ -1899,14 +2160,12 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw rd_printf("DW_CFA_advance_loc4: %+u", delta * cie->code_align_factor); } break; case DW_CFA_OffsetExt: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + U64 reg_idx = 0, reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); - rd_printf("DW_CFA_offset_extended: register %llu (%S), offset %+llu", - reg, - dw_string_from_register(arena, arch, reg), - (S64)offset * cie->data_align_factor); + rd_printf("DW_CFA_offset_extended: %S register %llu (%S), offset %+llu", + dw_string_from_reg_off(scratch.arena, arch, reg_idx, (S64)reg_off * cie->data_align_factor)); } break; case DW_CFA_RestoreExt: { rd_printf("DW_CFA_restore_extended"); @@ -1921,19 +2180,14 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw U64 reg = 0; cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - rd_printf("DW_CFA_same_value: register %llu (%S)", - reg, - dw_string_from_register(scratch.arena, arch, reg)); + rd_printf("DW_CFA_same_value: %S", dw_string_from_register(scratch.arena, arch, reg)); } break; case DW_CFA_Register: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); - - rd_printf("DW_CFA_register: register %llu (%S), offset %+llu", - reg, - dw_string_from_register(scratch.arena, arch, reg), - offset); + U64 reg_idx = 0, reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); + + rd_printf("DW_CFA_register: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off)); } break; case DW_CFA_RememberState: { rd_printf("DW_CFA_remember_state"); @@ -1942,14 +2196,11 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw rd_printf("DW_CFA_restore_state"); } break; case DW_CFA_DefCfa: { - U64 reg = 0, offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); + U64 reg_idx = 0, reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_off); - rd_printf("DW_CFA_def_cfa: register %llu (%S), offset %llu", - reg, - dw_string_from_register(scratch.arena, arch, reg), - offset); + rd_printf("DW_CFA_def_cfa: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off)); } break; case DW_CFA_DefCfaRegister: { U64 reg = 0; @@ -1972,7 +2223,7 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw cursor += block_size; rd_printf("DW_CFA_def_cfa_expression: %S", - dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + dw_format_expression_single_line(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); } break; case DW_CFA_Expr: { U64 reg = 0, block_size = 0; @@ -1981,28 +2232,25 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw String8 raw_expr = str8_substr(raw_data, rng_1u64(cursor, cursor + block_size)); cursor += block_size; - rd_printf("DW_CFA_expression: register %llu (%S), expression %S", - reg, + rd_printf("DW_CFA_expression: %S, expression %S", dw_string_from_register(scratch.arena, arch, reg), - dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + dw_format_expression_single_line(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); } break; case DW_CFA_OffsetExtSf: { - U64 reg = 0; - S64 offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + U64 reg_idx = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - rd_printf("DW_CFA_offset_ext_sf: register %llu (%S), offset %+lld", - reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + rd_printf("DW_CFA_offset_ext_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor)); } break; case DW_CFA_DefCfaSf: { - U64 reg = 0; - S64 offset = 0; - cursor += str8_deserial_read_uleb128(raw_data, cursor, ®); - cursor += str8_deserial_read_sleb128(raw_data, cursor, &offset); + U64 reg_idx = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(raw_data, cursor, ®_idx); + cursor += str8_deserial_read_sleb128(raw_data, cursor, ®_off); - rd_printf("DW_CFA_def_cfa_sf: register %llu (%S), offset %+lld", - reg, dw_string_from_register(scratch.arena, arch, reg), offset * cie->data_align_factor); + rd_printf("DW_CFA_def_cfa_sf: %S", dw_string_from_reg_off(scratch.arena, arch, reg_idx, reg_off * cie->data_align_factor)); } break; case DW_CFA_ValOffset: { U64 val = 0, offset = 0; @@ -2029,7 +2277,7 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw rd_printf("DW_CFA_val_expr: value %+llu, expression %S", val, - dw_format_expression_single_line(scratch.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64)); + dw_format_expression_single_line(scratch.arena, raw_expr, 0, address_size, arch, ver, ext, format)); } break; case DW_CFA_AdvanceLoc: { rd_printf("DW_CFA_advance_loc: %+llu", operand); @@ -2039,10 +2287,10 @@ dw_print_cfi_program(Arena *arena, String8List *out, String8 indent, String8 raw cursor += str8_deserial_read_uleb128(raw_data, cursor, &offset); S64 v = (S64)offset * cie->data_align_factor; - rd_printf("DW_CFA_offset: register %llu (%S), offset %lld", operand, dw_string_from_register(arena, arch, operand), v); + rd_printf("DW_CFA_offset: %S", dw_string_from_reg_off(scratch.arena, arch, operand, v)); } break; case DW_CFA_Restore: { - rd_printf("DW_CFA_restore: register %llu (%S)", operand, dw_string_from_register(scratch.arena, arch, operand)); + rd_printf("DW_CFA_restore: %S", operand, dw_string_from_register(scratch.arena, arch, operand)); } break; default: { rd_errorf("unknown CFI opcode %u", opcode); @@ -2151,9 +2399,9 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh rd_printf("CFI Program:"); rd_indent(); - B32 is_dwarf64 = length > max_U32; - String8 raw_cfi = str8_substr(raw_eh_frame, cfi_range); - dw_print_cfi_program(scratch.arena, out, indent, raw_cfi, &cie, ptr_ctx, arch, ver, ext, is_dwarf64); + DW_Format format = DW_FormatFromSize(length); + String8 raw_cfi = str8_substr(raw_eh_frame, cfi_range); + dw_print_cfi_program(scratch.arena, out, indent, raw_cfi, &cie, ptr_ctx, arch, ver, ext, format); rd_unindent(); rd_newline(); @@ -2165,71 +2413,60 @@ dw_print_eh_frame(Arena *arena, String8List *out, String8 indent, String8 raw_eh scratch_end(scratch); } -internal DW_AttribValueResolveParams -rd_dw_resolve_params_from_comp_root(DW_CompRoot comp_root) -{ - DW_AttribValueResolveParams resolve_params = {0}; - resolve_params.version = comp_root.version; - resolve_params.addr_size = comp_root.address_size; - resolve_params.containing_unit_info_off = comp_root.info_off; - resolve_params.debug_addrs_base = comp_root.addrs_base; - resolve_params.debug_rnglists_base = comp_root.rnglist_base; - resolve_params.debug_str_offs_base = comp_root.stroffs_base; - resolve_params.debug_loclists_base = comp_root.loclist_base; - return resolve_params; -} - internal void -dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_ListUnitInput lu_input, Arch arch, B32 relaxed) { Temp scratch = scratch_begin(&arena, 1); - Rng1U64List comp_unit_ranges = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + Rng1U64List cu_ranges = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Info].data); - if (comp_unit_ranges.count > 0) { - rd_printf("# %S", sections->v[DW_Section_Info].name); + if (cu_ranges.count > 0) { + rd_printf("# %S", input->sec[DW_Section_Info].name); rd_indent(); } U64 comp_idx = 0; - for (Rng1U64Node *comp_unit_range_n = comp_unit_ranges.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + for (Rng1U64Node *cu_range_n = cu_ranges.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++comp_idx) { Temp comp_temp = temp_begin(scratch.arena); - Rng1U64 comp_unit_range = comp_unit_range_n->v; - DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); - DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + U64 cu_base = cu_range_n->v.min; + Rng1U64 cu_range = cu_range_n->v; + DW_CompUnit cu = dw_cu_from_info_off(comp_temp.arena, input, lu_input, cu_range.min, relaxed); + + String8 cu_dir = dw_string_from_attrib (input, &cu, cu.tag, DW_Attrib_CompDir ); + String8 cu_name = dw_string_from_attrib (input, &cu, cu.tag, DW_Attrib_Name ); + String8 stmt_list = dw_line_ptr_from_attrib(input, &cu, cu.tag, DW_Attrib_StmtList); + + DW_LineVMHeader line_vm = {0}; + dw_read_line_vm_header(comp_temp.arena, stmt_list, 0, input, cu_dir, cu_name, cu.address_size, cu.str_offsets_lu, &line_vm); // print comp info rd_printf("Compilation Unit #%u", comp_idx); rd_indent(); - rd_printf("Version: %u", comp_root.version); - rd_printf("Address Size: %llu", comp_root.address_size); - rd_printf("Abbrev Offset: %#llx", comp_root.abbrev_off); - rd_printf("Tags Range: %#llx-%#llx (Size %#llx)", comp_root.tags_info_range.min, comp_root.tags_info_range.max, dim_1u64(comp_root.tags_info_range)); + rd_printf("Version: %u", cu.version); + rd_printf("Address Size: %llu", cu.address_size); + rd_printf("Abbrev Offset: %#llx", cu.abbrev_off); + rd_printf("Info Range: %#llx-%#llx (%M)", cu.info_range.min, cu.info_range.max, dim_1u64(cu.info_range)); rd_newline(); // prase tags U32 tag_depth = 0; - for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + for (U64 info_off = cu.first_tag_info_off; info_off < cu.info_range.max; ) { Temp tag_temp = temp_begin(scratch.arena); - U64 tag_info_off = info_off; - DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + U64 tag_info_off = info_off; + DW_Tag tag = {0}; + info_off += dw_read_tag_cu(tag_temp.arena, input, &cu, tag_info_off, &tag); - // advance parse - info_off = tag->info_range.max; - - String8 tag_str = dw_string_from_tag_kind(tag_temp.arena, tag->kind); - rd_printf("<%x><%llx> DW_Tag_%S (Abbrev Number: %llu)", tag_depth, tag_info_off, tag_str, tag->abbrev_id); + String8 tag_str = dw_string_from_tag_kind(tag_temp.arena, tag.kind); + rd_printf("<%x><%llx> DW_Tag_%S (Abbrev Number: %llu)", tag_depth, tag_info_off, tag_str, tag.abbrev_id); rd_indent(); // parse attributes - for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + for (DW_AttribNode *attrib_n = tag.attribs.first; attrib_n != 0; attrib_n = attrib_n->next) { Temp attrib_temp = temp_begin(tag_temp.arena); - DW_Attrib *attrib = &attrib_node->attrib; - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); + DW_Attrib *attrib = &attrib_n->v; String8List attrib_list = {0}; @@ -2237,10 +2474,10 @@ dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionAr str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx> ", attrib->info_off); // attribute kind - String8 attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, comp_root.version, ext, attrib->attrib_kind); + String8 attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, cu.version, cu.ext, attrib->attrib_kind); if (attrib_kind_str.size == 0) { if (relaxed) { - attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, DW_Version_Last, ext, attrib->attrib_kind); + attrib_kind_str = dw_string_from_attrib_kind(attrib_temp.arena, DW_Version_Last, cu.ext, attrib->attrib_kind); } } if (attrib_kind_str.size == 0) { @@ -2250,89 +2487,165 @@ dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionAr } // form kind - String8 form_kind_str = dw_string_from_form_kind(scratch.arena, comp_root.version, attrib->form_kind); + String8 form_kind_str = dw_string_from_form_kind(scratch.arena, cu.version, attrib->form_kind); str8_list_pushf(attrib_temp.arena, &attrib_list, "DW_Form_%-15S", form_kind_str); - switch (attrib->value_class) { + DW_AttribClass value_class = dw_value_class_from_attrib(&cu, attrib); + switch (value_class) { default: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Unknown value class"); + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: unknown value class"); } break; case DW_AttribClass_Undefined: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: Undefined value class"); + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: undefined value class"); } break; case DW_AttribClass_Address: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + U64 address = dw_address_from_attrib_ptr(input, &cu, attrib); + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", address); } break; case DW_AttribClass_Block: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx %#llx", attrib_value.v[0], attrib_value.v[1]); + String8 block = dw_block_from_attrib_ptr(input, &cu, attrib); + String8 block_str = rd_string_from_hex_u8(attrib_temp.arena, block.str, block.size); + str8_list_pushf(attrib_temp.arena, &attrib_list, "%S", block_str); } break; case DW_AttribClass_Const: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); - switch (attrib->attrib_kind) { - case DW_Attrib_Language: { - String8 lang_str = dw_string_from_language(attrib_temp.arena, attrib_value.v[0]); - str8_list_pushf(attrib_temp.arena, &attrib_list, " (%S)", lang_str); - } break; - } + U64 constant = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", constant); } break; case DW_AttribClass_ExprLoc: { - DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Info); - Rng1U64 sect_range = rng_1u64(0, sections->v[DW_Section_Info].data.size); - Rng1U64 expr_range = rng_1u64(sect_range.min+attrib_value.v[0], sect_range.min+attrib_value.v[0]+attrib_value.v[1]); - String8 raw_expr = str8_substr(sections->v[DW_Section_Info].data, expr_range); - B32 is_dwarf64 = mode == DW_Mode_32Bit ? 1 : 0; - String8 expression = dw_format_expression_single_line(attrib_temp.arena, raw_expr, comp_root.address_size, arch, comp_root.version, ext, is_dwarf64); - str8_list_push(attrib_temp.arena, &attrib_list, expression); + String8 exprloc = dw_exprloc_from_attrib_ptr(input, &cu, attrib); + String8 exprloc_str = dw_format_expression_single_line(attrib_temp.arena, exprloc, cu_base, cu.address_size, arch, cu.version, cu.ext, cu.format); + str8_list_push(attrib_temp.arena, &attrib_list, exprloc_str); } break; case DW_AttribClass_Flag: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + B32 flag = dw_flag_from_attrib_ptr(input, &cu, attrib); + str8_list_pushf(attrib_temp.arena, &attrib_list, "%llu (%s)", flag, flag == 0 ? "false" : "true"); } break; case DW_AttribClass_LinePtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: unexpected form %S", dw_string_from_form_kind(attrib_temp.arena, cu.version, attrib->form_kind)); + } } break; case DW_AttribClass_LocListPtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: unexpected form %S", dw_string_from_form_kind(attrib_temp.arena, cu.version, attrib->form_kind)); + } } break; case DW_AttribClass_MacPtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "\?\?\?"); + } } break; case DW_AttribClass_RngListPtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "\?\?\?"); + } } break; case DW_AttribClass_RngList: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "\?\?\?"); + } } break; case DW_AttribClass_Reference: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx>", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_Ref1 || + attrib->form_kind == DW_Form_Ref2 || + attrib->form_kind == DW_Form_Ref4 || + attrib->form_kind == DW_Form_Ref8 || + attrib->form_kind == DW_Form_RefUData) { + U64 info_off = cu.info_range.min + attrib->form.ref; + str8_list_pushf(attrib_temp.arena, &attrib_list, "<%llx>", info_off); + if (!contains_1u64(cu.info_range, attrib->form.ref)) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "(ERROR: out of bounds reference)"); + } + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.ref); + } } break; case DW_AttribClass_String: { - String8 string = dw_string_from_attrib_value(sections, attrib_value); - str8_list_pushf(attrib_temp.arena, &attrib_list, "\"%S\"", string); + if (attrib->form_kind == DW_Form_Strp) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } + String8 string = dw_string_from_attrib_ptr(input, &cu, attrib); + str8_list_pushf(attrib_temp.arena, &attrib_list, "(%S)", string); } break; case DW_AttribClass_StrOffsetsPtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: unexpected form %S", dw_string_from_form_kind(attrib_temp.arena, cu.version, attrib->form_kind)); + } } break; case DW_AttribClass_AddrPtr: { - str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib_value.v[0]); + if (attrib->form_kind == DW_Form_SecOffset) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "%#llx", attrib->form.sec_offset); + } else { + str8_list_pushf(attrib_temp.arena, &attrib_list, "ERROR: unexpected form %S", dw_string_from_form_kind(attrib_temp.arena, cu.version, attrib->form_kind)); + } } break; } - String8 print = str8_list_join(attrib_temp.arena, &attrib_list, 0); + String8 attrib_str = {0}; + switch (attrib->attrib_kind) { + case DW_Attrib_Language: { + DW_Language lang = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = dw_string_from_language(attrib_temp.arena, lang); + } break; + case DW_Attrib_DeclFile: { + U64 file_idx = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + DW_LineFile *file = dw_file_from_attrib_ptr(&cu, &line_vm, attrib); + attrib_str = str8_lit("\?\?\?"); + if (file) { + attrib_str = dw_path_from_file(attrib_temp.arena, &line_vm, file); + } + } break; + case DW_Attrib_DeclLine: { + U64 line = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = push_str8f(attrib_temp.arena, "%llu", line); + } break; + case DW_Attrib_Inline: { + DW_InlKind inl = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = dw_string_from_inl(attrib_temp.arena, inl); + } break; + case DW_Attrib_Accessibility: { + DW_AccessKind access = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = dw_string_from_access_kind(attrib_temp.arena, access); + } break; + case DW_Attrib_CallingConvention: { + DW_CallingConventionKind calling_convetion = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = dw_string_from_calling_convetion(attrib_temp.arena, calling_convetion); + } break; + case DW_Attrib_Encoding: { + DW_ATE encoding = dw_const_u64_from_attrib_ptr(input, &cu, attrib); + attrib_str = dw_string_from_attrib_type_encoding(attrib_temp.arena, encoding); + } break; + } + + if (attrib_str.size) { + str8_list_pushf(attrib_temp.arena, &attrib_list, "(%S)", attrib_str); + } + String8 print = str8_list_join(attrib_temp.arena, &attrib_list, &(StringJoin){.sep=str8_lit(" ")}); rd_printf("%S", print); temp_end(attrib_temp); } - B32 is_ender_tag = tag->abbrev_id == 0; - - if (tag->has_children) { + B32 is_ender_tag = tag.abbrev_id == 0; + if (tag.has_children) { if (is_ender_tag) { rd_errorf("null-tag cannot have children"); } rd_indent(); tag_depth += 1; } - if (is_ender_tag) { if (tag_depth == 0) { rd_errorf("malformed data detected, too many null tags"); @@ -2343,7 +2656,6 @@ dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionAr } rd_unindent(); - temp_end(tag_temp); } temp_end(comp_temp); @@ -2352,7 +2664,7 @@ dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionAr rd_newline(); } - if (comp_unit_ranges.count > 0) { + if (cu_ranges.count > 0) { rd_unindent(); } @@ -2360,19 +2672,21 @@ dw_print_debug_info(Arena *arena, String8List *out, String8 indent, DW_SectionAr } internal void -dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_Input *input) { Temp scratch = scratch_begin(&arena, 1); - DW_Section abbrev = sections->v[DW_Section_Abbrev]; + DW_Section abbrev = input->sec[DW_Section_Abbrev]; String8 raw_abbrev = abbrev.data; if (raw_abbrev.size) { - rd_printf("# %S", sections->v[DW_Section_Abbrev].name); + rd_printf("# %S", input->sec[DW_Section_Abbrev].name); rd_indent(); } for (U64 cursor = 0; cursor < raw_abbrev.size; ) { + U64 id_off = cursor; + U64 id = 0; cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &id); @@ -2387,9 +2701,11 @@ dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_Section cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &tag); cursor += str8_deserial_read_struct(raw_abbrev, cursor, &has_children); - rd_printf("%llu DW_Tag_%S %s", id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "[has children]" : "[no children]"); + rd_printf("<%llx> %llu DW_Tag_%S %s", id_off, id, dw_string_from_tag_kind(temp.arena, tag), has_children ? "[has children]" : "[no children]"); rd_indent(); for (;;) { + U64 attrib_off = cursor; + U64 attrib_id = 0, form_id = 0; cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &attrib_id); cursor += str8_deserial_read_uleb128(raw_abbrev, cursor, &form_id); @@ -2398,7 +2714,7 @@ dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_Section } String8 attrib_str = dw_string_from_attrib_kind(temp.arena, DW_Version_Last, DW_Ext_All, attrib_id); String8 form_str = dw_string_from_form_kind(temp.arena, DW_Version_Last, form_id); - rd_printf("DW_Attrib_%-20S DW_Form_%S", attrib_str, form_str); + rd_printf("<%llx> DW_Attrib_%-20S DW_Form_%S", attrib_off, attrib_str, form_str); } rd_unindent(); @@ -2413,282 +2729,287 @@ dw_print_debug_abbrev(Arena *arena, String8List *out, String8 indent, DW_Section } internal void -dw_print_debug_line(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed) +dw_print_debug_line(Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_ListUnitInput lu_input, B32 relaxed) { Temp scratch = scratch_begin(&arena, 1); - DW_Mode mode = dw_mode_from_sec(sections, DW_Section_Line); - Rng1U64 range = dw_range_from_sec(sections, DW_Section_Line); - void *base = dw_base_from_sec(sections, DW_Section_Line); - Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + rd_printf("# .debug_line"); - if (dim_1u64(range)) { - rd_printf("# %S", sections->v[DW_Section_Line].name); - rd_indent(); - } + Rng1U64List unit_ranges = dw_unit_ranges_from_data(scratch.arena, input->sec[DW_Section_Line].data); + for (Rng1U64Node *unit_range_n = unit_ranges.first; unit_range_n != 0; unit_range_n = unit_range_n->next) { + Temp unit_temp = temp_begin(scratch.arena); - U64 cursor = 0; - for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next) { - Temp comp_temp = temp_begin(scratch.arena); + String8 unit_data = str8_substr(input->sec[DW_Section_Line].data, unit_range_n->v); + String8 cu_dir = {0}; + String8 cu_name = {0}; + DW_ListUnit cu_str_offsets = {0}; + DW_LineVMHeader line_vm = {0}; + U64 line_vm_size = dw_read_line_vm_header(unit_temp.arena, unit_data, 0, input, cu_dir, cu_name, line_vm.address_size, &cu_str_offsets, &line_vm); - Rng1U64 comp_unit_range = comp_unit_range_n->v; - U64 line_table_offset = cursor; - DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); - - DW_LineVMHeader vm_header = {0}; - cursor += dw_read_line_vm_header(arena, base, range, cursor, mode, sections, resolve_params, comp_root.compile_dir, comp_root.name, &vm_header); - - if (vm_header.unit_length == 0) { + if (line_vm_size == 0) { continue; } - rd_printf("Line table offset: %#llx", line_table_offset); - rd_printf("Line table length: %llu", vm_header.unit_length); - rd_printf("Version: %u", vm_header.version); - rd_printf("Address size: %u", vm_header.address_size); - rd_printf("Segment selector size: %u", vm_header.segment_selector_size); - rd_printf("Header length: %llu", vm_header.header_length); - rd_printf("Program offset: %#llx", vm_header.program_off); - rd_printf("Min instruction length: %u", vm_header.min_inst_len); - rd_printf("Max ops for instruction: %u", vm_header.max_ops_for_inst); - rd_printf("Default Is Stmt: %u", vm_header.default_is_stmt); - rd_printf("Line base: %d", vm_header.line_base); - rd_printf("Line range: %u", vm_header.line_range); - rd_printf("Opcode base: %u", vm_header.opcode_base); - rd_printf("Opcode lengths: %S", rd_format_hex_array(comp_temp.arena, vm_header.opcode_lens, vm_header.num_opcode_lens)); - rd_newline(); - - rd_printf("Directory Table:"); - rd_indent(); - rd_printf("%-4s %-8s", "No.", "String"); - for (U64 dir_idx = 0; dir_idx < vm_header.dir_table.count; ++dir_idx) { - rd_printf("%-4llu %S", dir_idx, vm_header.dir_table.v[dir_idx]); + { + rd_printf("Header:", line_vm_size); + rd_indent(); + String8 opcode_lengths = rd_format_hex_array(unit_temp.arena, line_vm.opcode_lens, line_vm.num_opcode_lens); + rd_printf("Version: %u", line_vm.version ); + rd_printf("Line table offset: %#llx", line_vm.unit_range.min ); + rd_printf("Line table length: %llu", dim_1u64(line_vm.unit_range) ); + rd_printf("Version: %u", line_vm.version ); + rd_printf("Address size: %u", line_vm.address_size ); + rd_printf("Segment selector size: %u", line_vm.segment_selector_size); + rd_printf("Header length: %llu", line_vm.header_length ); + rd_printf("Min instruction length: %u", line_vm.min_inst_len ); + rd_printf("Max ops for instruction: %u", line_vm.max_ops_for_inst ); + rd_printf("Default Is Stmt: %u", line_vm.default_is_stmt ); + rd_printf("Line base: %d", line_vm.line_base ); + rd_printf("Line range: %u", line_vm.line_range ); + rd_printf("Opcode base: %u", line_vm.opcode_base ); + rd_printf("Opcode lengths: %S", opcode_lengths ); + rd_unindent(); + rd_newline(); } - rd_unindent(); - rd_newline(); - rd_printf("File Table:"); - rd_indent(); - rd_printf("%-4s %-8s %-8s %-17s %-8s %-8s", "No.", "DirIdx", "Time", "MD5", "Size", "Name"); - for (U64 file_idx = 0; file_idx < vm_header.file_table.count; ++file_idx) { - DW_LineFile *file = &vm_header.file_table.v[file_idx]; - rd_printf("%-4llu %-8llu %-8llu %08llx-%08llx %-8llu %S", - file_idx, - file->dir_idx, - file->modify_time, - file->md5_digest[0], - file->md5_digest[1], - file->file_size, - file->file_name); + { + rd_printf("Directory Table:"); + rd_indent(); + rd_printf("%-4s %-8s", "No.", "String"); + for (U64 dir_idx = 0; dir_idx < line_vm.dir_table.count; ++dir_idx) { + rd_printf("%-4llu %S", dir_idx, line_vm.dir_table.v[dir_idx]); + } + rd_unindent(); + rd_newline(); } - rd_unindent(); - rd_newline(); - B32 end_of_seq = 0; - DW_LineVMState vm_state = {0}; - dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); + { + rd_printf("File Table:"); + rd_indent(); + rd_printf("%-4s %-8s %-8s %-33s %-8s %-8s", "No.", "DirIdx", "Time", "MD5", "Size", "Name"); + for (U64 file_idx = 0; file_idx < line_vm.file_table.count; ++file_idx) { + DW_LineFile *file = &line_vm.file_table.v[file_idx]; + rd_printf("%-4llu %-8llu %-8llu %016llx-%016llx %-8llu %S", + file_idx, + file->dir_idx, + file->modify_time, + file->md5_digest.u64[1], + file->md5_digest.u64[0], + file->file_size, + file->file_name); + } + rd_unindent(); + rd_newline(); + } - rd_printf("Opcodes:"); - for (; cursor < vm_header.unit_opl; ) { - U64 opcode_offset = cursor; + { + rd_printf("Opcodes:"); + rd_indent(); - Temp opcode_temp = temp_begin(scratch.arena); + String8 opcodes = str8_skip(unit_data, line_vm_size); + B32 end_of_seq = 0; + DW_LineVMState vm_state = {0}; + dw_line_vm_reset(&vm_state, line_vm.default_is_stmt); - String8List list = {0}; + for (U64 cursor = 0; cursor < opcodes.size; ) { + Temp opcode_temp = temp_begin(unit_temp.arena); - // parse opcode - U8 opcode = 0; - cursor += dw_based_range_read_struct(base, range, cursor, &opcode); + String8List opcode_fmt = {0}; - // push opcode id - String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, opcode); - str8_list_push(arena, &list, opcode_str); - - // format operands - switch (opcode) { - default: { - if (opcode >= vm_header.opcode_base) { - U32 adjusted_opcode = 0; - U32 op_advance = 0; - S32 line_advance = 0; - U64 addr_advance = 0; - if (vm_header.line_range > 0 && vm_header.max_ops_for_inst > 0) { - adjusted_opcode = (U32)(opcode - vm_header.opcode_base); - op_advance = adjusted_opcode / vm_header.line_range; - line_advance = (S32)vm_header.line_base + ((S32)adjusted_opcode) % (S32)vm_header.line_range; - addr_advance = vm_header.min_inst_len * ((vm_state.op_index+op_advance) / vm_header.max_ops_for_inst); + // opcode offset + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "[%08llx]", cursor); + + // parse opcode + U8 opcode = 0; + cursor += str8_deserial_read_struct(opcodes, cursor, &opcode); + + // push opcode id + String8 opcode_str = dw_string_from_std_opcode(opcode_temp.arena, opcode); + str8_list_push(arena, &opcode_fmt, opcode_str); + + // format operands + switch (opcode) { + default: { + if (opcode >= line_vm.opcode_base) { + U32 adjusted_opcode = 0; + U32 op_advance = 0; + S32 line_advance = 0; + U64 addr_advance = 0; + if (line_vm.line_range > 0 && line_vm.max_ops_for_inst > 0) { + adjusted_opcode = (U32)(opcode - line_vm.opcode_base); + op_advance = adjusted_opcode / line_vm.line_range; + line_advance = (S32)line_vm.line_base + ((S32)adjusted_opcode) % (S32)line_vm.line_range; + addr_advance = line_vm.min_inst_len * ((vm_state.op_index+op_advance) / line_vm.max_ops_for_inst); + } + + vm_state.address += addr_advance; + vm_state.op_index = (vm_state.op_index + op_advance) % line_vm.max_ops_for_inst; + vm_state.line = (U32)((S32)vm_state.line + line_advance); + vm_state.basic_block = 0; + vm_state.prologue_end = 0; + vm_state.epilogue_begin = 0; + vm_state.discriminator = 0; + + end_of_seq = 0; + + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance line by %d, advance address by %lld", line_advance, addr_advance); + } else { + if (opcode > 0 && opcode <= line_vm.num_opcode_lens) { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "skip operands:"); + U64 num_operands = line_vm.opcode_lens[opcode - 1]; + for (U8 i = 0; i < num_operands; i += 1){ + U64 operand = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &operand); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, " %llx", operand); + } + } } + }break; - vm_state.address += addr_advance; - vm_state.op_index = (vm_state.op_index + op_advance) % vm_header.max_ops_for_inst; - vm_state.line = (U32)((S32)vm_state.line + line_advance); + case DW_StdOpcode_Copy: { + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "Line = %u, Column = %u, Address = %#llx", vm_state.line, vm_state.column, vm_state.address); + end_of_seq = 0; + vm_state.discriminator = 0; vm_state.basic_block = 0; vm_state.prologue_end = 0; vm_state.epilogue_begin = 0; - vm_state.discriminator = 0; - - end_of_seq = 0; - - str8_list_pushf(opcode_temp.arena, &list, "advance line by %d, advance address by %lld", line_advance, addr_advance); - } else { - if (opcode > 0 && opcode <= vm_header.num_opcode_lens) { - str8_list_pushf(opcode_temp.arena, &list, "skip operands:"); - U64 num_operands = vm_header.opcode_lens[opcode - 1]; - for (U8 i = 0; i < num_operands; i += 1){ - U64 operand = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &operand); - str8_list_pushf(opcode_temp.arena, &list, " %llx", operand); - } - } - } - }break; - - case DW_StdOpcode_Copy: { - str8_list_pushf(opcode_temp.arena, &list, "Line = %u, Column = %u, Address = %#llx", vm_state.line, vm_state.column, vm_state.address); - end_of_seq = 0; - vm_state.discriminator = 0; - vm_state.basic_block = 0; - vm_state.prologue_end = 0; - vm_state.epilogue_begin = 0; - } break; - case DW_StdOpcode_AdvancePc: { - U64 advance = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &advance); - dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); - str8_list_pushf(opcode_temp.arena, &list, "advance %#llx ; current address %#llx", advance, vm_state.address); - } break; - - case DW_StdOpcode_AdvanceLine: { - S64 advance = 0; - cursor += dw_based_range_read_sleb128(base, range, cursor, &advance); - vm_state.line += advance; - str8_list_pushf(opcode_temp.arena, &list, "advance %lld ; current line %u", advance, vm_state.line); - } break; - - case DW_StdOpcode_SetFile: { - U64 file_idx = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &file_idx); - vm_state.file_index = file_idx; - - String8 path = dw_path_from_file_idx(opcode_temp.arena, &vm_header, file_idx); - str8_list_pushf(opcode_temp.arena, &list, "%llu \"%S\"", file_idx, path); - } break; - - case DW_StdOpcode_SetColumn: { - U64 column = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &column); - vm_state.column = column; - str8_list_pushf(opcode_temp.arena, &list, "%llu", column); - } break; - - case DW_StdOpcode_NegateStmt: { - vm_state.is_stmt = !vm_state.is_stmt; - str8_list_pushf(opcode_temp.arena, &list, "is_stmt = %u", vm_state.is_stmt); - } break; - - case DW_StdOpcode_SetBasicBlock: { - vm_state.basic_block = 1; - } break; - - case DW_StdOpcode_ConstAddPc: { - U64 advance = (0xffu - vm_header.opcode_base)/vm_header.line_range; - dw_line_vm_advance(&vm_state, advance, vm_header.min_inst_len, vm_header.max_ops_for_inst); - str8_list_pushf(opcode_temp.arena, &list, "%lld ; address %#llx", advance, vm_state.address); - }break; - - case DW_StdOpcode_FixedAdvancePc: { - U64 operand = 0; - cursor += dw_based_range_read_struct(base, range, cursor, &operand); - vm_state.address += operand; - vm_state.op_index = 0; - str8_list_pushf(opcode_temp.arena, &list, "%llu", operand); - } break; - - case DW_StdOpcode_SetPrologueEnd: { - vm_state.prologue_end = 1; - } break; - - case DW_StdOpcode_SetEpilogueBegin: { - vm_state.epilogue_begin = 1; - } break; - - case DW_StdOpcode_SetIsa: { - U64 v = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &v); - vm_state.isa = v; - str8_list_pushf(opcode_temp.arena, &list, "%llu", v); - } break; - - case DW_StdOpcode_ExtendedOpcode: { - U64 length = 0; - U8 ext_opcode = 0; - - cursor += dw_based_range_read_uleb128(base, range, cursor, &length); - U64 opcode_end = cursor + length; - - cursor += dw_based_range_read_struct(base, range, cursor, &ext_opcode); - - String8 ext_opcode_str = dw_string_from_ext_opcode(opcode_temp.arena, ext_opcode); - //str8_list_pushf(opcode_temp.arena, &list, "length: %u", length); - str8_list_push(opcode_temp.arena, &list, ext_opcode_str); - switch (ext_opcode) { - case DW_ExtOpcode_EndSequence: { - vm_state.end_sequence = 1; - dw_line_vm_reset(&vm_state, vm_header.default_is_stmt); - end_of_seq = 1; } break; - case DW_ExtOpcode_SetAddress: { - U64 address = 0; - cursor += dw_based_range_read(base, range, cursor, comp_root.address_size, &address); - vm_state.address = address; - vm_state.op_index = 0; - vm_state.busted_seq = address != 0; - str8_list_pushf(opcode_temp.arena, &list, "%#llx", address); + case DW_StdOpcode_AdvancePc: { + U64 advance = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &advance); + dw_line_vm_advance(&vm_state, advance, line_vm.min_inst_len, line_vm.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %#llx ; current address %#llx", advance, vm_state.address); } break; - case DW_ExtOpcode_DefineFile: { - String8 file_name = dw_based_range_read_string(base, range, cursor); - cursor += file_name.size + 1; - U64 dir_idx = 0, modify_time = 0, file_size = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &dir_idx); - cursor += dw_based_range_read_uleb128(base, range, cursor, &modify_time); - cursor += dw_based_range_read_uleb128(base, range, cursor, &file_size); - str8_list_pushf(opcode_temp.arena, &list, "%S Dir: %llu, Time: %llu, Size: %llu", file_name, dir_idx, modify_time, file_size); + + case DW_StdOpcode_AdvanceLine: { + S64 advance = 0; + cursor += str8_deserial_read_sleb128(opcodes, cursor, &advance); + vm_state.line += advance; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "advance %lld ; current line %u", advance, vm_state.line); } break; - case DW_ExtOpcode_SetDiscriminator: { + + case DW_StdOpcode_SetFile: { + U64 file_idx = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &file_idx); + vm_state.file_index = file_idx; + + String8 path = dw_path_from_file_idx(opcode_temp.arena, &line_vm, file_idx); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu \"%S\"", file_idx, path); + } break; + + case DW_StdOpcode_SetColumn: { + U64 column = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &column); + vm_state.column = column; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", column); + } break; + + case DW_StdOpcode_NegateStmt: { + vm_state.is_stmt = !vm_state.is_stmt; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "is_stmt = %u", vm_state.is_stmt); + } break; + + case DW_StdOpcode_SetBasicBlock: { + vm_state.basic_block = 1; + } break; + + case DW_StdOpcode_ConstAddPc: { + U64 advance = (0xffu - line_vm.opcode_base)/line_vm.line_range; + dw_line_vm_advance(&vm_state, advance, line_vm.min_inst_len, line_vm.max_ops_for_inst); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%lld ; address %#llx", advance, vm_state.address); + }break; + + case DW_StdOpcode_FixedAdvancePc: { + U64 operand = 0; + cursor += str8_deserial_read_struct(opcodes, cursor, &operand); + vm_state.address += operand; + vm_state.op_index = 0; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", operand); + } break; + + case DW_StdOpcode_SetPrologueEnd: { + vm_state.prologue_end = 1; + } break; + + case DW_StdOpcode_SetEpilogueBegin: { + vm_state.epilogue_begin = 1; + } break; + + case DW_StdOpcode_SetIsa: { U64 v = 0; - cursor += dw_based_range_read_uleb128(base, range, cursor, &v); - vm_state.discriminator = v; - str8_list_pushf(arena, &list, "%llu", v); + cursor += str8_deserial_read_uleb128(opcodes, cursor, &v); + vm_state.isa = v; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%llu", v); + } break; + + case DW_StdOpcode_ExtendedOpcode: { + U64 length = 0; + U8 ext_opcode = 0; + + cursor += str8_deserial_read_uleb128(opcodes, cursor, &length); + U64 opcode_end = cursor + length; + + cursor += str8_deserial_read_struct(opcodes, cursor, &ext_opcode); + + String8 ext_opcode_str = dw_string_from_ext_opcode(opcode_temp.arena, ext_opcode); + //str8_list_pushf(opcode_temp.arena, &opcode_fmt, "length: %u", length); + str8_list_push(opcode_temp.arena, &opcode_fmt, ext_opcode_str); + switch (ext_opcode) { + case DW_ExtOpcode_EndSequence: { + vm_state.end_sequence = 1; + dw_line_vm_reset(&vm_state, line_vm.default_is_stmt); + end_of_seq = 1; + } break; + case DW_ExtOpcode_SetAddress: { + U64 address = 0; + cursor += str8_deserial_read(opcodes, cursor, &address, line_vm.address_size, line_vm.address_size); + vm_state.address = address; + vm_state.op_index = 0; + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%#llx", address); + } break; + case DW_ExtOpcode_DefineFile: { + String8 file_name = {0}; + cursor += str8_deserial_read_cstr(opcodes, cursor, &file_name); + + U64 dir_idx = 0, modify_time = 0, file_size = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &dir_idx); + cursor += str8_deserial_read_uleb128(opcodes, cursor, &modify_time); + cursor += str8_deserial_read_uleb128(opcodes, cursor, &file_size); + str8_list_pushf(opcode_temp.arena, &opcode_fmt, "%S Dir: %llu, Time: %llu, Size: %llu", file_name, dir_idx, modify_time, file_size); + } break; + case DW_ExtOpcode_SetDiscriminator: { + U64 v = 0; + cursor += str8_deserial_read_uleb128(opcodes, cursor, &v); + vm_state.discriminator = v; + str8_list_pushf(arena, &opcode_fmt, "%llu", v); + } break; + } + + cursor = opcode_end; } break; } - cursor = opcode_end; - } break; + String8 string = str8_list_join(opcode_temp.arena, &opcode_fmt, &(StringJoin){.sep=str8_lit(" ")}); + rd_printf("%S", string); + + temp_end(opcode_temp); } - String8 string = str8_list_join(opcode_temp.arena, &list, &(StringJoin){.sep=str8_lit(" ")}); - rd_printf("[%08llx] %S", opcode_offset, string); - - temp_end(opcode_temp); + rd_unindent(); + rd_newline(); } - temp_end(comp_temp); - rd_newline(); - } - - if (dim_1u64(range)) { - rd_unindent(); + temp_end(unit_temp); } scratch_end(scratch); } internal void -dw_print_debug_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_str(Arena *arena, String8List *out, String8 indent, DW_Input *input) { - String8 data = sections->v[DW_Section_Str].data; - rd_printf("# %S", sections->v[DW_Section_Str].name); + String8 data = input->sec[DW_Section_Str].data; + rd_printf("# %S", input->sec[DW_Section_Str].name); rd_indent(); for (U64 cursor = 0, read_size = 0; cursor < data.size; cursor += read_size) { String8 string = {0}; @@ -2699,10 +3020,11 @@ dw_print_debug_str(Arena *arena, String8List *out, String8 indent, DW_SectionArr } internal void -dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ImageType image_type, B32 relaxed) { - DW_Section info = sections->v[DW_Section_Info]; - DW_Section loc = sections->v[DW_Section_Loc]; +#if 0 + DW_Section info = input->sec[DW_Section_Info]; + DW_Section loc = input->sec[DW_Section_Loc]; if (loc.data.size == 0) { return; @@ -2710,55 +3032,54 @@ dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArr Temp scratch = scratch_begin(&arena, 1); - rd_printf("# %S", sections->v[DW_Section_Loc].name); + rd_printf("# %S", input->sec[DW_Section_Loc].name); rd_indent(); // TODO: warn about overlaps in ranges - Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, info); + Rng1U64List cu_range_list = dw_comp_unit_ranges_from_info(scratch.arena, info); // parse debug_info for attributes with LOCLIST and store .debug_loc offsets - U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); - U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); - U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); - DW_Version *ver_arr = push_array(scratch.arena, DW_Version, comp_unit_range_list.count); - DW_Ext *ext_arr = push_array(scratch.arena, DW_Ext, comp_unit_range_list.count); + U64List *loc_lists = push_array(scratch.arena, U64List, cu_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, cu_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, cu_range_list.count); + U64 *cu_bases = push_array(scratch.arena, U64, cu_range_list.count); + DW_Version *ver_arr = push_array(scratch.arena, DW_Version, cu_range_list.count); + DW_Ext *ext_arr = push_array(scratch.arena, DW_Ext, cu_range_list.count); U64 comp_idx = 0; - for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { + for (Rng1U64Node *cu_range_n = cu_range_list.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++comp_idx) { Temp comp_temp = temp_begin(arena); - Rng1U64 comp_unit_range = comp_unit_range_n->v; - DW_CompRoot comp_root = dw_comp_root_from_range(comp_temp.arena, sections, comp_unit_range, relaxed); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); + Rng1U64 cu_range = cu_range_n->v; + DW_CompUnit cu = dw_comp_unit_from_info_off(comp_temp.arena, input, cu_range.min, relaxed); // store info about comp unit - address_sizes[comp_idx] = comp_root.address_size; - address_bases[comp_idx] = comp_root.base_addr; - ver_arr[comp_idx] = comp_root.version; - ext_arr[comp_idx] = dw_ext_from_params(comp_root.producer, arch, image_type); + address_sizes[comp_idx] = cu.address_size; + address_bases[comp_idx] = cu.base_addr; + ver_arr[comp_idx] = cu.version; + cu_bases[comp_idx] = cu_range_n->v.min; // parse tags - for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { + for (U64 info_off = cu.tags_range.min; info_off < cu.tags_range.max; /* empty */) { Temp tag_temp = temp_begin(scratch.arena); - DW_Tag *tag = dw_tag_from_info_offset(tag_temp.arena, sections, comp_root.abbrev_table, ver_arr[comp_idx], ext_arr[comp_idx], comp_root.language, comp_root.address_size, info_off, relaxed); + DW_Tag tag = dw_tag_from_info_offset_cu(tag_temp.arena, input, &cu, ext_arr[comp_idx], info_off); // parse attribs - for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { - DW_Attrib *attrib = &attrib_node->attrib; + for (DW_AttribNode *attrib_node = tag.attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->v; B32 is_sect_offset = attrib->value_class == DW_AttribClass_LocListPtr || (attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_SecOffset); B32 is_sect_index = attrib->value_class == DW_AttribClass_LocList && attrib->form_kind == DW_Form_LocListx; if (is_sect_offset) { - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); - u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib->value.v[0]); } else if (is_sect_index) { // TODO: support for section indexing } } // advance to next tag - info_off = tag->info_range.max; + info_off = tag.next_info_off; temp_end(tag_temp); } @@ -2766,13 +3087,13 @@ dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArr temp_end(comp_temp); } - void *base = dw_base_from_sec(sections, DW_Section_Loc); - Rng1U64 range = dw_range_from_sec(sections, DW_Section_Loc); + void *base = dw_base_from_sec(input, DW_Section_Loc); + Rng1U64 range = dw_range_from_sec(input, DW_Section_Loc); - rd_printf("%S:", dw_string_from_section_kind(scratch.arena, DW_Section_Loc)); + rd_printf(".debug_loc"); rd_indent(); rd_printf("%-8s %-8s %-8s %s", "Offset", "Min", "Max", "Expression"); - for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + for (U32 comp_idx = 0; comp_idx < cu_range_list.count; ++comp_idx) { Temp locs_temp = temp_begin(scratch.arena); DW_Version ver = ver_arr[comp_idx]; @@ -2806,8 +3127,6 @@ dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArr } else if (v0 == base_selector) { base_address = v1; } else { - // this is not mentioned in the spec (june 10, 2010) - // found reference in gdb/binutils/dwarf.c => display_loc_list U16 expr_size = 0; cursor += dw_based_range_read_struct(base, range, cursor, &expr_size); Rng1U64 expr_range = rng_1u64(range.min+cursor, range.min+cursor+expr_size); @@ -2816,7 +3135,7 @@ dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArr // format dwarf expression B32 is_dwarf64 = (address_size == 8); String8 raw_expr = str8((U8*)base+expr_range.min, dim_1u64(expr_range)); - String8 expression = dw_format_expression_single_line(range_temp.arena, raw_expr, address_size, arch, ver, ext, is_dwarf64); + String8 expression = dw_format_expression_single_line(range_temp.arena, raw_expr, cu_bases[comp_idx], address_size, arch, ver, ext, input->sec[DW_Section_Loc].mode); // push entry U64 min = base_address + v0; @@ -2844,14 +3163,17 @@ dw_print_debug_loc(Arena *arena, String8List *out, String8 indent, DW_SectionArr rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed) +dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ImageType image_type, B32 relaxed) { - DW_Section ranges = sections->v[DW_Section_Ranges]; - void *base = dw_base_from_sec(sections, DW_Section_Ranges); - Rng1U64 range = dw_range_from_sec(sections, DW_Section_Ranges); + NotImplemented; +#if 0 + DW_Section ranges = input->sec[DW_Section_Ranges]; + void *base = dw_base_from_sec(input, DW_Section_Ranges); + Rng1U64 range = dw_range_from_sec(input, DW_Section_Ranges); if (dim_1u64(range) == 0) { return; @@ -2859,42 +3181,40 @@ dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_Section Temp scratch = scratch_begin(&arena, 1); - Rng1U64List comp_unit_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); + Rng1U64List cu_range_list = dw_comp_unit_ranges_from_info(scratch.arena, sections->v[DW_Section_Info]); // parse debug_info for attributes with LOCLIST and store .debug_loc offsets - U64List *loc_lists = push_array(scratch.arena, U64List, comp_unit_range_list.count); - U64 *address_sizes = push_array(scratch.arena, U64, comp_unit_range_list.count); - U64 *address_bases = push_array(scratch.arena, U64, comp_unit_range_list.count); + U64List *loc_lists = push_array(scratch.arena, U64List, cu_range_list.count); + U64 *address_sizes = push_array(scratch.arena, U64, cu_range_list.count); + U64 *address_bases = push_array(scratch.arena, U64, cu_range_list.count); { U64 comp_idx = 0; - for (Rng1U64Node *comp_unit_range_n = comp_unit_range_list.first; comp_unit_range_n != 0; comp_unit_range_n = comp_unit_range_n->next, ++comp_idx) { - Rng1U64 comp_unit_range = comp_unit_range_n->v; - DW_CompRoot comp_root = dw_comp_root_from_range(scratch.arena, sections, comp_unit_range, relaxed); - DW_AttribValueResolveParams resolve_params = dw_attrib_value_resolve_params_from_comp_root(&comp_root); - DW_Ext ext = dw_ext_from_params(comp_root.producer, arch, image_type); + for (Rng1U64Node *cu_range_n = cu_range_list.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++comp_idx) { + Rng1U64 cu_range = cu_range_n->v; + DW_CompUnit cu = dw_comp_unit_from_info_offset(scratch.arena, sections, cu_range.min, relaxed); // store info about comp unit - address_sizes[comp_idx] = comp_root.address_size; - address_bases[comp_idx] = comp_root.base_addr; + address_sizes[comp_idx] = cu.address_size; + address_bases[comp_idx] = cu.base_addr; // parse tags - for (U64 info_off = comp_root.tags_info_range.min; info_off < comp_root.tags_info_range.max; /* empty */) { - DW_Tag *tag = dw_tag_from_info_offset(scratch.arena, sections, comp_root.abbrev_table, comp_root.version, ext, comp_root.language, comp_root.address_size, info_off, relaxed); + for (U64 info_off = cu.tags_range.min; info_off < cu.tags_range.max; /* empty */) { + DW_Tag tag = dw_tag_from_info_offset_cu(scratch.arena, sections, &cu, info_off); // parse attribs - for (DW_AttribNode *attrib_node = tag->attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { - DW_Attrib *attrib = &attrib_node->attrib; + for (DW_AttribNode *attrib_node = tag.attribs.first; attrib_node != 0; attrib_node = attrib_node->next) { + DW_Attrib *attrib = &attrib_node->v; B32 is_sect_offset = attrib->value_class == DW_AttribClass_RngListPtr || (attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_SecOffset); B32 is_sect_index = attrib->value_class == DW_AttribClass_RngList && attrib->form_kind == DW_Form_RngListx; if (is_sect_offset) { - DW_AttribValue attrib_value = dw_attrib_value_from_form_value(sections, resolve_params, attrib->form_kind, attrib->value_class, attrib->form_value); - u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib_value.v[0]); + u64_list_push(scratch.arena, &loc_lists[comp_idx], attrib->value.v[0]); } else if (is_sect_index) { // TODO: support for section indexing } } - info_off = tag->info_range.max; + + info_off = tag.next_info_off; } } } @@ -2902,7 +3222,7 @@ dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_Section rd_printf("# %S", sections->v[DW_Section_Ranges].name); rd_indent(); rd_printf("%-8s %-8s %-8s", "Offset", "Min", "Max"); - for (U32 comp_idx = 0; comp_idx < comp_unit_range_list.count; ++comp_idx) { + for (U32 comp_idx = 0; comp_idx < cu_range_list.count; ++comp_idx) { U64Array locs = u64_array_from_list(scratch.arena, &loc_lists[comp_idx]); u64_array_sort(locs.count, locs.v); U64Array locs_set = remove_duplicates_u64_array(scratch.arena, locs); @@ -2949,11 +3269,14 @@ dw_print_debug_ranges(Arena *arena, String8List *out, String8 indent, DW_Section } } } +#endif } internal void -dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_Input *input) { + NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_ARanges); Rng1U64 range = dw_range_from_sec(sections, DW_Section_ARanges); @@ -3035,11 +3358,14 @@ dw_print_debug_aranges(Arena *arena, String8List *out, String8 indent, DW_Sectio rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_Input *input) { + NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_Addr); Rng1U64 range = dw_range_from_sec(sections, DW_Section_Addr); @@ -3114,6 +3440,7 @@ dw_print_debug_addr(Arena *arena, String8List *out, String8 indent, DW_SectionAr rd_unindent(); scratch_end(scratch); +#endif } internal U64 @@ -3144,8 +3471,10 @@ dw_based_range_read_address(void *base, Rng1U64 range, U64 offset, Rng1U64Array } internal void -dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_virtual_ranges, Arch arch) +dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_virtual_ranges, Arch arch) { + NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_LocLists); Rng1U64 range = dw_range_from_sec(sections, DW_Section_LocLists); @@ -3261,8 +3590,10 @@ dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_Secti String8 raw_expr = str8((U8*)base+cursor, expr_length); cursor += expr_length; - - String8 expression = dw_format_expression_single_line(temp.arena, raw_expr, address_size, arch, version, DW_Ext_Null, is_dwarf64); + + // TODO: we need actual cu base to format expression correctly + NotImplemented; + String8 expression = dw_format_expression_single_line(temp.arena, raw_expr, 0, address_size, arch, version, DW_Ext_Null, is_dwarf64); str8_list_pushf(temp.arena, &list, "(%S)", expression); } break; case DW_LocListEntryKind_StartXLength: { @@ -3289,11 +3620,14 @@ dw_print_debug_loclists(Arena *arena, String8List *out, String8 indent, DW_Secti rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_ranges) +dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_ranges) { + NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_RngLists); Rng1U64 range = dw_range_from_sec(sections, DW_Section_RngLists); @@ -3425,11 +3759,14 @@ dw_print_debug_rnglists(Arena *arena, String8List *out, String8 indent, DW_Secti rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, DW_SectionKind sec) +dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_SectionKind sec) { +NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, sec); Rng1U64 range = dw_range_from_sec(sections, sec); @@ -3484,23 +3821,26 @@ dw_format_string_table(Arena *arena, String8List *out, String8 indent, DW_Sectio rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_print_debug_pubnames(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_pubnames(Arena *arena, String8List *out, String8 indent, DW_Input *input) { - dw_format_string_table(arena, out, indent, sections, DW_Section_PubNames); + dw_format_string_table(arena, out, indent, input, DW_Section_PubNames); } internal void -dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_pubtypes(Arena *arena, String8List *out, String8 indent, DW_Input *input) { - dw_format_string_table(arena, out, indent, sections, DW_Section_PubTypes); + dw_format_string_table(arena, out, indent, input, DW_Section_PubTypes); } internal void -dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_Input *input) { +NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_LineStr); Rng1U64 range = dw_range_from_sec(sections, DW_Section_LineStr); @@ -3523,11 +3863,14 @@ dw_print_debug_line_str(Arena *arena, String8List *out, String8 indent, DW_Secti rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections) +dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Input *input) { +NotImplemented; +#if 0 void *base = dw_base_from_sec(sections, DW_Section_StrOffsets); Rng1U64 range = dw_range_from_sec(sections, DW_Section_StrOffsets); @@ -3586,61 +3929,77 @@ dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Se rd_unindent(); scratch_end(scratch); +#endif } internal void -dw_format(Arena *arena, String8List *out, String8 indent, RD_Option opts, DW_SectionArray *sections, Arch arch, ImageType image_type) +dw_format(Arena *arena, String8List *out, String8 indent, RD_Option opts, DW_Input *input, Arch arch, ImageType image_type) { + Temp scratch = scratch_begin(&arena, 1); + Rng1U64Array segment_vranges = {0}; - B32 relaxed = !!(opts & RD_Option_RelaxDwarfParser); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, input); + B32 relaxed = !!(opts & RD_Option_RelaxDwarfParser); if (opts & RD_Option_DebugInfo) { - dw_print_debug_info(arena, out, indent, sections, arch, image_type, relaxed); + dw_print_debug_info(arena, out, indent, input, lu_input, arch, relaxed); } if (opts & RD_Option_DebugAbbrev) { - dw_print_debug_abbrev(arena, out, indent, sections); + dw_print_debug_abbrev(arena, out, indent, input); } if (opts & RD_Option_DebugLine) { - dw_print_debug_line(arena, out, indent, sections, relaxed); + dw_print_debug_line(arena, out, indent, input, lu_input, relaxed); } if (opts & RD_Option_DebugStr) { - dw_print_debug_str(arena, out, indent, sections); + dw_print_debug_str(arena, out, indent, input); } if (opts & RD_Option_DebugLoc) { - dw_print_debug_loc(arena, out, indent, sections, arch, image_type, relaxed); + dw_print_debug_loc(arena, out, indent, input, arch, image_type, relaxed); } if (opts & RD_Option_DebugRanges) { - dw_print_debug_ranges(arena, out, indent, sections, arch, image_type, relaxed); + dw_print_debug_ranges(arena, out, indent, input, arch, image_type, relaxed); } if (opts & RD_Option_DebugARanges) { - dw_print_debug_aranges(arena, out, indent, sections); + dw_print_debug_aranges(arena, out, indent, input); } if (opts & RD_Option_DebugAddr) { - dw_print_debug_addr(arena, out, indent, sections); + dw_print_debug_addr(arena, out, indent, input); } if (opts & RD_Option_DebugLocLists) { - dw_print_debug_loclists(arena, out, indent, sections, segment_vranges, arch); + dw_print_debug_loclists(arena, out, indent, input, segment_vranges, arch); } if (opts & RD_Option_DebugRngLists) { - dw_print_debug_rnglists(arena, out, indent, sections, segment_vranges); + dw_print_debug_rnglists(arena, out, indent, input, segment_vranges); } if (opts & RD_Option_DebugPubNames) { - dw_print_debug_pubnames(arena, out, indent, sections); + dw_print_debug_pubnames(arena, out, indent, input); } if (opts & RD_Option_DebugPubTypes) { - dw_print_debug_pubtypes(arena, out, indent, sections); + dw_print_debug_pubtypes(arena, out, indent, input); } if (opts & RD_Option_DebugLineStr) { - dw_print_debug_line_str(arena, out, indent, sections); + dw_print_debug_line_str(arena, out, indent, input); } if (opts & RD_Option_DebugStrOffsets) { - dw_print_debug_str_offsets(arena, out, indent, sections); + dw_print_debug_str_offsets(arena, out, indent, input); } + + scratch_end(scratch); } // CodeView +internal String8 +cv_string_from_reg_off(Arena *arena, CV_Arch arch, U32 reg_idx, U32 reg_off) +{ + Temp scratch = scratch_begin(&arena, 1); + String8 reg_str = cv_string_from_reg_id(scratch.arena, arch, reg_idx); + String8 result = rd_string_from_reg_off(arena, reg_str, reg_off); + scratch_end(scratch); + return result; +} + internal void cv_print_binary_annots(Arena *arena, String8List *out, String8 indent, CV_Arch arch, String8 raw_data) { @@ -3721,26 +4080,26 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV switch (type) { case CV_SymKind_THUNK32_ST: case CV_SymKind_THUNK32: { - CV_SymThunk32 sym = {0}; + CV_SymThunk32 sym = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %x", sym.parent); - rd_printf("End: %x", sym.end); - rd_printf("Next: %x", sym.next); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u", sym.len); - rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); + rd_printf("Name : %S", name); + rd_printf("Parent : %#x", sym.parent); + rd_printf("End : %#x", sym.end); + rd_printf("Next : %#x", sym.next); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length : %u", sym.len); + rd_printf("Ordinal: %S", cv_string_from_thunk_ordinal(sym.ord)); } break; case CV_SymKind_FILESTATIC: { CV_SymFileStatic sym = {0}; String8 name = str8_zero(); cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_CALLERS: @@ -3757,7 +4116,7 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV rd_indent(); for (U32 i = 0; i < sym.count; ++i) { U32 invoks = i < invocation_count ? invocations[i] : 0; - rd_printf("%08x (%u)", funcs[i], invoks); + rd_printf("%#08x (%u)", funcs[i], invoks); } rd_unindent(); } break; @@ -3780,20 +4139,20 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_annots.size; - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); + rd_printf("Parent : %#x", sym.parent); + rd_printf("End : %#x", sym.end); rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; case CV_SymKind_INLINESITE2: { - CV_SymInlineSite2 sym = {0}; + CV_SymInlineSite2 sym = {0}; String8 raw_annots = str8_skip(raw_symbol, sizeof(CV_SymInlineSite2)); cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_annots.size; - rd_printf("Parent: %#x", sym.parent_off); - rd_printf("End: %#x", sym.end_off); - rd_printf("Inlinee: %S", cv_string_from_itemid(arena, sym.inlinee)); + rd_printf("Parent : %#x", sym.parent_off); + rd_printf("End : %#x", sym.end_off); + rd_printf("Inlinee : %S", cv_string_from_itemid(arena, sym.inlinee)); rd_printf("Invocations: %u", sym.invocations); cv_print_binary_annots(arena, out, indent, arch, raw_annots); } break; @@ -3804,37 +4163,37 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV case CV_SymKind_GTHREAD32_ST: case CV_SymKind_LTHREAD32: case CV_SymKind_GTHREAD32: { - CV_SymThread32 sym = {0}; + CV_SymThread32 sym = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("TSL Address: %S", cv_string_sec_off(scratch.arena, sym.tls_seg, sym.tls_off)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_OBJNAME: { - CV_SymObjName sym = {0}; + CV_SymObjName sym = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Signature: %#x", sym.sig); } break; case CV_SymKind_BLOCK32_ST: case CV_SymKind_BLOCK32: { - CV_SymBlock32 sym = {0}; + CV_SymBlock32 sym = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Parent: %x", sym.parent); - rd_printf("End: %x", sym.end); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u", sym.len); + rd_printf("Parent : %#x", sym.parent); + rd_printf("End : %#x", sym.end); + rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length : %u", sym.len); + rd_printf("Name : %S", name); if (name.size) { - rd_printf("Name: %S", name); } } break; case CV_SymKind_LABEL32_ST: @@ -3858,13 +4217,13 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV U32 float_pkg = CV_CompileFlags_Extract_FloatPkg(sym.flags); U32 ambient_data = CV_CompileFlags_Extract_AmbientData(sym.flags); U32 mode = CV_CompileFlags_Extract_Mode(sym.flags); - rd_printf("Arch: %S", cv_string_from_arch(sym.machine)); - rd_printf("Language: %S", cv_string_from_language(language)); - rd_printf("FloatPrec: %x", float_prec); - rd_printf("FloatPkg: %x", float_pkg); - rd_printf("Ambient Data: %x", ambient_data); - rd_printf("Mode: %x", mode); - rd_printf("Version String: %S", version_string); + rd_printf("Arch : %#x (%S)", sym.machine, cv_string_from_arch(sym.machine)); + rd_printf("Language : %#x (%S)", language, cv_string_from_language(language)); + rd_printf("FloatPrec : %#x", float_prec); + rd_printf("FloatPkg : %#x", float_pkg); + rd_printf("Ambient Data : %#x", ambient_data); + rd_printf("Mode : %#x", mode); + rd_printf("Version String: %S", version_string); } break; case CV_SymKind_COMPILE2_ST: case CV_SymKind_COMPILE2: { @@ -3875,14 +4234,14 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); U32 language = CV_Compile2Flags_Extract_Language(sym.flags); - rd_printf("Machine: %S", cv_string_from_arch(sym.machine)); - rd_printf("Flags: %x", sym.flags); - rd_printf("Language: %S", cv_string_from_language(language)); - rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); - rd_printf("Frontend Build: %u", sym.ver_fe_build); - rd_printf("Backend Version: %u.%u", sym.ver_major, sym.ver_minor); - rd_printf("Backend Build: %u", sym.ver_build); - rd_printf("Version String: %S", version_string); + rd_printf("Machine : %#x (%S)", sym.machine, cv_string_from_arch(sym.machine)); + rd_printf("Flags : %#x", sym.flags); + rd_printf("Language : %#x (%S)", language, cv_string_from_language(language)); + rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); + rd_printf("Frontend Build : %u", sym.ver_fe_build); + rd_printf("Backend Version : %u.%u", sym.ver_major, sym.ver_minor); + rd_printf("Backend Build : %u", sym.ver_build); + rd_printf("Version String : %S", version_string); } break; case CV_SymKind_COMPILE3: { CV_SymCompile3 sym = {0}; @@ -3891,16 +4250,16 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_cstr(raw_symbol, cursor, &version_string); U32 language = CV_Compile3Flags_Extract_Language(sym.flags); - rd_printf("Machine: %S", cv_string_from_arch(sym.machine)); - rd_printf("Flags: %x", sym.flags); - rd_printf("Language: %S", cv_string_from_language(language)); - rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); - rd_printf("Frontend Build: %u", sym.ver_fe_build); - rd_printf("Fontend QFE: %u", sym.ver_feqfe); - rd_printf("Backend Version: %u.%u", sym.ver_major, sym.ver_minor); - rd_printf("Backend Build: %u", sym.ver_build); - rd_printf("Backend QFE: %u", sym.ver_qfe); - rd_printf("Version String: %S", version_string); + rd_printf("Machine : %#x (%S)", sym.machine, cv_string_from_arch(sym.machine)); + rd_printf("Flags : %#x", sym.flags); + rd_printf("Language : %#x (%S)", language, cv_string_from_language(language)); + rd_printf("Frontend Version: %u.%u", sym.ver_fe_major, sym.ver_fe_minor); + rd_printf("Frontend Build : %u", sym.ver_fe_build); + rd_printf("Fontend QFE : %u", sym.ver_feqfe); + rd_printf("Backend Version : %u.%u", sym.ver_major, sym.ver_minor); + rd_printf("Backend Build : %u", sym.ver_build); + rd_printf("Backend QFE : %u", sym.ver_qfe); + rd_printf("Version String : %S", version_string); } break; case CV_SymKind_GPROC32_ST: case CV_SymKind_LPROC32_ST: @@ -3913,16 +4272,16 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV String8 name = str8_zero(); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Next: %#x", sym.next); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Length: %u", sym.len); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); - rd_printf("Flags: %S", cv_string_from_proc_flags(scratch.arena, sym.flags)); - rd_printf("Debug Start: %#x", sym.dbg_start); - rd_printf("Debug End: %#x", sym.dbg_end); + rd_printf("Name : %S", name); + rd_printf("Parent : %#x", sym.parent); + rd_printf("End : %#x", sym.end); + rd_printf("Next : %#x", sym.next); + rd_printf("Address : %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Length : %u", sym.len); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Flags : %#x (%S)", sym.flags, cv_string_from_proc_flags(scratch.arena, sym.flags)); + rd_printf("Debug Start: %#x", sym.dbg_start); + rd_printf("Debug End : %#x", sym.dbg_end); } break; case CV_SymKind_LDATA32_ST: case CV_SymKind_GDATA32_ST: @@ -3933,8 +4292,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_CONSTANT_ST: @@ -3957,14 +4316,14 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV String8 flags = cv_string_from_frame_proc_flags(scratch.arena, sym.flags); U32 local_ptr = CV_FrameprocFlags_Extract_LocalBasePointer(sym.flags); U32 param_ptr = CV_FrameprocFlags_Extract_ParamBasePointer(sym.flags); - rd_printf("Frame Size: %x", sym.frame_size); - rd_printf("Pad Size: %x", sym.pad_size); - rd_printf("Pad Offset: %x", sym.pad_off); - rd_printf("Save Registers Area: %u", sym.save_reg_size); - rd_printf("Exception Handler: %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); - rd_printf("Flags: %S", flags); - rd_printf("Local pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, local_ptr))); - rd_printf("Param pointer: %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, param_ptr))); + rd_printf("Frame Size : %#x", sym.frame_size); + rd_printf("Pad Size : %#x", sym.pad_size); + rd_printf("Pad Offset : %#x", sym.pad_off); + rd_printf("Save Registers Area: %u", sym.save_reg_size); + rd_printf("Exception Handler : %S", cv_string_sec_off(arena, sym.eh_sec, sym.eh_off)); + rd_printf("Flags : %S", flags); + rd_printf("Local pointer : %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, local_ptr))); + rd_printf("Param pointer : %S", cv_string_from_reg_id(scratch.arena, arch, cv_map_encoded_base_pointer(arch, param_ptr))); } break; case CV_SymKind_LOCAL: { CV_SymLocal sym = {0}; @@ -3972,8 +4331,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Flags: %S", cv_string_from_local_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_DEFRANGE: { @@ -3992,7 +4351,7 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + rd_printf("Register : %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); cv_print_lvar_addr_range(arena, out, indent, sym.range); cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); @@ -4012,9 +4371,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); - rd_printf("Attributes: %S", cv_string_from_range_attribs(scratch.arena, sym.attribs)); - rd_printf("Parent Offset: %#x", sym.field_offset); + rd_printf("Register : %#x (%S)", sym.reg, cv_string_from_reg_id(scratch.arena, arch, sym.reg)); + rd_printf("Attributes : %#x (%S)", sym.attribs, cv_string_from_range_attribs(scratch.arena, sym.attribs)); + rd_printf("Parent Offset: %#x", sym.field_offset); cv_print_lvar_addr_range(arena, out, indent, sym.range); cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; @@ -4029,8 +4388,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += raw_gaps.size; - rd_printf("Flags: %S", cv_string_from_defrange_register_rel_flags(scratch.arena, sym.flags)); - rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); + rd_printf("Flags : %#x (%S)", sym.flags, cv_string_from_defrange_register_rel_flags(scratch.arena, sym.flags)); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.reg_off)); cv_print_lvar_addr_gap(arena, out, indent, raw_gaps); } break; case CV_SymKind_END: @@ -4076,16 +4435,16 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); - rd_printf("Pad: %u", sym.pad); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Pad : %u", sym.pad); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_FRAMECOOKIE: { CV_SymFrameCookie sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Address: %S", cv_string_sec_off(arena, sym.reg, sym.off)); - rd_printf("Kind: %S", cv_string_from_frame_cookie_kind(sym.kind)); - rd_printf("Flags: %#x", sym.flags); // TODO: llvm and cvinfo.h don't define these flags... + rd_printf("Address: %S", cv_string_sec_off(arena, sym.reg, sym.off)); + rd_printf("Kind : %#x (%S)", sym.kind, cv_string_from_frame_cookie_kind(sym.kind)); + rd_printf("Flags : %#x", sym.flags); // TODO: llvm and cvinfo.h don't define these flags... } break; case CV_SymKind_HEAPALLOCSITE: { CV_SymHeapAllocSite sym = {0}; @@ -4093,8 +4452,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV String8 addr = cv_string_sec_off(arena, sym.sec, sym.off); String8 itype = cv_string_from_itype(arena, min_itype, sym.itype); - rd_printf("Address: %S", addr); - rd_printf("Type: %S", itype); + rd_printf("Address : %S", addr); + rd_printf("Type : %S", itype); rd_printf("Call instruction length: %x", sym.call_inst_len); } break; case CV_SymKind_ALIGN: { @@ -4127,7 +4486,7 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); rd_printf("Start Symbol: %#x", sym.start_symbol); - rd_printf("Segment: %#x", sym.segment); + rd_printf("Segment : %#x", sym.segment); } break; case CV_SymKind_RETURN: { Assert(!"TODO: test"); @@ -4135,15 +4494,15 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymReturn sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Flags: %S", cv_string_from_generic_flags(scratch.arena, sym.flags)); - rd_printf("Style: %S", cv_string_from_generic_style(sym.style)); + rd_printf("Flags : %#x (%S)", sym.flags, cv_string_from_generic_flags(scratch.arena, sym.flags)); + rd_printf("Style : %#x (%S)", sym.style, cv_string_from_generic_style(sym.style)); if (sym.style == CV_GenericStyle_REG) { U8 count = 0; cursor += str8_deserial_read_struct(raw_symbol, cursor, &count); String8 data = rd_format_hex_array(scratch.arena, raw_symbol.str, raw_symbol.size); rd_printf("Byte Count: %u", count); - rd_printf("Data: %S", data); + rd_printf("Data : %S", data); } } break; case CV_SymKind_ENTRYTHIS: { @@ -4157,13 +4516,13 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cv_print_symbol(arena, out, indent, arch, min_itype, type, raw_subsym); } break; case CV_SymKind_SLINK32: { - Assert(!"ret"); + Assert(!"TODO: test"); CV_SymSLink32 sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); rd_printf("Frame Size: %x", sym.frame_size); - rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.offset)); + rd_printf("Address : %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.offset)); } break; case CV_SymKind_OEM: { Assert(!"TODO: test"); @@ -4176,7 +4535,7 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV // // CV-spec doesn't even mention S_OEM just LF_OEM and cvdump.exe prints out type with guid... rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); - rd_printf("ID: %S", string_from_guid(scratch.arena, sym.id)); + rd_printf("ID : %S", string_from_guid(scratch.arena, sym.id)); } break; case CV_SymKind_VFTABLE32:{ Assert(!"TODO: test"); @@ -4184,8 +4543,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymVPath32 sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Root: %S", cv_string_from_itype(scratch.arena, min_itype, sym.root)); - rd_printf("Path: %S", cv_string_from_itype(scratch.arena, min_itype, sym.path)); + rd_printf("Root : %S", cv_string_from_itype(scratch.arena, min_itype, sym.root)); + rd_printf("Path : %S", cv_string_from_itype(scratch.arena, min_itype, sym.path)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); } break; case CV_SymKind_PUB32_ST: @@ -4195,8 +4554,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Flags: %S", cv_string_from_pub32_flags(scratch.arena, sym.flags)); + rd_printf("Name : %S", name); + rd_printf("Flags : %S", cv_string_from_pub32_flags(scratch.arena, sym.flags)); rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_BPREL32_ST: @@ -4208,9 +4567,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_REGISTER: { Assert(!"TODO: test"); @@ -4220,9 +4579,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); } break; case CV_SymKind_PROCREF_ST: case CV_SymKind_DATAREF_ST: @@ -4238,9 +4597,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("SUC: %#x", sym.suc_name); - rd_printf("IMod: %#x", sym.imod); + rd_printf("Name : %S", name); + rd_printf("SUC : %#x", sym.suc_name); + rd_printf("IMod : %#x", sym.imod); rd_printf("Symbol Stream Offset: %#x", sym.sym_off); } break; case CV_SymKind_SEPCODE: { @@ -4249,12 +4608,12 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymSepcode sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Parent: %#x", sym.parent); - rd_printf("End: %#x", sym.end); - rd_printf("Length: %u", sym.len); - rd_printf("Flags: %S", cv_string_from_sepcode(scratch.arena, sym.flags)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); - rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); + rd_printf("Parent : %#x", sym.parent); + rd_printf("End : %#x", sym.end); + rd_printf("Length : %u", sym.len); + rd_printf("Flags : %#x (%S)", sym.flags, cv_string_from_sepcode(scratch.arena, sym.flags)); + rd_printf("Address : %S", cv_string_sec_off(scratch.arena, sym.sec, sym.sec_off)); + rd_printf("Parent Address: %S", cv_string_sec_off(scratch.arena, sym.sec_parent, sym.sec_parent_off)); } break; case CV_SymKind_PARAMSLOT_ST: case CV_SymKind_LOCALSLOT_ST: @@ -4276,10 +4635,10 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymTrampoline sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_trampoline_kind(sym.kind)); - rd_printf("Thunk Size: %u", sym.thunk_size); - rd_printf("Thunk: %.*s", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); - rd_printf("Target: %.*s", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); + rd_printf("Type : %S", cv_string_from_trampoline_kind(sym.kind)); + rd_printf("Thunk Size: %u", sym.thunk_size); + rd_printf("Thunk : %S", cv_string_sec_off(scratch.arena, sym.thunk_sec, sym.thunk_sec_off)); + rd_printf("Target : %S", cv_string_sec_off(scratch.arena, sym.target_sec, sym.target_sec_off)); } break; case CV_SymKind_POGODATA: { Assert(!"TODO: test"); @@ -4287,9 +4646,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymPogoInfo sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Invocations: %u", sym.invocations); - rd_printf("Dynamic instruction count: %u", sym.dynamic_inst_count); - rd_printf("Static instruction count: %u", sym.static_inst_count); + rd_printf("Invocations : %u", sym.invocations); + rd_printf("Dynamic instruction count : %u", sym.dynamic_inst_count); + rd_printf("Static instruction count : %u", sym.static_inst_count); rd_printf("Post inline static instruction count: %u", sym.post_inline_static_inst_count); } break; case CV_SymKind_MANYREG: { @@ -4298,9 +4657,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); - rd_printf("Regs:"); + rd_printf("Regs :"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { U8 v = 0; @@ -4316,9 +4675,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymManyreg sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(arena, min_itype, sym.itype)); rd_printf("Reg Count: %u", sym.count); - rd_printf("Regs:"); + rd_printf("Regs :"); rd_indent(); for (U16 i = 0; i < sym.count; ++i) { U16 v = 0; @@ -4335,11 +4694,11 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Index: %u", sym.sec_index); - rd_printf("Align: %u", sym.align); - rd_printf("Virtual Offset: %#x", sym.rva); - rd_printf("Size: %u", sym.size); + rd_printf("Name : %S", name); + rd_printf("Index : %u", sym.sec_index); + rd_printf("Align : %u", sym.align); + rd_printf("Virtual Offset : %#x", sym.rva); + rd_printf("Size : %u", sym.size); rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); } break; case CV_SymKind_ENVBLOCK: { @@ -4365,10 +4724,10 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Size: %u", sym.size); - rd_printf("Characteristics: %S", coff_string_from_section_flags(scratch.arena, sym.characteristics)); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); + rd_printf("Name : %S", name); + rd_printf("Size : %u", sym.size); + rd_printf("Characteristics: %#x (%S)", sym.characteristics, coff_string_from_section_flags(scratch.arena, sym.characteristics)); + rd_printf("Address : %S", cv_string_sec_off(scratch.arena, sym.sec, sym.off)); } break; case CV_SymKind_EXPORT: { Assert(!"TODO: test"); @@ -4378,9 +4737,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Ordinal: %#x", sym.ordinal); - rd_printf("Flags: %S", cv_string_from_export_flags(scratch.arena, sym.flags)); + rd_printf("Flags : %S", cv_string_from_export_flags(scratch.arena, sym.flags)); } break; case CV_SymKind_ANNOTATION: { Assert(!"TODO: test"); @@ -4388,8 +4747,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymAnnotation sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Address: %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); - rd_printf("Count: %u", sym.count); + rd_printf("Address : %S", cv_string_sec_off(scratch.arena, sym.seg, sym.off)); + rd_printf("Count : %u", sym.count); rd_printf("Annotations:"); rd_indent(); for (U16 i = 0; i < sym.count; ++i) { @@ -4408,9 +4767,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Offset: %#x", sym.off); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANREGISTER: @@ -4422,8 +4781,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); rd_printf("Register: %S", cv_string_from_reg_id(scratch.arena, arch, sym.reg)); cv_print_lvar_attr(arena, out, indent, sym.attr); } break; @@ -4435,9 +4794,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); - rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.off)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Address: %S", cv_string_from_reg_off(scratch.arena, arch, sym.reg, sym.off)); cv_print_lvar_attr(arena, out, indent, sym.attr); } break; case CV_SymKind_MANYREG_ST: @@ -4452,11 +4811,11 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV String8 name = str8_zero(); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, sym.itype)); cv_print_lvar_attr(arena, out, indent, sym.attr); rd_printf("Reg Count: %u", sym.count); - rd_printf("Regs:"); + rd_printf("Regs :"); rd_indent(); for (U8 i = 0; i < sym.count; ++i) { rd_printf("%S", cv_string_from_reg_id(scratch.arena, arch, regs[i])); @@ -4503,8 +4862,8 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &symbol_type); String8 raw_subsym = str8_skip(raw_symbol, cursor); - rd_printf("Kind: %x", sym.kind); - rd_printf("File ID: %x", sym.file_id); + rd_printf("Kind : %x", sym.kind); + rd_printf("File ID : %x", sym.file_id); rd_printf("File Line Number: %u", sym.file_ln); rd_printf("# Discarded Symbol"); cv_print_symbol(arena, out, indent, arch, min_itype, symbol_type, raw_subsym); @@ -4518,7 +4877,7 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_cstr(raw_symbol, cursor, &to); rd_printf("From: %S", from); - rd_printf("To: %S", to); + rd_printf("To : %S", to); } break; case CV_SymKind_FASTLINK: { Assert(!"TODO: test"); @@ -4528,9 +4887,9 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Flags: %x", sym.flags); - rd_printf("Type: %S", cv_string_from_itype(arena, min_itype, sym.itype)); + rd_printf("Name : %S", name); + rd_printf("Flags: %#x", sym.flags); + rd_printf("Type : %S", cv_string_from_itype(arena, min_itype, sym.itype)); } break; case CV_SymKind_ARMSWITCHTABLE: { Assert(!"TODO: test"); @@ -4538,11 +4897,11 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV CV_SymArmSwitchTable sym = {0}; cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); - rd_printf("Base Address: %S", cv_string_sec_off(scratch.arena, sym.sec_base, sym.off_base)); + rd_printf("Base Address : %S", cv_string_sec_off(scratch.arena, sym.sec_base, sym.off_base)); rd_printf("Branch Address: %S", cv_string_sec_off(scratch.arena, sym.sec_branch, sym.off_branch)); - rd_printf("Table Address: %S", cv_string_sec_off(scratch.arena, sym.sec_table, sym.off_table)); - rd_printf("Entry count: %u", sym.entry_count); - rd_printf("Switch Type: %x", sym.kind); + rd_printf("Table Address : %S", cv_string_sec_off(scratch.arena, sym.sec_table, sym.off_table)); + rd_printf("Entry count : %u", sym.entry_count); + rd_printf("Switch Type : %x", sym.kind); } break; case CV_SymKind_REF_MINIPDB: { Assert(!"TODO: test"); @@ -4552,11 +4911,11 @@ cv_print_symbol(Arena *arena, String8List *out, String8 indent, CV_Arch arch, CV cursor += str8_deserial_read_struct(raw_symbol, cursor, &sym); cursor += str8_deserial_read_cstr(raw_symbol, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Flags: %x", sym.flags); - rd_printf("IMod: %04x", sym.imod); + rd_printf("Name : %S", name); + rd_printf("Flags : %x", sym.flags); + rd_printf("IMod : %04x", sym.imod); if (sym.flags & CV_RefMiniPdbFlag_UDT) { - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, (CV_TypeIndex)sym.data)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, (CV_TypeIndex)sym.data)); } else { rd_printf("Coff ISect: %#x", sym.data); } @@ -4673,8 +5032,8 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i CV_LeafBitField lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); - rd_printf("Length: %u", lf.len); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Length : %u", lf.len); rd_printf("Position: %u", lf.pos); } break; case CV_LeafKind_CLASS2: @@ -4686,12 +5045,12 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += cv_read_numeric(raw_leaf, cursor, &size); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Fields: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Derived: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); - rd_printf("Unknown: %x", lf.unknown); + rd_printf("Name : %S", name); + rd_printf("Fields : %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Properties : %#x (%S)", lf.props, cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Derived : %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape : %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); + rd_printf("Unknown : %#x", lf.unknown); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = str8_zero(); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -4700,25 +5059,25 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i } break; case CV_LeafKind_PRECOMP_ST: case CV_LeafKind_PRECOMP: { - CV_LeafPreComp lf = {0}; + CV_LeafPreComp lf = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Start Index: %x", lf.start_index); - rd_printf("Count: %u", lf.count); - rd_printf("Signature: %x", lf.sig); + rd_printf("Count : %u", lf.count); + rd_printf("Signature : %x", lf.sig); } break; case CV_LeafKind_TYPESERVER2: { - CV_LeafTypeServer2 lf = {0}; + CV_LeafTypeServer2 lf = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Sig70: %S", string_from_guid(arena, lf.sig70)); - rd_printf("Age: %u", lf.age); + rd_printf("Age : %u", lf.age); } break; case CV_LeafKind_BUILDINFO: { CV_LeafBuildInfo lf = {0}; @@ -4734,13 +5093,13 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i rd_unindent(); } break; case CV_LeafKind_MFUNC_ID: { - CV_LeafMFuncId lf = {0}; + CV_LeafMFuncId lf = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Owner Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.owner_itype)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_VFUNCTAB: { CV_LeafVFuncTab lf = {0}; @@ -4758,8 +5117,8 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i if (has_vbase) { cursor += str8_deserial_read_struct(raw_leaf, cursor, &vbase); } - rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, ml.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, ml.itype)); + rd_printf("Attribs : %#x (%S)", ml.attribs, cv_string_from_field_attribs(scratch.arena, ml.attribs)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, ml.itype)); if (has_vbase) { rd_printf("Virtual Base: %x", vbase); } @@ -4777,48 +5136,48 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i } String8 name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Name : %S", name); + rd_printf("Field Attribs: %#x (%S)", lf.attribs, cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); if (has_vbase) { rd_printf("Virtual Base: %#x", vbase); } } break; case CV_LeafKind_METHOD_ST: case CV_LeafKind_METHOD: { - CV_LeafMethod lf = {0}; + CV_LeafMethod lf = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Count: %u", lf.count); + rd_printf("Name : %S", name); + rd_printf("Count : %u", lf.count); rd_printf("Type List: %S", cv_string_from_itype(scratch.arena, min_itype, lf.list_itype)); } break; case CV_LeafKind_VBCLASS: case CV_LeafKind_IVBCLASS: { - CV_LeafVBClass lf = {0}; + CV_LeafVBClass lf = {0}; CV_NumericParsed vbptr_off = {0}; CV_NumericParsed vbtable_off = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += cv_read_numeric(raw_leaf, cursor, &vbptr_off); cursor += cv_read_numeric(raw_leaf, cursor, &vbtable_off); - rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Attribs : %#x (%S)", lf.attribs, cv_string_from_field_attribs(scratch.arena, lf.attribs)); rd_printf("Direct Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Virtual Base Ptr: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vbptr_itype)); - rd_printf("vbpoff: %S", cv_string_from_numeric(scratch.arena, vbptr_off)); - rd_printf("vbind: %S", cv_string_from_numeric(scratch.arena, vbtable_off)); + rd_printf("vbpoff : %S", cv_string_from_numeric(scratch.arena, vbptr_off)); + rd_printf("vbind : %S", cv_string_from_numeric(scratch.arena, vbtable_off)); } break; case CV_LeafKind_BCLASS: { - CV_LeafBClass lf = {0}; + CV_LeafBClass lf = {0}; CV_NumericParsed offset = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += cv_read_numeric(raw_leaf, cursor, &offset); - rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); - rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, offset)); + rd_printf("Attribs: %#x (%S)", lf.attribs, cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Offset : %S", cv_string_from_numeric(scratch.arena, offset)); } break; case CV_LeafKind_VTSHAPE: { CV_LeafVTShape lf = {0}; @@ -4837,26 +5196,26 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i } break; case CV_LeafKind_STMEMBER_ST: case CV_LeafKind_STMEMBER: { - CV_LeafStMember lf = {0}; + CV_LeafStMember lf = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Name : %S", name); + rd_printf("Attribs: %#x (%S)", lf.attribs, cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MFUNCTION: { CV_LeafMFunction lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Return Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); - rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.class_itype)); - rd_printf("This Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.this_itype)); - rd_printf("Call Kind: %S", cv_string_from_call_kind(lf.call_kind)); - rd_printf("Function Attribs: %S", cv_string_from_function_attribs(scratch.arena, lf.attribs)); - rd_printf("Argument Count: %u", lf.arg_count); - rd_printf("Argument Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); + rd_printf("Return Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); + rd_printf("Class Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.class_itype)); + rd_printf("This Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.this_itype)); + rd_printf("Call Kind : %#x (%S)", lf.call_kind, cv_string_from_call_kind(lf.call_kind)); + rd_printf("Function Attribs: %#x (%S)", lf.attribs, cv_string_from_function_attribs(scratch.arena, lf.attribs)); + rd_printf("Argument Count : %u", lf.arg_count); + rd_printf("Argument Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; #if 0 case CV_LeafKind_SKIP_16t: { @@ -4880,11 +5239,11 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.base_itype)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Name : %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties : %#x (%S)", lf.props, cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.base_itype)); + rd_printf("Field : %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -4899,9 +5258,9 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += cv_read_numeric(raw_leaf, cursor, &value); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Value: %S", cv_string_from_numeric(scratch.arena, value)); + rd_printf("Value : %S", cv_string_from_numeric(scratch.arena, value)); } break; case CV_LeafKind_NESTTYPE_ST: case CV_LeafKind_NESTTYPE: { @@ -4909,7 +5268,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); rd_printf("Index: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_NOTTRAN: { @@ -4928,7 +5287,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &string); - rd_printf("string: %S", string); + rd_printf("string : %S", string); rd_printf("Substrings: %S", cv_string_from_itemid(arena, lf.substr_list_id)); // TODO: print actual strings instead } break; case CV_LeafKind_POINTER: { @@ -4938,7 +5297,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i CV_PointerKind kind = CV_PointerAttribs_Extract_Kind(lf.attribs); CV_PointerMode mode = CV_PointerAttribs_Extract_Mode(lf.attribs); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); rd_printf("Attribs: %S", cv_string_from_pointer_attribs(arena, lf.attribs)); rd_indent(); if (mode == CV_PointerMode_PtrMem) { @@ -4948,7 +5307,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += str8_deserial_read_struct(raw_leaf, cursor, &pm); rd_printf("Class Type: %S", cv_string_from_itype(scratch.arena, min_itype, itype)); - rd_printf("Format: %S", cv_string_from_member_pointer_kind(pm)); + rd_printf("Format : %S", cv_string_from_member_pointer_kind(pm)); } else { if (kind == CV_PointerKind_BaseSeg) { U16 seg; @@ -4962,25 +5321,25 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); rd_printf("Base Type: %S", cv_string_from_itype(scratch.arena, min_itype, base_itype)); - rd_printf("Name: %S", name); + rd_printf("Name : %S", name); } } rd_unindent(); } break; case CV_LeafKind_UNION_ST: case CV_LeafKind_UNION: { - CV_LeafUnion lf = {0}; + CV_LeafUnion lf = {0}; CV_NumericParsed num = {0}; String8 name = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); - rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name : %S", name); + rd_printf("Field Count: %u", lf.count); + rd_printf("Properties : %#x (%S)", lf.props, cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field : %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Size : %S", cv_string_from_numeric(scratch.arena, num)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -4998,13 +5357,13 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Field Count: %u", lf.count); - rd_printf("Properties: %S", cv_string_from_type_props(scratch.arena, lf.props)); - rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); - rd_printf("Derived Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); - rd_printf("VShape: %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); - rd_printf("Size: %S", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name : %S", name); + rd_printf("Field Count : %u", lf.count); + rd_printf("Properties : %#x (%S)", lf.props, cv_string_from_type_props(scratch.arena, lf.props)); + rd_printf("Field List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.field_itype)); + rd_printf("Derived Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.derived_itype)); + rd_printf("VShape : %S", cv_string_from_itype(scratch.arena, min_itype, lf.vshape_itype)); + rd_printf("Size : %S", cv_string_from_numeric(scratch.arena, num)); if (lf.props & CV_TypeProp_HasUniqueName) { String8 unique_name = {0}; cursor += str8_deserial_read_cstr(raw_leaf, cursor, &unique_name); @@ -5032,11 +5391,11 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i String8 call_kind = cv_string_from_call_kind(lf.call_kind); String8 func_attribs = cv_string_from_function_attribs(scratch.arena, lf.attribs); - rd_printf("Return type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); - rd_printf("Call Convention: %S", call_kind); - rd_printf("Function Attribs: %S", func_attribs); - rd_printf("Argumnet Count: %u", lf.arg_count); - rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); + rd_printf("Return type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.ret_itype)); + rd_printf("Call Convention : %#x (%S)", lf.call_kind, call_kind); + rd_printf("Function Attribs : %#x (%S)", lf.attribs, func_attribs); + rd_printf("Argumnet Count : %u", lf.arg_count); + rd_printf("Argument List Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.arg_itype)); } break; case CV_LeafKind_FUNC_ID: { CV_LeafFuncId lf = {0}; @@ -5044,16 +5403,16 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Scope Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.scope_string_id)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Name : %S", name); + rd_printf("Scope Type: %#x (%S)", lf.scope_string_id, cv_string_from_itype(scratch.arena, min_itype, lf.scope_string_id)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); } break; case CV_LeafKind_MODIFIER: { CV_LeafModifier lf = {0}; cursor += str8_deserial_read_struct(raw_leaf, cursor, &lf); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); - rd_printf("Flags: %S", cv_string_from_modifier_flags(scratch.arena, lf.flags)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Flags: %#x (%S)", lf.flags, cv_string_from_modifier_flags(scratch.arena, lf.flags)); } break; case CV_LeafKind_ARRAY_ST: case CV_LeafKind_ARRAY: { @@ -5064,7 +5423,7 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i rd_printf("Entry type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.entry_itype)); rd_printf("Index type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.index_itype)); - rd_printf("Length: %S", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Length : %S", cv_string_from_numeric(scratch.arena, num)); } break; case CV_LeafKind_FIELDLIST: { for (U64 idx = 0; cursor < raw_leaf.size;) { @@ -5088,10 +5447,10 @@ cv_print_leaf(Arena *arena, String8List *out, String8 indent, CV_TypeIndex min_i cursor += cv_read_numeric(raw_leaf, cursor, &num); cursor += str8_deserial_read_cstr(raw_leaf, cursor, &name); - rd_printf("Name: %S", name); - rd_printf("Attribs: %S", cv_string_from_field_attribs(scratch.arena, lf.attribs)); - rd_printf("Type: %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); - rd_printf("Offset: %S", cv_string_from_numeric(scratch.arena, num)); + rd_printf("Name : %S", name); + rd_printf("Attribs: %#x (%S)", lf.attribs, cv_string_from_field_attribs(scratch.arena, lf.attribs)); + rd_printf("Type : %S", cv_string_from_itype(scratch.arena, min_itype, lf.itype)); + rd_printf("Offset : %S", cv_string_from_numeric(scratch.arena, num)); } break; case CV_LeafKind_LABEL: { CV_LeafLabel lf = {0}; @@ -5494,14 +5853,14 @@ cv_print_symbols_section(Arena *arena, } internal void -cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 raw_image, U64 string_table_off, U64 section_count, COFF_SectionHeader *sections) +cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *sections) { CV_Arch arch = ~0; { B32 keep_parsing = 1; for (U64 i = 0; i < section_count && keep_parsing; ++i) { COFF_SectionHeader *header = §ions[i]; - String8 sect_name = coff_name_from_section_header(raw_image, header, string_table_off); + String8 sect_name = coff_name_from_section_header(string_table, header); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); if (str8_match_lit(".debug$S", sect_name, 0)) { @@ -5549,7 +5908,7 @@ cv_format_debug_sections(Arena *arena, String8List *out, String8 indent, String8 for (U64 i = 0; i < section_count; ++i) { COFF_SectionHeader *header = §ions[i]; - String8 sect_name = coff_name_from_section_header(raw_image, header, string_table_off); + String8 sect_name = coff_name_from_section_header(string_table, header); Rng1U64 sect_frange = rng_1u64(header->foff, header->foff+header->fsize); String8 raw_sect = str8_substr(raw_image, sect_frange); if (str8_match_lit(".debug$S", sect_name, 0)) { @@ -5587,46 +5946,45 @@ coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, Temp scratch = scratch_begin(&arena, 1); String8 time_stamp = coff_string_from_time_stamp(scratch.arena, header.time_stamp); - rd_printf("Name: %S" , header.name ); - rd_printf("Time Stamp: %S" , time_stamp ); - rd_printf("User ID: %u" , header.user_id ); - rd_printf("Group ID: %u" , header.group_id); - rd_printf("Mode: %S" , header.mode ); - rd_printf("Data: [%#llx-%#llx)", header.data_range.min, header.data_range.max); + rd_printf("Name : %S" , header.name ); + rd_printf("Time Stamp: (%#x) %S" , header.time_stamp, time_stamp ); + rd_printf("User ID : %u" , header.user_id ); + rd_printf("Group ID : %u" , header.group_id); + rd_printf("Mode : %S" , header.mode ); + rd_printf("Data : [%#llx-%#llx)", header.data_range.min, header.data_range.max); scratch_end(scratch); } internal void -coff_print_seciton_table(Arena *arena, +coff_print_section_table(Arena *arena, String8List *out, String8 indent, - String8 raw_data, - U64 string_table_off, - COFF_Symbol32Array symbols, - U64 sect_count, - COFF_SectionHeader *sect_headers) + String8 string_table, + COFF_Symbol32Array symbol_table, + U64 section_count, + COFF_SectionHeader *section_table) { Temp scratch = scratch_begin(&arena, 1); - String8 *symlinks = push_array(scratch.arena, String8, sect_count); - for (U64 i = 0; i < symbols.count; ++i) { - COFF_Symbol32 *symbol = symbols.v+i; + String8 *symlinks = push_array(scratch.arena, String8, section_count); + for (U64 i = 0; i < symbol_table.count; ++i) { + COFF_Symbol32 *symbol = symbol_table.v+i; COFF_SymbolValueInterpType interp = coff_interp_symbol(symbol->section_number, symbol->value, symbol->storage_class); if (interp == COFF_SymbolValueInterp_Regular && symbol->aux_symbol_count == 0 && (symbol->storage_class == COFF_SymStorageClass_External || symbol->storage_class == COFF_SymStorageClass_Static)) { - if (symbol->section_number > 0 && symbol->section_number <= symbols.count) { - COFF_SectionHeader *header = sect_headers+(symbol->section_number-1); + if (symbol->section_number > 0 && symbol->section_number <= symbol_table.count) { + COFF_SectionHeader *header = section_table+(symbol->section_number-1); if (header->flags & COFF_SectionFlag_LnkCOMDAT) { - symlinks[symbol->section_number-1] = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + symlinks[symbol->section_number-1] = coff_read_symbol_name(string_table, &symbol->name); } } } i += symbol->aux_symbol_count; } - if (sect_count) { + if (section_count) { rd_printf("# Section Table"); rd_indent(); @@ -5645,11 +6003,11 @@ coff_print_seciton_table(Arena *arena, "Flags", "Symlink"); - for (U64 i = 0; i < sect_count; ++i) { - COFF_SectionHeader *header = sect_headers+i; + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *header = section_table+i; String8 name = str8_cstring_capped(header->name, header->name+sizeof(header->name)); - String8 full_name = coff_name_from_section_header(raw_data, header, string_table_off); + String8 full_name = coff_name_from_section_header(string_table, header); String8 align; { @@ -5829,13 +6187,13 @@ coff_raw_data_sections(Arena *arena, String8 indent, String8 raw_data, B32 is_obj, - RD_MarkerArray *section_markers, + RD_MarkerArray *section_markers, U64 section_count, - COFF_SectionHeader *sections) + COFF_SectionHeader *section_table) { if (section_count) { for (U64 sect_idx = 0; sect_idx < section_count; ++sect_idx) { - COFF_SectionHeader *sect = sections+sect_idx; + COFF_SectionHeader *sect = section_table+sect_idx; if (sect->fsize > 0) { U64 sect_size = is_obj ? sect->fsize : sect->vsize; String8 raw_sect = str8_substr(raw_data, rng_1u64(sect->foff, sect->foff+sect_size)); @@ -5856,7 +6214,7 @@ coff_print_relocs(Arena *arena, String8List *out, String8 indent, String8 raw_data, - U64 string_table_off, + String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, @@ -5904,7 +6262,7 @@ coff_print_relocs(Arena *arena, } COFF_Symbol32 *symbol = symbols.v+reloc->isymbol; - String8 symbol_name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + String8 symbol_name = coff_read_symbol_name(string_table, &symbol->name); String8List line = {0}; str8_list_pushf(scratch.arena, &line, "%-4x", reloc_idx ); @@ -5935,7 +6293,7 @@ coff_print_symbol_table(Arena *arena, String8 indent, String8 raw_data, B32 is_big_obj, - U64 string_table_off, + String8 string_table, COFF_Symbol32Array symbols) { Temp scratch = scratch_begin(&arena, 1); @@ -5949,7 +6307,7 @@ coff_print_symbol_table(Arena *arena, for (U64 i = 0; i < symbols.count; ++i) { COFF_Symbol32 *symbol = &symbols.v[i]; - String8 name = coff_read_symbol_name(raw_data, string_table_off, &symbol->name); + String8 name = coff_read_symbol_name(string_table, &symbol->name); String8 msb = coff_string_from_sym_dtype(symbol->type.u.msb); String8 lsb = coff_string_from_sym_type(symbol->type.u.lsb); String8 storage_class = coff_string_from_sym_storage_class(symbol->storage_class); @@ -6039,11 +6397,11 @@ coff_print_big_obj_header(Arena *arena, String8List *out, String8 indent, COFF_B rd_printf("# Big Obj"); rd_indent(); - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Machine: %S", machine ); + rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp); + rd_printf("Machine : %#x (%S)", header->machine, machine ); rd_printf("Section Count: %u", header->section_count ); - rd_printf("Symbol Table: %#x", header->symbol_table_foff); - rd_printf("Symbol Count: %u", header->symbol_count ); + rd_printf("Symbol Table : %#x", header->symbol_table_foff); + rd_printf("Symbol Count : %u", header->symbol_count ); rd_unindent(); scratch_end(scratch); @@ -6060,13 +6418,13 @@ coff_print_file_header(Arena *arena, String8List *out, String8 indent, COFF_File rd_printf("# COFF File Header"); rd_indent(); - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Machine: %S", machine ); - rd_printf("Section Count: %u", header->section_count ); - rd_printf("Symbol Table: %#x", header->symbol_table_foff ); - rd_printf("Symbol Count: %u", header->symbol_count ); - rd_printf("Optional Header Size: %m", header->optional_header_size); - rd_printf("Flags: %S", flags ); + rd_printf("Time Stamp : %#x (%S)", header->time_stamp, time_stamp ); + rd_printf("Machine : %#x %S", header->machine, machine ); + rd_printf("Section Count : %u", header->section_count ); + rd_printf("Symbol Table : %#x", header->symbol_table_foff ); + rd_printf("Symbol Count : %u", header->symbol_count ); + rd_printf("Optional Header Size: %#x (%m)", header->optional_header_size, header->optional_header_size); + rd_printf("Flags : %#x (%S)", header->flags, flags ); rd_unindent(); scratch_end(scratch); @@ -6082,15 +6440,15 @@ coff_print_import(Arena *arena, String8List *out, String8 indent, COFF_ParsedArc rd_printf("# Import"); rd_indent(); - rd_printf("Version: %u", header->version ); - rd_printf("Machine: %S", machine ); - rd_printf("Time Stamp: %S", time_stamp ); - rd_printf("Data Size: %m", header->data_size ); - rd_printf("Hint: %u", header->hint_or_ordinal); - rd_printf("Type: %u", header->type ); - rd_printf("Import By: %u", header->import_by ); - rd_printf("Function: %S", header->func_name ); - rd_printf("DLL: %S", header->dll_name ); + rd_printf("Version : %u", header->version ); + rd_printf("Machine : %S", machine ); + rd_printf("Time Stamp: %#x (%S)", header->time_stamp, time_stamp ); + rd_printf("Data Size : %#x (%m)", header->data_size, header->data_size); + rd_printf("Hint : %u", header->hint_or_ordinal); + rd_printf("Type : %u", header->type ); + rd_printf("Import By : %u", header->import_by ); + rd_printf("Function : %S", header->func_name ); + rd_printf("DLL : %S", header->dll_name ); rd_unindent(); scratch_end(scratch); @@ -6101,10 +6459,15 @@ coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_d { Temp scratch = scratch_begin(&arena, 1); - COFF_BigObjHeader *big_obj = str8_deserial_get_raw_ptr(raw_data, 0, sizeof(COFF_BigObjHeader)); - COFF_SectionHeader *sections = str8_deserial_get_raw_ptr(raw_data, sizeof(COFF_BigObjHeader), sizeof(COFF_SectionHeader)*big_obj->section_count); - U64 string_table_off = big_obj->symbol_table_foff + sizeof(COFF_Symbol32)*big_obj->symbol_count; - COFF_Symbol32Array symbols = coff_symbol_array_from_data_32(scratch.arena, raw_data, big_obj->symbol_table_foff, big_obj->symbol_count); + COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data); + + String8 raw_header = str8_substr(raw_data, header_info.header_range); + String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range); + String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range); + + COFF_BigObjHeader *big_obj = (COFF_BigObjHeader *)raw_header.str; + COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; + COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_32(scratch.arena, raw_data, header_info.symbol_table_range.min, big_obj->symbol_count); if (opts & RD_Option_Headers) { coff_print_big_obj_header(arena, out, indent, big_obj); @@ -6131,17 +6494,17 @@ coff_print_big_obj(Arena *arena, String8List *out, String8 indent, String8 raw_d } } - coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, big_obj->section_count, sections); + coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, big_obj->section_count, section_table); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_print_relocs(arena, out, indent, raw_data, string_table_off, big_obj->machine, big_obj->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, raw_string_table, big_obj->machine, big_obj->section_count, section_table, symbol_table); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_print_symbol_table(arena, out, indent, raw_data, 1, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 1, raw_string_table, symbol_table); rd_newline(); } @@ -6154,11 +6517,16 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, { Temp scratch = scratch_begin(&arena, 1); - COFF_FileHeader *header = (COFF_FileHeader *)raw_data.str; - COFF_SectionHeader *sections = (COFF_SectionHeader *)(header+1); - U64 string_table_off = header->symbol_table_foff + sizeof(COFF_Symbol16)*header->symbol_count; - COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, header->symbol_table_foff, header->symbol_count); - Arch arch = arch_from_coff_machine(header->machine); + COFF_FileHeaderInfo header_info = coff_file_header_info_from_data(raw_data); + + String8 raw_header = str8_substr(raw_data, header_info.header_range); + String8 raw_section_table = str8_substr(raw_data, header_info.section_table_range); + String8 raw_string_table = str8_substr(raw_data, header_info.string_table_range); + + COFF_FileHeader *header = (COFF_FileHeader *)raw_header.str; + COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; + COFF_Symbol32Array symbol_table = coff_symbol_array_from_data_16(scratch.arena, raw_data, header_info.symbol_table_range.min, header->symbol_count); + Arch arch = arch_from_coff_machine(header->machine); if (opts & RD_Option_Headers) { coff_print_file_header(arena, out, indent, header); @@ -6185,41 +6553,41 @@ coff_print_obj(Arena *arena, String8List *out, String8 indent, String8 raw_data, } } - coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, header->section_count, sections); + coff_print_section_table(arena, out, indent, raw_string_table, symbol_table, header->section_count, section_table); rd_newline(); } if (opts & RD_Option_Relocs) { - coff_print_relocs(arena, out, indent, raw_data, string_table_off, header->machine, header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, raw_string_table, header->machine, header->section_count, section_table, symbol_table); rd_newline(); } if (opts & RD_Option_Symbols) { - coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbol_table); rd_newline(); } RD_MarkerArray *section_markers = 0; if (opts & (RD_Option_Disasm|RD_Option_Rawdata)) { - section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, header->section_count, symbols); + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, header->section_count, symbol_table); } if (opts & RD_Option_Rawdata) { - coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, sections); + coff_raw_data_sections(arena, out, indent, raw_data, 1, section_markers, header->section_count, section_table); } if (opts & RD_Option_Disasm) { - coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, sections); + coff_disasm_sections(arena, out, indent, raw_data, header->machine, 0, 1, section_markers, header->section_count, section_table); rd_newline(); } if (opts & RD_Option_Codeview) { - cv_format_debug_sections(arena, out, indent, raw_data, string_table_off, header->section_count, sections); + cv_format_debug_sections(arena, out, indent, raw_data, raw_string_table, header->section_count, section_table); } if (opts & RD_Option_Dwarf) { - DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, header->section_count, sections); - dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_CoffPe); + DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, header->section_count, section_table); + dw_format(arena, out, indent, opts, &dwarf_input, arch, Image_CoffPe); } exit:; @@ -6243,8 +6611,8 @@ coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_a rd_printf("# First Header"); rd_indent(); - rd_printf("Symbol Count: %u", first_member.symbol_count); - rd_printf("String Table Size: %M", first_member.string_table.size); + rd_printf("Symbol Count : %u", first_member.symbol_count); + rd_printf("String Table Size: %#llx (%M)", first_member.string_table.size, first_member.string_table.size); rd_printf("Members:"); rd_indent(); @@ -6273,9 +6641,9 @@ coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_a rd_printf("# Second Header"); rd_indent(); - rd_printf("Member Count: %u", second_member.member_count); - rd_printf("Symbol Count: %u", second_member.symbol_count); - rd_printf("String Table Size: %M", second_member.string_table.size); + rd_printf("Member Count : %u", second_member.member_count); + rd_printf("Symbol Count : %u", second_member.symbol_count); + rd_printf("String Table Size: %#llx (%M)", second_member.string_table.size, second_member.string_table.size); String8List string_table = str8_split_by_string_chars(scratch.arena, second_member.string_table, str8_lit("\0"), 0); @@ -6387,56 +6755,6 @@ coff_print_archive(Arena *arena, String8List *out, String8 indent, String8 raw_a scratch_end(scratch); } -internal String8 -coff_string_from_resource_id(Arena *arena, COFF_ResourceID id) -{ - String8 result = str8_zero(); - switch (id.type) { - case COFF_ResourceIDType_Null: result = str8_lit("\?\?\?"); break; - case COFF_ResourceIDType_Number: result = push_str8f(arena, "%u", id.u.number); break; - case COFF_ResourceIDType_String: result = id.u.string; break; - } - return result; -} - -internal void -coff_print_parsed_res(Arena *arena, String8List *out, String8 indent, COFF_ParsedResource *res) -{ - Temp scratch = scratch_begin(&arena, 1); - - String8 type; - if (res->type.type == COFF_ResourceIDType_Number) { - type = pe_resource_kind_to_string(res->type.u.number); - } else { - type = coff_string_from_resource_id(scratch.arena, res->type); - } - - String8 name = coff_string_from_resource_id(scratch.arena, res->name); - String8 flags = coff_string_from_resource_memory_flags(scratch.arena, res->memory_flags); - - rd_printf("Type: %S", type); - rd_printf("Name: %S", name); - rd_printf("Language ID: %u", res->language_id); - rd_printf("Data Version: %u", res->data_version); - rd_printf("Version: %u", res->version); - rd_printf("Memory Flags: %S", flags); - rd_printf("Data size: %u (bytes)", res->data.size); - - scratch_end(scratch); -} - -internal void -coff_print_res(Arena *arena, String8List *out, String8 indent, String8 raw_res) -{ - Temp scratch = scratch_begin(&arena, 1); - COFF_ParsedResourceList res_list = coff_resource_list_from_data(scratch.arena, raw_res); - for (COFF_ParsedResourceNode *n = res_list.first; n != 0; n = n->next) { - coff_print_parsed_res(arena, out, indent, &n->data); - rd_newline(); - } - scratch_end(scratch); -} - // MSVC CRT internal void @@ -6445,11 +6763,11 @@ mscrt_print_eh_handler_type32(Arena *arena, String8List *out, String8 indent, RD Temp scratch = scratch_begin(&arena, 1); String8 catch_line = rd_format_line_from_voff(scratch.arena, rdi, handler->catch_handler_voff, PathStyle_WindowsAbsolute); String8 adjectives_str = mscrt_string_from_eh_adjectives(scratch.arena, handler->adjectives); - rd_printf("Adjectives: %S", adjectives_str, handler->adjectives); - rd_printf("Descriptor: %#x", handler->descriptor_voff); - rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); - rd_printf("Catch Handler: %#x%s%S", handler->catch_handler_voff, catch_line.size ? " " : "", catch_line); - rd_printf("Delta to FP Handler: %#x", handler->fp_distance); + rd_printf("Adjectives : %#x (%S)", handler->adjectives, adjectives_str); + rd_printf("Descriptor : %#x", handler->descriptor_voff); + rd_printf("Catch Object Frame Offset: %#x", handler->catch_obj_frame_offset); + rd_printf("Catch Handler : %#x%s%S", handler->catch_handler_voff, catch_line.size ? " " : "", catch_line); + rd_printf("Delta to FP Handler : %#x", handler->fp_distance); scratch_end(scratch); } @@ -6484,32 +6802,32 @@ pe_print_optional_header32(Arena *arena, String8List *out, String8 indent, PE_Op rd_printf("# PE Optional Header 32"); rd_indent(); - rd_printf("Magic: %#x", opt_header->magic); - rd_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); - rd_printf("Size of code: %m", opt_header->sizeof_code); - rd_printf("Size of inited data: %m", opt_header->sizeof_inited_data); - rd_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); - rd_printf("Entry point: %#x", opt_header->entry_point_va); - rd_printf("Code base: %#x", opt_header->code_base); - rd_printf("Data base: %#x", opt_header->data_base); - rd_printf("Image base: %#x", opt_header->image_base); - rd_printf("Section align: %#x", opt_header->section_alignment); - rd_printf("File align: %#x", opt_header->file_alignment); - rd_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); - rd_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); - rd_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); - rd_printf("Win32 version: %u", opt_header->win32_version_value); - rd_printf("Size of image: %m", opt_header->sizeof_image); - rd_printf("Size of headers: %m", opt_header->sizeof_headers); - rd_printf("Checksum: %#x", opt_header->check_sum); - rd_printf("Subsystem: %S", subsystem); - rd_printf("DLL Characteristics: %S", dll_chars); - rd_printf("Stack reserve: %m", opt_header->sizeof_stack_reserve); - rd_printf("Stack commit: %m", opt_header->sizeof_stack_commit); - rd_printf("Heap reserve: %m", opt_header->sizeof_heap_reserve); - rd_printf("Heap commit: %m", opt_header->sizeof_heap_commit); - rd_printf("Loader flags: %#x", opt_header->loader_flags); - rd_printf("RVA and offset count: %u", opt_header->data_dir_count); + rd_printf("Magic : %#x", opt_header->magic); + rd_printf("Linker version : %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); + rd_printf("Size of code : %#-8x (%m)", opt_header->sizeof_code, opt_header->sizeof_code); + rd_printf("Size of inited data : %#-8x (%m)", opt_header->sizeof_inited_data, opt_header->sizeof_inited_data); + rd_printf("Size of uninited data: %#-8x (%m)", opt_header->sizeof_uninited_data, opt_header->sizeof_uninited_data); + rd_printf("Entry point : %#x", opt_header->entry_point_va); + rd_printf("Code base : %#x", opt_header->code_base); + rd_printf("Data base : %#x", opt_header->data_base); + rd_printf("Image base : %#x", opt_header->image_base); + rd_printf("Section align : %#x", opt_header->section_alignment); + rd_printf("File align : %#x", opt_header->file_alignment); + rd_printf("OS version : %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); + rd_printf("Image Version : %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); + rd_printf("Subsystem version : %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); + rd_printf("Win32 version : %u", opt_header->win32_version_value); + rd_printf("Size of image : %#x (%m)", opt_header->sizeof_image, opt_header->sizeof_image); + rd_printf("Size of headers : %#x (%m)", opt_header->sizeof_headers, opt_header->sizeof_headers); + rd_printf("Checksum : %#x", opt_header->check_sum); + rd_printf("Subsystem : %#x (%S)", opt_header->subsystem, subsystem); + rd_printf("DLL Characteristics : %#x (%S)", opt_header->dll_characteristics, dll_chars); + rd_printf("Stack reserve : %#-8x (%m)", opt_header->sizeof_stack_reserve, opt_header->sizeof_stack_reserve); + rd_printf("Stack commit : %#-8x (%m)", opt_header->sizeof_stack_commit, opt_header->sizeof_stack_commit); + rd_printf("Heap reserve : %#-8x (%m)", opt_header->sizeof_heap_reserve, opt_header->sizeof_heap_reserve); + rd_printf("Heap commit : %#-8x (%m)", opt_header->sizeof_heap_commit, opt_header->sizeof_heap_commit); + rd_printf("Loader flags : %#x", opt_header->loader_flags); + rd_printf("RVA and offset count : %u", opt_header->data_dir_count); rd_newline(); pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); @@ -6528,31 +6846,31 @@ pe_print_optional_header32plus(Arena *arena, String8List *out, String8 indent, P rd_printf("# PE Optional Header 32+"); rd_indent(); - rd_printf("Magic: %#x", opt_header->magic); - rd_printf("Linker version: %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); - rd_printf("Size of code: %m", opt_header->sizeof_code); - rd_printf("Size of inited data: %m", opt_header->sizeof_inited_data); - rd_printf("Size of uninited data: %m", opt_header->sizeof_uninited_data); - rd_printf("Entry point: %#x", opt_header->entry_point_va); - rd_printf("Code base: %#x", opt_header->code_base); - rd_printf("Image base: %#llx", opt_header->image_base); - rd_printf("Section align: %#x", opt_header->section_alignment); - rd_printf("File align: %#x", opt_header->file_alignment); - rd_printf("OS version: %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); - rd_printf("Image Version: %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); - rd_printf("Subsystem version: %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); - rd_printf("Win32 version: %u", opt_header->win32_version_value); - rd_printf("Size of image: %m", opt_header->sizeof_image); - rd_printf("Size of headers: %m", opt_header->sizeof_headers); - rd_printf("Checksum: %#x", opt_header->check_sum); - rd_printf("Subsystem: %S", subsystem); - rd_printf("DLL Characteristics: %S", dll_chars); - rd_printf("Stack reserve: %M", opt_header->sizeof_stack_reserve); - rd_printf("Stack commit: %M", opt_header->sizeof_stack_commit); - rd_printf("Heap reserve: %M", opt_header->sizeof_heap_reserve); - rd_printf("Heap commit: %M", opt_header->sizeof_heap_commit); - rd_printf("Loader flags: %#x", opt_header->loader_flags); - rd_printf("RVA and offset count: %u", opt_header->data_dir_count); + rd_printf("Magic : %#x", opt_header->magic); + rd_printf("Linker version : %u.%u", opt_header->major_linker_version, opt_header->minor_linker_version); + rd_printf("Size of code : %#-8x (%m)", opt_header->sizeof_code, opt_header->sizeof_code); + rd_printf("Size of inited data : %#-8x (%m)", opt_header->sizeof_inited_data, opt_header->sizeof_inited_data); + rd_printf("Size of uninited data: %#-8x (%m)", opt_header->sizeof_uninited_data, opt_header->sizeof_uninited_data); + rd_printf("Entry point : %#x", opt_header->entry_point_va); + rd_printf("Code base : %#x", opt_header->code_base); + rd_printf("Image base : %#llx", opt_header->image_base); + rd_printf("Section align : %#x", opt_header->section_alignment); + rd_printf("File align : %#x", opt_header->file_alignment); + rd_printf("OS version : %u.%u", opt_header->major_os_ver, opt_header->minor_os_ver); + rd_printf("Image Version : %u.%u", opt_header->major_img_ver, opt_header->minor_img_ver); + rd_printf("Subsystem version : %u.%u", opt_header->major_subsystem_ver, opt_header->minor_subsystem_ver); + rd_printf("Win32 version : %u", opt_header->win32_version_value); + rd_printf("Size of image : %#x (%m)", opt_header->sizeof_image, opt_header->sizeof_image); + rd_printf("Size of headers : %#x (%m)", opt_header->sizeof_headers, opt_header->sizeof_headers); + rd_printf("Checksum : %#x", opt_header->check_sum); + rd_printf("Subsystem : %#llx (%S)", opt_header->subsystem, subsystem); + rd_printf("DLL Characteristics : %#llx (%S)", opt_header->dll_characteristics, dll_chars); + rd_printf("Stack reserve : %#-8llx (%M)", opt_header->sizeof_stack_reserve, opt_header->sizeof_stack_reserve); + rd_printf("Stack commit : %#-8llx (%M)", opt_header->sizeof_stack_commit, opt_header->sizeof_stack_commit); + rd_printf("Heap reserve : %#-8llx (%M)", opt_header->sizeof_heap_reserve, opt_header->sizeof_heap_reserve); + rd_printf("Heap commit : %#-8llx (%M)", opt_header->sizeof_heap_commit, opt_header->sizeof_heap_commit); + rd_printf("Loader flags : %#x", opt_header->loader_flags); + rd_printf("RVA and offset count : %u", opt_header->data_dir_count); rd_newline(); pe_print_data_directory_ranges(arena, out, indent, opt_header->data_dir_count, dirs); @@ -7202,9 +7520,6 @@ pe_print_exceptions_x8664(Arena *arena, PE_IntelPdata *pdata = str8_deserial_get_raw_ptr(raw_except, pdata_offset, sizeof(*pdata)); String8 pdata_name = rd_proc_name_from_voff(rdi, pdata->voff_first); - if (pdata->voff_first == 0x0020cf44) { - int x = 0; - } U64 unwind_info_offset = coff_foff_from_voff(sections, section_count, pdata->voff_unwind_info); PE_UnwindInfo *uwinfo = str8_deserial_get_raw_ptr(raw_data, unwind_info_offset, sizeof(*uwinfo)); @@ -7653,9 +7968,9 @@ pe_print_exceptions(Arena *arena, rd_indent(); rd_printf("%-8s %-8s %-8s %-8s", "Offset", "Begin", "End", "Unwind Info"); switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X64: - case COFF_Machine_X86: { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X64: + case COFF_MachineType_X86: { pe_print_exceptions_x8664(arena, out, indent, section_count, sections, raw_data, except_frange, rdi); } break; default: NotImplemented; break; @@ -7688,9 +8003,9 @@ pe_print_base_relocs(Arena *arena, U32 addr_size = 0; switch (machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: addr_size = 4; break; - case COFF_Machine_X64: addr_size = 8; break; + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: addr_size = 4; break; + case COFF_MachineType_X64: addr_size = 8; break; default: NotImplemented; } @@ -7720,9 +8035,9 @@ pe_print_base_relocs(Arena *arena, case PE_BaseRelocKind_DIR64: type_str = "DIR64"; break; default: { switch (machine) { - case COFF_Machine_Arm: - case COFF_Machine_Arm64: - case COFF_Machine_ArmNt: { + case COFF_MachineType_Arm: + case COFF_MachineType_Arm64: + case COFF_MachineType_ArmNt: { switch (type) { case PE_BaseRelocKind_ARM_MOV32: type_str = "ARM_MOV32"; break; case PE_BaseRelocKind_THUMB_MOV32: type_str = "THUMB_MOV32"; break; @@ -7803,7 +8118,8 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op goto exit; } - U64 string_table_off = file_header->symbol_table_foff + sizeof(COFF_Symbol16) * file_header->symbol_count; + U64 string_table_off = file_header->symbol_table_foff + sizeof(COFF_Symbol16) * file_header->symbol_count; + String8 raw_string_table = str8_substr(raw_data, rng_1u64(string_table_off, raw_data.size)); COFF_Symbol32Array symbols = coff_symbol_array_from_data_16(scratch.arena, raw_data, file_header->symbol_table_foff, file_header->symbol_count); @@ -7859,15 +8175,15 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op } if (opts & RD_Option_Sections) { - coff_print_seciton_table(arena, out, indent, raw_data, string_table_off, symbols, file_header->section_count, sections); + coff_print_section_table(arena, out, indent, raw_string_table, symbols, file_header->section_count, sections); } if (opts & RD_Option_Relocs) { - coff_print_relocs(arena, out, indent, raw_data, string_table_off, file_header->machine, file_header->section_count, sections, symbols); + coff_print_relocs(arena, out, indent, raw_data, raw_string_table, file_header->machine, file_header->section_count, sections, symbols); } if (opts & RD_Option_Symbols) { - coff_print_symbol_table(arena, out, indent, raw_data, 0, string_table_off, symbols); + coff_print_symbol_table(arena, out, indent, raw_data, 0, raw_string_table, symbols); } if (opts & RD_Option_Exports) { @@ -7920,8 +8236,8 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op String8 raw_lc = str8_substr(raw_data, dirs_file_ranges[PE_DataDirectoryIndex_LOAD_CONFIG]); if (raw_lc.size) { switch (file_header->machine) { - case COFF_Machine_Unknown: break; - case COFF_Machine_X86: { + case COFF_MachineType_Unknown: break; + case COFF_MachineType_X86: { PE_LoadConfig32 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { pe_print_load_config32(arena, out, indent, lc); @@ -7929,7 +8245,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op rd_errorf("not enough bytes to parse 32bit load config"); } } break; - case COFF_Machine_X64: { + case COFF_MachineType_X64: { PE_LoadConfig64 *lc = str8_deserial_get_raw_ptr(raw_lc, 0, sizeof(*lc)); if (lc) { pe_print_load_config64(arena, out, indent, lc); @@ -7947,7 +8263,7 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op if (rdi) { section_markers = rd_section_markers_from_rdi(scratch.arena, rdi); } else { - section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_data, string_table_off, file_header->section_count, symbols); + section_markers = rd_section_markers_from_coff_symbol_table(scratch.arena, raw_string_table, file_header->section_count, symbols); } } @@ -7960,11 +8276,130 @@ pe_print(Arena *arena, String8List *out, String8 indent, String8 raw_data, RD_Op } if (opts & RD_Option_Dwarf) { - DW_SectionArray dwarf_sections = rd_dw_sections_from_coff_section_table(scratch.arena, raw_data, string_table_off, file_header->section_count, sections); - dw_format(arena, out, indent, opts, &dwarf_sections, arch, Image_CoffPe); + DW_Input dwarf_input = dw_input_from_coff_section_table(scratch.arena, raw_data, raw_string_table, file_header->section_count, sections); + dw_format(arena, out, indent, opts, &dwarf_input, arch, Image_CoffPe); } exit:; scratch_end(scratch); } +#if 0 +internal void +elf_print_dwarf_expressions(Arena *arena, String8List *out, String8 indent, String8 raw_data) +{ + Temp scratch = scratch_begin(&arena, 1); + + ELF_BinInfo bin = elf_bin_from_data(raw_data); + Arch arch = arch_from_elf_machine(bin.hdr.e_machine); + DW_Input dwarf_input = dw_input_from_elf_section_table(scratch.arena, raw_data, &bin); + ELF_Class elf_class = bin.hdr.e_ident[ELF_Identifier_Class]; + ImageType image_type = elf_class == ELF_Class_32 ? Image_Elf32 : elf_class == ELF_Class_64 ? Image_Elf64 : ELF_Class_None; + B32 relaxed = 1; + Rng1U64List cu_ranges = dw_unit_ranges_from_data(scratch.arena, dwarf_input.sec[DW_Section_Info].data); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &dwarf_input); + + if (bin.hdr.e_type == ELF_Type_Exec || bin.hdr.e_type == ELF_Type_Dyn) { + U64 cu_idx = 0; + for (Rng1U64Node *cu_range_n = cu_ranges.first; cu_range_n != 0; cu_range_n = cu_range_n->next, ++cu_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + U64 cu_base = cu_range_n->v.min; + Rng1U64 cu_range = cu_range_n->v; + DW_CompUnit cu = dw_cu_from_info_off(comp_temp.arena, &dwarf_input, lu_input, cu_range.min, relaxed); + + struct TagNode { + struct TagNode *next; + DW_Tag tag; + }; + struct TagNode *tag_stack = 0; + struct TagNode *free_tags = 0; + + S32 lexical_block_depth = 0; + + for (U64 info_off = cu.first_tag_info_off, tag_size = 0; info_off < cu.info_range.max; info_off += tag_size) { + DW_Tag tag = {0}; + tag_size = dw_read_tag_cu(comp_temp.arena, &dwarf_input, &cu, info_off, &tag); + if (tag.has_children) { + struct TagNode *n = free_tags; + if (n == 0) { + n = push_array(comp_temp.arena, struct TagNode, 1); + } else { + SLLStackPop(free_tags); + } + n->tag = tag; + SLLStackPush(tag_stack, n); + } + + if (tag.kind == DW_Tag_Null) { + if (tag_stack) { + struct TagNode *n = tag_stack; + if ((n->tag.kind == DW_Tag_SubProgram || n->tag.kind == DW_Tag_LexicalBlock)) { + Assert(lexical_block_depth > 0); + --lexical_block_depth; + } + SLLStackPop(tag_stack); + SLLStackPush(free_tags, n); + } + } else if (tag.kind == DW_Tag_LexicalBlock || tag.kind == DW_Tag_SubProgram) { + ++lexical_block_depth; + if (tag.kind == DW_Tag_SubProgram) { + String8 expr = dw_exprloc_from_attrib(&dwarf_input, &cu, tag, DW_Attrib_FrameBase); + if (expr.size > 0) { + String8 expr_str = dw_format_expression_single_line(comp_temp.arena, expr, cu_base, cu.address_size, arch, cu.version, cu.ext, cu.format); + } + } + } else if (tag.kind == DW_Tag_Variable || tag.kind == DW_Tag_FormalParameter) { +#if 0 + String8 name = dw_string_from_attrib(&dwarf_input, &cu, tag, DW_Attrib_Name); + DW_Attrib *location_attrib = dw_attrib_from_tag(&dwarf_input, &cu, tag, DW_Attrib_Location); + DW_AttribClass value_class = dw_value_class_from_attrib(&cu, location_attrib); + if (value_class != DW_AttribClass_Null) { + if (lexical_block_depth == 0) { + rd_printf("%llx Global: %S", info_off, name); + is_global_var = 1; + } else { + rd_printf("%llx Local: %S", info_off, name); + is_global_var = 0; + } + + rd_indent(); + if (value_class == DW_AttribClass_LocListPtr || value_class == DW_AttribClass_LocList) { + DW_LocList location = dw_loclist_from_attrib_ptr(comp_temp.arena, &dwarf_input, &cu, location_attrib); + for (DW_LocNode *loc_n = location.first; loc_n != 0; loc_n = loc_n->next) { + String8 expr_str = dw_format_expression_single_line(comp_temp.arena, loc_n->v.expr, cu_base, cu.address_size, arch, cu.version, cu.ext, cu.format); + rd_printf("[%llx-%llx] %S", loc_n->v.range.min, loc_n->v.range.max, expr_str); + } + } else if (value_class == DW_AttribClass_ExprLoc) { + String8 expr = dw_exprloc_from_attrib_ptr(&dwarf_input, &cu, location_attrib); + String8 expr_str = dw_format_expression_single_line(comp_temp.arena, expr, cu_base, cu.address_size, arch, cu.version, cu.ext, cu.format); + rd_printf("%S", expr_str); + } + rd_unindent(); + } +#endif + } + +#if 0 + if (tag.kind == DW_Tag_LexicalBlock || tag.kind == DW_Tag_CompileUnit || tag.kind == DW_Tag_InlinedSubroutine || tag.kind == DW_Tag_SubProgram) { + Temp temp = temp_begin(comp_temp.arena); + DW_Attrib *ranges_attrib = dw_attrib_from_tag(&dwarf_input, &cu, tag, DW_Attrib_Ranges); + if (ranges_attrib->attrib_kind == DW_Attrib_Ranges) { + Rng1U64List ranges = dw_rnglist_from_attrib_ptr(temp.arena, &dwarf_input, &cu, ranges_attrib); + } + temp_end(temp); + } +#endif + } + + temp_end(comp_temp); + } + } else { + fprintf(stderr, "Skipping unexpected ELF type %u\n", bin.hdr.e_type); + } + + scratch_end(scratch); +} +#endif + + diff --git a/src/raddump/raddump.h b/src/raddump/raddump.h index 16e074db..0daad497 100644 --- a/src/raddump/raddump.h +++ b/src/raddump/raddump.h @@ -65,7 +65,7 @@ typedef U64 RD_Option; RD_Option_DebugStrOffsets) #define RD_Option_RelaxDwarfParser (1ull << 31ull) // RDI -#define RD_Option_NoRdi (1ull << 32ull) +#define RD_Option_NoRdi (1ull << 32ull) #define RD_Option_RdiDataSections (1ull << 33ull) #define RD_Option_RdiTopLevelInfo (1ull << 34ull) #define RD_Option_RdiBinarySections (1ull << 35ull) @@ -86,6 +86,27 @@ typedef U64 RD_Option; #define RD_Option_RdiInlineSites (1ull << 51ull) #define RD_Option_RdiNameMaps (1ull << 52ull) #define RD_Option_RdiStrings (1ull << 53ull) +#define RD_Option_RdiAll (RD_Option_RdiDataSections | \ + RD_Option_RdiTopLevelInfo | \ + RD_Option_RdiBinarySections | \ + RD_Option_RdiFilePaths | \ + RD_Option_RdiSourceFiles | \ + RD_Option_RdiLineTables | \ + RD_Option_RdiSourceLineMaps | \ + RD_Option_RdiUnits | \ + RD_Option_RdiUnitVMap | \ + RD_Option_RdiTypeNodes | \ + RD_Option_RdiUserDefinedTypes | \ + RD_Option_RdiGlobalVars | \ + RD_Option_RdiGlobalVarsVMap | \ + RD_Option_RdiThreadVars | \ + RD_Option_RdiProcedures | \ + RD_Option_RdiScopes | \ + RD_Option_RdiScopeVMap | \ + RD_Option_RdiInlineSites | \ + RD_Option_RdiNameMaps | \ + RD_Option_RdiStrings) + typedef struct RD_Marker { @@ -140,7 +161,6 @@ typedef struct RD_Line // raddump -internal B32 rd_is_pe (String8 raw_data); internal B32 rd_is_rdi(String8 raw_data); internal String8 rd_string_from_flags(Arena *arena, String8List list, U64 remaining_flags); @@ -149,7 +169,7 @@ internal void rd_format_preamble(Arena *arena, String8List *out, String8 indent, // Markers -internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 raw_data, U64 string_table_off, U64 section_count, COFF_Symbol32Array symbols); +internal RD_MarkerArray * rd_section_markers_from_coff_symbol_table(Arena *arena, String8 string_table, U64 section_count, COFF_Symbol32Array symbols); // Sections @@ -171,7 +191,7 @@ internal String8 rdi_string_from_data_section_kind(Arena *arena, RDI_SectionKind internal String8 rdi_string_from_arch (Arena *arena, RDI_Arch v); internal String8 rdi_string_from_language (Arena *arena, RDI_Language v); internal String8 rdi_string_from_local_kind (Arena *arena, RDI_LocalKind v); -internal String8 rdi_string_from_type_kind (Arena *arena, RDI_TypeKind v); +//internal String8 rdi_string_from_type_kind (Arena *arena, RDI_TypeKind v); internal String8 rdi_string_from_member_kind (Arena *arena, RDI_MemberKind v); internal String8 rdi_string_from_binary_section_flags(Arena *arena, RDI_BinarySectionFlags flags); @@ -191,33 +211,33 @@ internal void rdi_print_type_node (Arena *arena, String8List *out, String8 internal void rdi_print_udt (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_UDT *udt); internal void rdi_print_global_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_GlobalVariable *gvar); internal void rdi_print_thread_variable(Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_ThreadVariable *tvar); -internal void rdi_print_procedure (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc); +internal void rdi_print_procedure (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Procedure *proc, RDI_Arch arch); internal void rdi_print_scope (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_Scope *scope, RDI_Arch arch); -internal void rdi_print_inline_site (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, RDI_InlineSite *inline_site); +internal void rdi_print_inline_site (Arena *arena, String8List *out, String8 indent, RDI_Parsed *rdi, U64 idx, RDI_InlineSite *inline_site); internal void rdi_print_vmap_entry (Arena *arena, String8List *out, String8 indent, RDI_VMapEntry *v); // DWARF -internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); -internal String8 dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); +internal String8 dw_format_expression_single_line(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal String8 dw_format_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc); -internal void dw_print_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, B32 is_dwarf64); +internal void dw_print_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format); internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx); -internal void dw_print_debug_info (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); -internal void dw_print_debug_abbrev (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_line (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, B32 relaxed); -internal void dw_print_debug_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); -internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Arch arch, ImageType image_type, B32 relaxed); -internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges, Arch arch); -internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections, Rng1U64Array segment_vranges); -internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); -internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_SectionArray *sections); +internal void dw_print_debug_info (Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_ListUnitInput lu_input, Arch arch, B32 relaxed); +internal void dw_print_debug_abbrev (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_line (Arena *arena, String8List *out, String8 indent, DW_Input *input, DW_ListUnitInput lu_input, B32 relaxed); +internal void dw_print_debug_str (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ImageType image_type, B32 relaxed); +internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_vranges, Arch arch); +internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Input *input, Rng1U64Array segment_vranges); +internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Input *input); +internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Input *input); // CodeView @@ -238,11 +258,11 @@ internal void cv_print_symbols_section(Arena *arena, String8List *out, String8 i // COFF internal void coff_print_archive_member_header(Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveMemberHeader header, String8 long_names); -internal void coff_print_seciton_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); +internal void coff_print_section_table (Arena *arena, String8List *out, String8 indent, String8 string_table, COFF_Symbol32Array symbols, U64 sect_count, COFF_SectionHeader *sect_headers); internal void coff_disasm_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, COFF_MachineType machine, U64 image_base, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); internal void coff_raw_data_sections (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_obj, RD_MarkerArray *section_markers, U64 section_count, COFF_SectionHeader *sections); -internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, U64 string_table_off, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); -internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, U64 string_table_off, COFF_Symbol32Array symbols); +internal void coff_print_relocs (Arena *arena, String8List *out, String8 indent, String8 raw_data, String8 string_table, COFF_MachineType machine, U64 sect_count, COFF_SectionHeader *sect_headers, COFF_Symbol32Array symbols); +internal void coff_print_symbol_table (Arena *arena, String8List *out, String8 indent, String8 raw_data, B32 is_big_obj, String8 string_table, COFF_Symbol32Array symbols); internal void coff_print_big_obj_header (Arena *arena, String8List *out, String8 indent, COFF_BigObjHeader *header); internal void coff_print_file_header (Arena *arena, String8List *out, String8 indent, COFF_FileHeader *header); internal void coff_print_import (Arena *arena, String8List *out, String8 indent, COFF_ParsedArchiveImportHeader *header); diff --git a/src/raddump/raddump_main.c b/src/raddump/raddump_main.c index 98888163..d6fee2b4 100644 --- a/src/raddump/raddump_main.c +++ b/src/raddump/raddump_main.c @@ -17,19 +17,25 @@ #include "third_party/zydis/zydis.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" +#define SINFL_IMPLEMENTATION +#include "third_party/sinfl/sinfl.h" //////////////////////////////// #include "base/base_inc.h" +#include "linker/base_ext/base_inc.h" #include "os/os_inc.h" #include "async/async.h" #include "rdi_format/rdi_format_local.h" #include "rdi_make/rdi_make_local.h" #include "path/path.h" +#include "linker/hash_table.h" #include "coff/coff.h" #include "coff/coff_enum.h" #include "coff/coff_parse.h" #include "pe/pe.h" +#include "elf/elf.h" +#include "elf/elf_parse.h" #include "msvc_crt/msvc_crt.h" #include "msvc_crt/msvc_crt_enum.h" #include "codeview/codeview.h" @@ -39,23 +45,34 @@ #include "msf/msf_parse.h" #include "pdb/pdb.h" #include "pdb/pdb_parse.h" -#include "rdi_from_pdb/rdi_from_pdb.h" #include "dwarf/dwarf.h" #include "dwarf/dwarf_parse.h" #include "dwarf/dwarf_expr.h" #include "dwarf/dwarf_unwind.h" +#include "dwarf/dwarf_coff.h" +#include "dwarf/dwarf_elf.h" #include "dwarf/dwarf_enum.h" +#include "radcon/radcon.h" +#include "radcon/radcon_coff.h" +#include "radcon/radcon_cv.h" +#include "radcon/radcon_elf.h" +#include "radcon/radcon_pdb.h" +#include "radcon/radcon_dwarf.h" #include "base/base_inc.c" +#include "linker/base_ext/base_inc.c" #include "os/os_inc.c" #include "async/async.c" #include "rdi_format/rdi_format_local.c" #include "rdi_make/rdi_make_local.c" #include "path/path.c" +#include "linker/hash_table.c" #include "coff/coff.c" #include "coff/coff_enum.c" #include "coff/coff_parse.c" #include "pe/pe.c" +#include "elf/elf.c" +#include "elf/elf_parse.c" #include "msvc_crt/msvc_crt.c" #include "msvc_crt/msvc_crt_enum.c" #include "codeview/codeview.c" @@ -65,23 +82,24 @@ #include "msf/msf_parse.c" #include "pdb/pdb.c" #include "pdb/pdb_parse.c" -#include "rdi_from_pdb/rdi_from_pdb.c" #include "dwarf/dwarf.c" #include "dwarf/dwarf_parse.c" #include "dwarf/dwarf_expr.c" #include "dwarf/dwarf_unwind.c" +#include "dwarf/dwarf_coff.c" +#include "dwarf/dwarf_elf.c" #include "dwarf/dwarf_enum.c" +#include "radcon/radcon_coff.c" +#include "radcon/radcon_cv.c" +#include "radcon/radcon_elf.c" +#include "radcon/radcon_pdb.c" +#include "radcon/radcon_dwarf.c" +#include "radcon/radcon.c" -#include "linker/base_ext/base_inc.h" -#include "linker/base_ext/base_inc.c" -#include "linker/path_ext/path.h" -#include "linker/path_ext/path.c" #include "linker/thread_pool/thread_pool.h" #include "linker/thread_pool/thread_pool.c" #include "linker/codeview_ext/codeview.h" #include "linker/codeview_ext/codeview.c" -#include "linker/hash_table.h" -#include "linker/hash_table.c" #include "linker/rdi/rdi.h" #include "linker/rdi/rdi.c" @@ -256,7 +274,13 @@ entry_point(CmdLine *cmdline) RDI_Parsed rdi = {0}; RDI_ParseStatus parse_status = rdi_parse(raw_data.str, raw_data.size, &rdi); switch (parse_status) { - case RDI_ParseStatus_Good: rdi_print(arena, out, indent, &rdi, opts); break; + case RDI_ParseStatus_Good: { + RD_Option rdi_print_opts = opts; + if ((rdi_print_opts & RD_Option_RdiAll) == 0) { + rdi_print_opts |= RD_Option_RdiAll; + } + rdi_print(arena, out, indent, &rdi, rdi_print_opts); + } break; case RDI_ParseStatus_HeaderDoesNotMatch: rd_errorf("RDI Parse: header does not match"); break; case RDI_ParseStatus_UnsupportedVersionNumber: rd_errorf("RDI Parse: unsupported version"); break; case RDI_ParseStatus_InvalidDataSecionLayout: rd_errorf("RDI Parse: invalid data section layout"); break; @@ -269,14 +293,16 @@ entry_point(CmdLine *cmdline) coff_print_big_obj(arena, out, indent, raw_data, opts); } else if (coff_is_obj(raw_data)) { coff_print_obj(arena, out, indent, raw_data, opts); - } else if (rd_is_pe(raw_data)) { + } else if (pe_check_magic(raw_data)) { RDI_Parsed *rdi = 0; if (!(opts & RD_Option_NoRdi)) { - rdi = rd_rdi_from_pe(arena, file_path, raw_data); + rdi = rd_rdi_from_pe(arena, file_path); } pe_print(arena, out, indent, raw_data, opts, rdi); } else if (pe_is_res(raw_data)) { - coff_print_res(arena, out, indent, raw_data); + //tool_out_coff_res(stdout, file_data); + } else if (elf_check_magic(raw_data)) { + //elf_print_dwarf_expressions(arena, out, indent, raw_data); } exit:; diff --git a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c index f3c72e7e..6e6b71d0 100644 --- a/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c +++ b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c @@ -21,6 +21,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" +#include "path/path.h" #include "async/async.h" #include "rdi_make/rdi_make_local.h" #include "coff/coff.h" @@ -38,6 +39,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" +#include "path/path.c" #include "async/async.c" #include "rdi_make/rdi_make_local.c" #include "coff/coff.c" diff --git a/src/rdi_dump/rdi_dump.c b/src/rdi_dump/rdi_dump.c deleted file mode 100644 index 8cfd3d59..00000000 --- a/src/rdi_dump/rdi_dump.c +++ /dev/null @@ -1,843 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: RDI Enum -> String Functions - -internal String8 -rdi_string_from_reg_code_x86(U64 reg_code) -{ -#define X(name, value) case RDI_RegCodeX86_##name: return str8_lit(#name); - switch (reg_code) { - RDI_RegCodeX86_XList - } -#undef X - return str8_lit(""); -} - -internal String8 -rdi_string_from_reg_code_x64(U64 reg_code) -{ -#define X(name, value) case RDI_RegCodeX64_##name: return str8_lit(#name); - switch (reg_code) { - RDI_RegCodeX64_XList - } -#undef X - return str8_lit(""); -} - -internal String8 -rdi_string_from_reg_code(RDI_Arch arch, U64 reg_code) -{ - switch (arch) { - case RDI_Arch_NULL: break; - case RDI_Arch_X86: return rdi_string_from_reg_code_x86(reg_code); - case RDI_Arch_X64: return rdi_string_from_reg_code_x64(reg_code); - default: InvalidPath; - } - return str8_lit(""); -} - -internal String8 -rdi_string_from_data_section_kind(RDI_SectionKind v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name, lower, type) case RDI_SectionKind_##name:{result = str8_lit(#name);}break; - RDI_SectionKind_XList -#undef X - } - return result; -} - -internal String8 -rdi_string_from_arch(RDI_Arch v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name) case RDI_Arch_##name:{result = str8_lit(#name);}break; - RDI_Arch_XList -#undef X - } - return result; -} - -internal String8 -rdi_string_from_language(RDI_Language v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name) case RDI_Language_##name:{result = str8_lit(#name);}break; - RDI_Language_XList -#undef X - } - return result; -} - -internal String8 -rdi_string_from_type_kind(RDI_TypeKind v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name) case RDI_TypeKind_##name:{result = str8_lit(#name);}break; - RDI_TypeKind_XList -#undef X - } - return result; -} - -internal String8 -rdi_string_from_member_kind(RDI_MemberKind v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name) case RDI_MemberKind_##name:{result = str8_lit(#name);}break; - RDI_MemberKind_XList -#undef X - } - return result; -} - -internal String8 -rdi_string_from_local_kind(RDI_LocalKind v) -{ - String8 result = str8_lit(""); - switch(v) - { - default:{}break; -#define X(name) case RDI_LocalKind_##name:{result = str8_lit(#name);}break; - RDI_LocalKind_XList -#undef X - } - return result; -} - -//////////////////////////////// -//~ rjf: RDI Flags -> String Functions - -internal void -rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags) -{ - if(flags == 0) { str8_list_push(arena, out, str8_lit("0")); } -#define X(name) if(flags & RDI_BinarySectionFlag_##name) { str8_list_push(arena, out, str8_lit(#name " ")); } - RDI_BinarySectionFlags_XList; -#undef X -} - -internal void -rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, - RDI_TypeModifierFlags flags) -{ - if(flags == 0) { str8_list_push(arena, out, str8_lit("0")); } -#define X(name) if(flags & RDI_TypeModifierFlag_##name) { str8_list_push(arena, out, str8_lit(#name " ")); } - RDI_TypeModifierFlags_XList; -#undef X -} - -internal void -rdi_stringize_udt_flags(Arena *arena, String8List *out, RDI_UDTFlags flags) -{ - if(flags == 0) { str8_list_push(arena, out, str8_lit("0")); } -#define X(name) if(flags & RDI_UDTFlag_##name) { str8_list_push(arena, out, str8_lit(#name " ")); } - RDI_UDTFlags_XList; -#undef X -} - -internal void -rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags) -{ - if(flags == 0) { str8_list_push(arena, out, str8_lit("0")); } -#define X(name) if(flags & RDI_LinkFlag_##name) { str8_list_push(arena, out, str8_lit(#name " ")); } - RDI_LinkFlags_XList; -#undef X -} - -//////////////////////////////// - -internal String8 -rdi_format_reg_code(Arena *arena, RDI_Arch arch, U64 reg_code) -{ - String8 result = {0}; - String8 reg_name = rdi_string_from_reg_code(arch, reg_code); - if (reg_name.size) { - result = push_str8f(arena, "%S", reg_name, reg_code); - } else { - result = push_str8f(arena, "??? (%llu)", reg_code); - } - return result; -} - -//////////////////////////////// -//~ rjf: RADDBG Compound Stringize Functions - -global char rdi_stringize_spaces[] = " "; - -internal void -rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *rdi, U32 indent_level) -{ - for(U64 idx = 0; idx < rdi->sections_count; idx += 1) - { - RDI_SectionKind kind = (RDI_SectionKind)idx; - RDI_Section *section = &rdi->sections[idx]; - String8 kind_str = rdi_string_from_data_section_kind(kind); - str8_list_pushf(arena, out, "%.*sdata_section[%5I64u] = {0x%08llx, %7u, %7u} %S\n", - indent_level, rdi_stringize_spaces, - idx, section->off, section->encoded_size, section->unpacked_size, kind_str); - } -} - -internal void -rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TopLevelInfo *tli, U32 indent_level) -{ - String8 arch_str = rdi_string_from_arch(tli->arch); - String8 exe_name = {0}; - exe_name.str = rdi_string_from_idx(rdi, tli->exe_name_string_idx, &exe_name.size); - String8 producer_name = {0}; - producer_name.str = rdi_string_from_idx(rdi, tli->producer_name_string_idx, &producer_name.size); - str8_list_pushf(arena, out, "%.*sarch=%S\n", indent_level, rdi_stringize_spaces, arch_str); - str8_list_pushf(arena, out, "%.*sexe_name='%S'\n", indent_level, rdi_stringize_spaces, exe_name); - str8_list_pushf(arena, out, "%.*svoff_max=0x%08llx\n", indent_level, rdi_stringize_spaces, tli->voff_max); - str8_list_pushf(arena, out, "%.*sproducer_name='%S'\n", indent_level, rdi_stringize_spaces, producer_name); -} - -internal void -rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_BinarySection *bin_section, U32 indent_level) -{ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, bin_section->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sname='%.*s'\n", indent_level, rdi_stringize_spaces, str8_varg(name)); - - str8_list_pushf(arena, out, "%.*sflags=", indent_level, rdi_stringize_spaces); - rdi_stringize_binary_section_flags(arena, out, bin_section->flags); - str8_list_pushf(arena, out, "\n"); - - str8_list_pushf(arena, out, "%.*svoff_first=0x%08x\n", indent_level, rdi_stringize_spaces, bin_section->voff_first); - str8_list_pushf(arena, out, "%.*svoff_opl =0x%08x\n", indent_level, rdi_stringize_spaces, bin_section->voff_opl); - str8_list_pushf(arena, out, "%.*sfoff_first=0x%08x\n", indent_level, rdi_stringize_spaces, bin_section->foff_first); - str8_list_pushf(arena, out, "%.*sfoff_opl =0x%08x\n", indent_level, rdi_stringize_spaces, bin_section->foff_opl); -} - -internal void -rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, U32 indent_level) -{ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, file_path->name_string_idx, &name.size); - U32 this_idx = (U32)(file_path - bundle->file_paths); - if(file_path->source_file_idx == 0) - { - str8_list_pushf(arena, out, "%.*s[%u] '%.*s'\n", - indent_level, rdi_stringize_spaces, - this_idx, str8_varg(name)); - } - else - { - str8_list_pushf(arena, out, "%.*s[%u] '%.*s'; source_file=%u\n", - indent_level, rdi_stringize_spaces, - this_idx, str8_varg(name), file_path->source_file_idx); - } - - for(U32 child = file_path->first_child; child != 0;) - { - // get node for child - RDI_FilePathNode *child_node = 0; - if (child < bundle->file_path_count){ - child_node = bundle->file_paths + child; - } - if (child_node == 0){ - break; - } - - // stringize child - rdi_stringize_file_path(arena, out, rdi, bundle, child_node, indent_level + 1); - - // increment iterator - child = child_node->next_sibling; - } -} - -internal void -rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceFile *source_file, U32 indent_level) -{ - // file path node idx - str8_list_pushf(arena, out, "%.*sfile_path_node_idx: %u\n", indent_level, rdi_stringize_spaces, source_file->file_path_node_idx); - - // normal source path - String8 path = {0}; - path.str = rdi_string_from_idx(rdi, source_file->normal_full_path_string_idx, &path.size); - str8_list_pushf(arena, out, "%.*spath: \"%S\"\n", indent_level, rdi_stringize_spaces, path); - - // rjf: source line map idx - str8_list_pushf(arena, out, "%.*ssource_line_map: %u\n", indent_level, rdi_stringize_spaces, source_file->source_line_map_idx); -} - -internal void -rdi_stringize_line_table(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_LineTable *line_table, U32 indent_level) -{ - // rjf: parse line table - RDI_ParsedLineTable parsed_line_table = {0}; - rdi_parsed_from_line_table(rdi, line_table, &parsed_line_table); - - // rjf: stringize lines - str8_list_pushf(arena, out, "%.*slines:\n", indent_level, rdi_stringize_spaces); - for(U32 i = 0; i < parsed_line_table.count; i += 1) - { - U64 first = parsed_line_table.voffs[i]; - U64 opl = parsed_line_table.voffs[i + 1]; - RDI_Line *line = parsed_line_table.lines + i; - RDI_Column *col = 0; - if(i < parsed_line_table.col_count) - { - col = parsed_line_table.cols + i; - } - if(col == 0) - { - str8_list_pushf(arena, out, "%.*s [0x%08llx,0x%08llx) file=%u; line=%u\n", - indent_level, rdi_stringize_spaces, - first, opl, line->file_idx, line->line_num); - } - else - { - str8_list_pushf(arena, out, "%.*s [0x%08llx,0x%08llx) file=%u; line=%u; columns=[%u,%u)\n", - indent_level, rdi_stringize_spaces, - first, opl, line->file_idx, line->line_num, - col->col_first, col->col_opl); - } - } -} - -internal void -rdi_stringize_source_line_map(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceLineMap *map, U32 indent_level) -{ - RDI_ParsedSourceLineMap line_map = {0}; - rdi_parsed_from_source_line_map(rdi, map, &line_map); - str8_list_pushf(arena, out, "%.*slines:\n", indent_level, rdi_stringize_spaces); - - for(U32 i = 0; i < line_map.count; i += 1) - { - U32 line_num = line_map.nums[i]; - U32 digit_count = 1; - if(line_num > 0) - { - U32 x = line_num; - for(;;) - { - x /= 10; - if(x == 0) - { - break; - } - digit_count += 1; - } - } - - str8_list_pushf(arena, out, "%.*s %u: ", indent_level, rdi_stringize_spaces, line_num); - - U32 first = line_map.ranges[i]; - U32 opl_raw = line_map.ranges[i + 1]; - U32 opl = ClampTop(opl_raw, line_map.voff_count); - for(U32 j = first; j < opl; j += 1) - { - if(j == first) - { - str8_list_pushf(arena, out, "0x%08x\n", line_map.voffs[j]); - } - else - { - str8_list_pushf(arena, out, "%.*s0x%08x\n", - indent_level + digit_count + 3, rdi_stringize_spaces, - line_map.voffs[j]); - } - } - } -} - -internal void -rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Unit *unit, U32 indent_level) -{ - String8 unit_name = {0}; - unit_name.str = rdi_string_from_idx(rdi, unit->unit_name_string_idx, &unit_name.size); - String8 compiler_name = {0}; - compiler_name.str = rdi_string_from_idx(rdi, unit->compiler_name_string_idx, &compiler_name.size); - - str8_list_pushf(arena, out, "%.*sunit_name='%.*s'\n", indent_level, rdi_stringize_spaces, str8_varg(unit_name)); - str8_list_pushf(arena, out, "%.*scompiler_name='%.*s'\n", indent_level, rdi_stringize_spaces, str8_varg(compiler_name)); - - str8_list_pushf(arena, out, "%.*ssource_file_path=%u\n", indent_level, rdi_stringize_spaces, unit->source_file_path_node); - str8_list_pushf(arena, out, "%.*sobject_file_path=%u\n", indent_level, rdi_stringize_spaces, unit->object_file_path_node); - str8_list_pushf(arena, out, "%.*sarchive_file_path=%u\n", indent_level, rdi_stringize_spaces, unit->archive_file_path_node); - str8_list_pushf(arena, out, "%.*sbuild_path=%u\n", indent_level, rdi_stringize_spaces, unit->build_path_node); - - String8 language_str = rdi_string_from_language(unit->language); - str8_list_pushf(arena, out, "%.*slanguage=%.*s\n", indent_level, rdi_stringize_spaces, str8_varg(language_str)); - - str8_list_pushf(arena, out, "%.*sline_table_idx=%u\n", indent_level, rdi_stringize_spaces, unit->line_table_idx); -} - -internal void -rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *rdi, - RDI_TypeNode *type, U32 indent_level){ - RDI_TypeKind kind = type->kind; - String8 type_kind_str = rdi_string_from_type_kind(kind); - - str8_list_pushf(arena, out, "%.*skind=%.*s\n", - indent_level, rdi_stringize_spaces, str8_varg(type_kind_str)); - - switch (type->kind){ - case RDI_TypeKind_Modifier: - { - str8_list_pushf(arena, out, "%.*sflags=", indent_level, rdi_stringize_spaces); - rdi_stringize_type_modifier_flags(arena, out, type->flags); - str8_list_push(arena, out, str8_lit("\n")); - }break; - - default: - { - if (type->flags != 0){ - str8_list_pushf(arena, out, "%.*sflags=%x (missing stringizer path)", - indent_level, rdi_stringize_spaces, type->flags); - } - }break; - } - - str8_list_pushf(arena, out, "%.*sbyte_size=%u\n", - indent_level, rdi_stringize_spaces, type->byte_size); - - if (RDI_TypeKind_FirstBuiltIn <= kind && - kind <= RDI_TypeKind_LastBuiltIn){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, type->built_in.name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sbuilt_in.name='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - } - - else if (RDI_TypeKind_FirstConstructed <= kind && - kind <= RDI_TypeKind_LastConstructed){ - str8_list_pushf(arena, out, "%.*sconstructed.direct_type=%u\n", - indent_level, rdi_stringize_spaces, type->constructed.direct_type_idx); - - if (type->kind == RDI_TypeKind_Array){ - str8_list_pushf(arena, out, "%.*sconstructed.array_count=%u\n", - indent_level, rdi_stringize_spaces, type->constructed.count); - } - - if (type->kind == RDI_TypeKind_Function || - type->kind == RDI_TypeKind_Method){ - U32 run_first = type->constructed.param_idx_run_first; - U32 run_count_raw = type->constructed.count; - - U32 run_count = 0; - U32 *run = rdi_idx_run_from_first_count(rdi, run_first, run_count_raw, &run_count); - - U32 this_type_idx = 0; - if (run_count > 0 && type->kind == RDI_TypeKind_Method){ - this_type_idx = run[0]; - run += 1; - run_count -= 1; - } - - if (this_type_idx != 0){ - str8_list_pushf(arena, out, "%.*sconstructed.this_type=%u\n", - indent_level, rdi_stringize_spaces, this_type_idx); - } - - str8_list_pushf(arena, out, "%.*sconstructed.params={", - indent_level, rdi_stringize_spaces); - - if (run_count > 0){ - U32 last = run_count - 1; - for (U32 j = 0; j < last; j += 1){ - str8_list_pushf(arena, out, " %u,", run[j]); - } - str8_list_pushf(arena, out, " %u ", run[last]); - } - - str8_list_push(arena, out, str8_lit("}\n")); - } - } - - else if (RDI_TypeKind_FirstUserDefined <= kind && - kind <= RDI_TypeKind_LastUserDefined){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, type->user_defined.name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*suser_defined.name='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - str8_list_pushf(arena, out, "%.*suser_defined.direct_type=%u\n", - indent_level, rdi_stringize_spaces, - type->user_defined.direct_type_idx); - str8_list_pushf(arena, out, "%.*suser_defined.udt=%u\n", - indent_level, rdi_stringize_spaces, - type->user_defined.udt_idx); - } - - else if (kind == RDI_TypeKind_Bitfield){ - str8_list_pushf(arena, out, "%.*sbitfield.off=%u\n", - indent_level, rdi_stringize_spaces, type->bitfield.off); - str8_list_pushf(arena, out, "%.*sbitfield.size=%u\n", - indent_level, rdi_stringize_spaces, type->bitfield.size); - } -} - -internal void -rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *rdi, - RDI_UDTMemberBundle *member_bundle, RDI_UDT *udt, - U32 indent_level){ - str8_list_pushf(arena, out, "%.*sself_type=%u\n", - indent_level, rdi_stringize_spaces, udt->self_type_idx); - - str8_list_pushf(arena, out, "%.*sflags=", indent_level, rdi_stringize_spaces); - rdi_stringize_udt_flags(arena, out, udt->flags); - str8_list_push(arena, out, str8_lit("\n")); - - if (udt->file_idx != 0){ - str8_list_pushf(arena, out, "%.*sloc={file=%u; line=%u; col=%u}\n", - indent_level, rdi_stringize_spaces, - udt->file_idx, udt->line, udt->col); - } - - // enum members - if (udt->flags & RDI_UDTFlag_EnumMembers){ - U32 first_raw = udt->member_first; - U32 opl_raw = first_raw + udt->member_count; - U32 opl = ClampTop(opl_raw, member_bundle->enum_member_count); - U32 first = ClampTop(first_raw, opl); - - if (first < opl){ - str8_list_pushf(arena, out, "%.*smembers={\n", indent_level, rdi_stringize_spaces); - RDI_EnumMember *enum_member = member_bundle->enum_members + first; - for (U32 i = first; i < opl; i += 1, enum_member += 1){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, enum_member->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*s '%.*s' %llu\n", - indent_level, rdi_stringize_spaces, - str8_varg(name), enum_member->val); - } - str8_list_pushf(arena, out, "%.*s}\n", indent_level, rdi_stringize_spaces); - } - } - - // field members - else{ - U32 first_raw = udt->member_first; - U32 opl_raw = first_raw + udt->member_count; - U32 opl = ClampTop(opl_raw, member_bundle->member_count); - U32 first = ClampTop(first_raw, opl); - - if (first < opl){ - str8_list_pushf(arena, out, "%.*smembers={\n", indent_level, rdi_stringize_spaces); - RDI_Member *member = member_bundle->members + first; - for (U32 i = first; i < opl; i += 1, member += 1){ - str8_list_pushf(arena, out, "%.*s {\n", indent_level, rdi_stringize_spaces); - - String8 kind_str = rdi_string_from_member_kind(member->kind); - str8_list_pushf(arena, out, "%.*s kind=%.*s\n", - indent_level, rdi_stringize_spaces, str8_varg(kind_str)); - - if (member->name_string_idx != 0){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, member->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*s name='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - } - - str8_list_pushf(arena, out, "%.*s type=%u\n", - indent_level, rdi_stringize_spaces, member->type_idx); - str8_list_pushf(arena, out, "%.*s off=%u\n", - indent_level, rdi_stringize_spaces, member->off); - - str8_list_pushf(arena, out, "%.*s }\n", indent_level, rdi_stringize_spaces); - } - str8_list_pushf(arena, out, "%.*s}\n", indent_level, rdi_stringize_spaces); - } - } -} - -internal void -rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, - RDI_GlobalVariable *global_variable, U32 indent_level){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, global_variable->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, rdi_stringize_spaces); - rdi_stringize_link_flags(arena, out, global_variable->link_flags); - str8_list_push(arena, out, str8_lit("\n")); - - str8_list_pushf(arena, out, "%.*svoff=0x%08llx\n", - indent_level, rdi_stringize_spaces, global_variable->voff); - - str8_list_pushf(arena, out, "%.*stype_idx=%u\n", - indent_level, rdi_stringize_spaces, global_variable->type_idx); - - str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, rdi_stringize_spaces, global_variable->container_idx); -} - -internal void -rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, - RDI_ThreadVariable *thread_var, - U32 indent_level){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, thread_var->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, rdi_stringize_spaces); - rdi_stringize_link_flags(arena, out, thread_var->link_flags); - str8_list_push(arena, out, str8_lit("\n")); - - str8_list_pushf(arena, out, "%.*stls_off=0x%08x\n", - indent_level, rdi_stringize_spaces, thread_var->tls_off); - - str8_list_pushf(arena, out, "%.*stype_idx=%u\n", - indent_level, rdi_stringize_spaces, thread_var->type_idx); - - str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, rdi_stringize_spaces, thread_var->container_idx); -} - -internal void -rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *rdi, - RDI_Procedure *proc, U32 indent_level){ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, proc->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - - String8 link_name = {0}; - link_name.str = rdi_string_from_idx(rdi, proc->link_name_string_idx, &link_name.size); - str8_list_pushf(arena, out, "%.*slink_name='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(link_name)); - - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, rdi_stringize_spaces); - rdi_stringize_link_flags(arena, out, proc->link_flags); - str8_list_push(arena, out, str8_lit("\n")); - - str8_list_pushf(arena, out, "%.*stype_idx=%u\n", - indent_level, rdi_stringize_spaces, proc->type_idx); - - str8_list_pushf(arena, out, "%.*sroot_scope_idx=%u\n", - indent_level, rdi_stringize_spaces, proc->root_scope_idx); - - str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, rdi_stringize_spaces, proc->container_idx); -} - -internal void -rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Arch arch, - RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level) -{ - Temp scratch = scratch_begin(&arena, 1); - - U32 this_idx = (U32)(scope - bundle->scopes); - - str8_list_pushf(arena, out, "%.*s[%u]\n", - indent_level, rdi_stringize_spaces, this_idx); - - str8_list_pushf(arena, out, "%.*s proc_idx=%u\n", - indent_level, rdi_stringize_spaces, scope->proc_idx); - - if(scope->inline_site_idx != 0) - { - str8_list_pushf(arena, out, "%.*s inline_site_idx=%u\n", - indent_level, rdi_stringize_spaces, scope->inline_site_idx); - } - - // voff ranges - { - U32 voff_range_first_raw = scope->voff_range_first; - U32 voff_range_opl_raw = scope->voff_range_opl; - U32 voff_range_opl_clamped = ClampTop(voff_range_opl_raw, bundle->scope_voff_count); - U32 voff_range_first = ClampTop(voff_range_first_raw, voff_range_opl_clamped); - U32 voff_range_opl = voff_range_opl_clamped; - if ((voff_range_opl - voff_range_first) % 2 == 1){ - voff_range_opl -= 1; - } - - U64 *voff_ptr = bundle->scope_voffs + voff_range_first; - - if (voff_range_opl - voff_range_first > 2){ - str8_list_pushf(arena, out, "%.*s voff_ranges={\n", - indent_level, rdi_stringize_spaces); - for (U32 i = voff_range_first; i < voff_range_opl; i += 2, voff_ptr += 2){ - str8_list_pushf(arena, out, "%.*s [0x%08llx, 0x%08llx)\n", - indent_level, rdi_stringize_spaces, - voff_ptr[0], voff_ptr[1]); - } - str8_list_pushf(arena, out, "%.*s }\n", - indent_level, rdi_stringize_spaces); - } - else if (voff_range_opl - voff_range_first == 2){ - str8_list_pushf(arena, out, "%.*s voff_range=[0x%08llx, 0x%08llx)\n", - indent_level, rdi_stringize_spaces, - voff_ptr[0], voff_ptr[1]); - } - } - - // locals - { - U32 local_first = scope->local_first; - U32 local_opl_raw = local_first + scope->local_count; - U32 local_opl = ClampTop(local_opl_raw, bundle->local_count); - - if (local_first < local_opl){ - RDI_Local *local_ptr = bundle->locals + local_first; - for (U32 i = local_first; i < local_opl; i += 1, local_ptr += 1){ - str8_list_pushf(arena, out, "%.*s local[%u]\n", - indent_level, rdi_stringize_spaces, i); - - String8 local_kind_str = rdi_string_from_local_kind(local_ptr->kind); - str8_list_pushf(arena, out, "%.*s kind=%.*s\n", - indent_level, rdi_stringize_spaces, str8_varg(local_kind_str)); - - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, local_ptr->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*s name='%.*s'\n", - indent_level, rdi_stringize_spaces, str8_varg(name)); - - str8_list_pushf(arena, out, "%.*s type_idx=%u\n", - indent_level, rdi_stringize_spaces, local_ptr->type_idx); - - U32 location_first = local_ptr->location_first; - U32 location_opl_raw = local_ptr->location_opl; - U32 location_opl = ClampTop(location_opl_raw, bundle->location_block_count); - - if (location_first < location_opl){ - str8_list_pushf(arena, out, "%.*s locations:\n", indent_level, rdi_stringize_spaces); - RDI_LocationBlock *block_ptr = bundle->location_blocks + location_first; - for (U32 j = location_first; j < location_opl; j += 1, block_ptr += 1){ - if (block_ptr->scope_off_first == 0 && block_ptr->scope_off_opl == max_U32){ - str8_list_pushf(arena, out, "%.*s case *always*:\n", indent_level, rdi_stringize_spaces); - } - else{ - str8_list_pushf(arena, out, "%.*s case [0x%08x, 0x%08x):\n", - indent_level, rdi_stringize_spaces, - block_ptr->scope_off_first, block_ptr->scope_off_opl); - } - - if (block_ptr->location_data_off >= bundle->location_data_size){ - str8_list_pushf(arena, out, "%.*s \n", - indent_level, rdi_stringize_spaces); - } - else{ - str8_list_pushf(arena, out, "%.*s ", indent_level, rdi_stringize_spaces); - - U8 *loc_data_opl = bundle->location_data + bundle->location_data_size; - U8 *loc_base_ptr = bundle->location_data + block_ptr->location_data_off; - RDI_LocationKind kind = (RDI_LocationKind)*loc_base_ptr; - switch (kind){ - default: - { - str8_list_pushf(arena, out, "\n"); - }break; - - case RDI_LocationKind_AddrBytecodeStream: - { - str8_list_pushf(arena, out, "AddrBytecodeStream\n"); - str8_list_pushf(arena, out, "%.*s ", indent_level, rdi_stringize_spaces); - U8 *bytecode_ptr = loc_base_ptr + 1; - for (;bytecode_ptr < loc_data_opl && *bytecode_ptr != 0; bytecode_ptr += 1){ - str8_list_pushf(arena, out, "%02x ", *bytecode_ptr); - } - str8_list_pushf(arena, out, "\n"); - }break; - - case RDI_LocationKind_ValBytecodeStream: - { - str8_list_pushf(arena, out, "ValBytecodeStream\n"); - str8_list_pushf(arena, out, "%.*s ", indent_level, rdi_stringize_spaces); - U8 *bytecode_ptr = loc_base_ptr + 1; - for (;bytecode_ptr < loc_data_opl && *bytecode_ptr != 0; bytecode_ptr += 1){ - str8_list_pushf(arena, out, "%02x ", *bytecode_ptr); - } - str8_list_pushf(arena, out, "\n"); - }break; - - case RDI_LocationKind_AddrRegPlusU16: - { - if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ - str8_list_pushf(arena, out, "AddrRegPlusU16( )\n"); - } - else{ - RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; - str8_list_pushf(arena, out, "AddrRegPlusU16(reg: %S, off: %u)\n", - rdi_format_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); - } - }break; - - case RDI_LocationKind_AddrAddrRegPlusU16: - { - if (loc_base_ptr + sizeof(RDI_LocationRegPlusU16) > loc_data_opl){ - str8_list_pushf(arena, out, "AddrAddrRegPlusU16( )\n"); - } - else{ - RDI_LocationRegPlusU16 *loc = (RDI_LocationRegPlusU16*)loc_base_ptr; - str8_list_pushf(arena, out, "AddrAddrRegisterPlusU16(reg: %S, off: %u)\n", - rdi_format_reg_code(scratch.arena, arch, loc->reg_code), loc->offset); - } - }break; - - case RDI_LocationKind_ValReg: - { - if (loc_base_ptr + sizeof(RDI_LocationReg) > loc_data_opl){ - str8_list_pushf(arena, out, "ValReg( )\n"); - } - else{ - RDI_LocationReg *loc = (RDI_LocationReg*)loc_base_ptr; - str8_list_pushf(arena, out, "ValReg(reg: %S)\n", rdi_format_reg_code(scratch.arena, arch, loc->reg_code)); - } - }break; - } - } - } - } - } - } - } - - // TODO(allen): static locals - - for (U32 child = scope->first_child_scope_idx; - child != 0;){ - // get scope for child - RDI_Scope *child_scope = 0; - if (child < bundle->scope_count){ - child_scope = bundle->scopes + child; - } - if (child_scope == 0){ - break; - } - - // stringize child - rdi_stringize_scope(arena, out, rdi, arch, bundle, child_scope, indent_level + 1); - - // increment iterator - child = child_scope->next_sibling_scope_idx; - } - - str8_list_pushf(arena, out, "%.*s[/%u]\n", - indent_level, rdi_stringize_spaces, this_idx); - - scratch_end(scratch); -} - -internal void -rdi_stringize_inline_site(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_InlineSite *inline_site, U32 indent_level) -{ - String8 name = {0}; - name.str = rdi_string_from_idx(rdi, inline_site->name_string_idx, &name.size); - str8_list_pushf(arena, out, "%.*sname='%S'\n", indent_level, rdi_stringize_spaces, name); - str8_list_pushf(arena, out, "%.*stype_idx=%u\n", indent_level, rdi_stringize_spaces, inline_site->type_idx); - str8_list_pushf(arena, out, "%.*sowner_type_idx=%u\n", indent_level, rdi_stringize_spaces, inline_site->owner_type_idx); - str8_list_pushf(arena, out, "%.*sline_table_idx=%u\n", indent_level, rdi_stringize_spaces, inline_site->line_table_idx); -} diff --git a/src/rdi_dump/rdi_dump.h b/src/rdi_dump/rdi_dump.h deleted file mode 100644 index 1c99092c..00000000 --- a/src/rdi_dump/rdi_dump.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_DUMP_H -#define RDI_DUMP_H - -//////////////////////////////// -//~ rjf: RADDBG Stringize Helper Types - -typedef struct RDI_FilePathBundle RDI_FilePathBundle; -struct RDI_FilePathBundle -{ - RDI_FilePathNode *file_paths; - U64 file_path_count; -}; - -typedef struct RDI_UDTMemberBundle RDI_UDTMemberBundle; -struct RDI_UDTMemberBundle -{ - RDI_Member *members; - RDI_EnumMember *enum_members; - U32 member_count; - U32 enum_member_count; -}; - -typedef struct RDI_ScopeBundle RDI_ScopeBundle; -struct RDI_ScopeBundle -{ - RDI_Scope *scopes; - U64 *scope_voffs; - RDI_Local *locals; - RDI_LocationBlock *location_blocks; - U8 *location_data; - U32 scope_count; - U32 scope_voff_count; - U32 local_count; - U32 location_block_count; - U32 location_data_size; -}; - -//////////////////////////////// -//~ rjf: RDI Enum -> String Functions - -internal String8 rdi_string_from_reg_code_x86(U64 reg_code); -internal String8 rdi_string_from_reg_code_x64(U64 reg_code); -internal String8 rdi_string_from_reg_code(RDI_Arch arch, U64 reg_code); -internal String8 rdi_string_from_data_section_kind(RDI_SectionKind v); -internal String8 rdi_string_from_arch(RDI_Arch v); -internal String8 rdi_string_from_language(RDI_Language v); -internal String8 rdi_string_from_type_kind(RDI_TypeKind v); -internal String8 rdi_string_from_member_kind(RDI_MemberKind v); -internal String8 rdi_string_from_local_kind(RDI_LocalKind v); - -//////////////////////////////// -//~ rjf: RDI Flags -> String Functions - -internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags); -internal void rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, RDI_TypeModifierFlags flags); -internal void rdi_stringize_udt_flags(Arena *arena, String8List *out, RDI_UDTFlags flags); -internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags); - -//////////////////////////////// - -internal String8 rdi_format_reg_code(Arena *arena, RDI_Arch arch, U64 reg_code); - -//////////////////////////////// -//~ rjf: RDI Compound Stringize Functions - -internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *rdi, U32 indent_level); -internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TopLevelInfo *tli, U32 indent_level); -internal void rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_BinarySection *bin_section, U32 indent_level); -internal void rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, U32 indent_level); -internal void rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceFile *source_file, U32 indent_level); -internal void rdi_stringize_line_table(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_LineTable *line_table, U32 indent_level); -internal void rdi_stringize_source_line_map(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_SourceLineMap *map, U32 indent_level); -internal void rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Unit *unit, U32 indent_level); -internal void rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_TypeNode *type, U32 indent_level); -internal void rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_UDTMemberBundle *bundle, RDI_UDT *udt, U32 indent_level); -internal void rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_GlobalVariable *global_variable, U32 indent_level); -internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_ThreadVariable *thread_var, U32 indent_level); -internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Procedure *proc, U32 indent_level); -internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_Arch arch, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level); -internal void rdi_stringize_inline_site(Arena *arena, String8List *out, RDI_Parsed *rdi, RDI_InlineSite *inline_site, U32 indent_level); - -#endif // RDI_DUMP_H diff --git a/src/rdi_dump/rdi_dump_main.c b/src/rdi_dump/rdi_dump_main.c deleted file mode 100644 index 34ebf27a..00000000 --- a/src/rdi_dump/rdi_dump_main.c +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Build Options - -#define BUILD_TITLE "rdi_dump" -#define BUILD_CONSOLE_INTERFACE 1 - -//////////////////////////////// -//~ rjf: Includes - -//- rjf: [lib] -#include "third_party/rad_lzb_simple/rad_lzb_simple.h" -#include "third_party/rad_lzb_simple/rad_lzb_simple.c" - -//- rjf: [h] -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "rdi_format/rdi_format_local.h" -#include "rdi_dump.h" - -//- rjf: [c] -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "rdi_format/rdi_format_local.c" -#include "rdi_dump.c" - -//////////////////////////////// -//~ rjf: Entry Point - -internal void -entry_point(CmdLine *cmd_line) -{ - ////////////////////////////// - //- rjf: set up - // - Arena *arena = arena_alloc(); - String8List errors = {0}; - - ////////////////////////////// - //- rjf: extract command line parameters - // - typedef U32 DumpFlags; - enum - { - DumpFlag_DataSections = (1<<0), - DumpFlag_TopLevelInfo = (1<<1), - DumpFlag_BinarySections = (1<<2), - DumpFlag_FilePaths = (1<<3), - DumpFlag_SourceFiles = (1<<4), - DumpFlag_LineTables = (1<<5), - DumpFlag_SourceLineMaps = (1<<6), - DumpFlag_Units = (1<<7), - DumpFlag_UnitVMap = (1<<8), - DumpFlag_TypeNodes = (1<<9), - DumpFlag_UDTs = (1<<10), - DumpFlag_GlobalVariables = (1<<11), - DumpFlag_GlobalVMap = (1<<12), - DumpFlag_ThreadVariables = (1<<13), - DumpFlag_Procedures = (1<<14), - DumpFlag_Scopes = (1<<15), - DumpFlag_ScopeVMap = (1<<16), - DumpFlag_InlineSites = (1<<17), - DumpFlag_NameMaps = (1<<18), - DumpFlag_Strings = (1<<19), - }; - String8 input_name = {0}; - DumpFlags dump_flags = (U32)0xffffffff; - { - // rjf: extract input file path - input_name = str8_list_first(&cmd_line->inputs); - - // rjf: extract "only" options - { - String8List dump_options = cmd_line_strings(cmd_line, str8_lit("only")); - if(dump_options.first != 0) - { - dump_flags = 0; - for(String8Node *n = dump_options.first; n != 0; n = n->next) - { - if(0){} - else if(str8_match(n->string, str8_lit("data_sections"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_DataSections; } - else if(str8_match(n->string, str8_lit("top_level_info"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_TopLevelInfo; } - else if(str8_match(n->string, str8_lit("binary_sections"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_BinarySections; } - else if(str8_match(n->string, str8_lit("file_paths"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_FilePaths; } - else if(str8_match(n->string, str8_lit("source_files"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_SourceFiles; } - else if(str8_match(n->string, str8_lit("line_tables"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_LineTables; } - else if(str8_match(n->string, str8_lit("source_line_maps"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_SourceLineMaps; } - else if(str8_match(n->string, str8_lit("units"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_Units; } - else if(str8_match(n->string, str8_lit("unit_vmap"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_UnitVMap; } - else if(str8_match(n->string, str8_lit("type_nodes"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_TypeNodes; } - else if(str8_match(n->string, str8_lit("udt_data"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_UDTs; } - else if(str8_match(n->string, str8_lit("global_variables"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_GlobalVariables; } - else if(str8_match(n->string, str8_lit("global_vmap"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_GlobalVMap; } - else if(str8_match(n->string, str8_lit("thread_variables"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_ThreadVariables; } - else if(str8_match(n->string, str8_lit("procedures"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_Procedures; } - else if(str8_match(n->string, str8_lit("scopes"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_Scopes; } - else if(str8_match(n->string, str8_lit("scope_vmap"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_ScopeVMap; } - else if(str8_match(n->string, str8_lit("inline_sites"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_InlineSites; } - else if(str8_match(n->string, str8_lit("name_maps"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_NameMaps; } - else if(str8_match(n->string, str8_lit("strings"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_Strings; } - } - } - } - } - - ////////////////////////////// - //- rjf: load file - // - String8 input_data = os_data_from_file_path(arena, input_name); - if(input_name.size == 0) - { - str8_list_pushf(arena, &errors, "error (input): No input RDI file specified."); - } - else if(input_data.size == 0) - { - str8_list_pushf(arena, &errors, "error (input): No input RDI file successfully loaded; either the path or file contents are invalid."); - } - - ////////////////////////////// - //- rjf: obtain initial rdi parse - // - RDI_Parsed rdi_ = {0}; - RDI_Parsed *rdi = &rdi_; - RDI_ParseStatus status = rdi_parse(input_data.str, input_data.size, rdi); - - ////////////////////////////// - //- rjf: decompress rdi if necessary - // - { - U64 decompressed_size = rdi_decompressed_size_from_parsed(rdi); - if(decompressed_size > input_data.size) - { - U8 *decompressed_data = push_array_no_zero(arena, U8, decompressed_size); - rdi_decompress_parsed(decompressed_data, decompressed_size, rdi); - status = rdi_parse(decompressed_data, decompressed_size, rdi); - } - } - - ////////////////////////////// - //- rjf: error on bad parse status - // - if(status != RDI_ParseStatus_Good) - { - str8_list_pushf(arena, &errors, "error (input): RDI file could not be successfully decoded."); - } - - ////////////////////////////// - //- rjf: output error strings to stderr - // - for(String8Node *n = errors.first; n != 0; n = n->next) - { - fwrite(n->string.str, 1, n->string.size, stderr); - fprintf(stderr, "\n"); - } - - ////////////////////////////// - //- rjf: build dump strings - // - String8List dump = {0}; - if(errors.node_count == 0) - { - //- rjf: DATA SECTIONS - if(dump_flags & DumpFlag_DataSections) - { - str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); - rdi_stringize_data_sections(arena, &dump, rdi, 1); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: TOP LEVEL INFO - RDI_TopLevelInfo *tli = rdi_element_from_name_idx(rdi, TopLevelInfo, 0); - if(dump_flags & DumpFlag_TopLevelInfo) - { - str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); - rdi_stringize_top_level_info(arena, &dump, rdi, tli, 1); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: BINARY SECTIONS - if(dump_flags & DumpFlag_BinarySections) - { - str8_list_pushf(arena, &dump, "# BINARY SECTIONS:\n"); - U64 count = 0; - RDI_BinarySection *v = rdi_table_from_name(rdi, BinarySections, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " section[%I64u]:\n", idx); - rdi_stringize_binary_section(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: FILE PATHS - if(dump_flags & DumpFlag_FilePaths) - { - RDI_FilePathBundle file_path_bundle = {0}; - file_path_bundle.file_paths = rdi_table_from_name(rdi, FilePathNodes, &file_path_bundle.file_path_count); - str8_list_pushf(arena, &dump, "# FILE PATHS\n"); - RDI_FilePathNode *ptr = file_path_bundle.file_paths; - for(U32 i = 0; i < file_path_bundle.file_path_count; i += 1, ptr += 1) - { - if(ptr->parent_path_node == 0) - { - rdi_stringize_file_path(arena, &dump, rdi, &file_path_bundle, ptr, 1); - } - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: SOURCE FILES - if(dump_flags & DumpFlag_SourceFiles) - { - str8_list_pushf(arena, &dump, "# SOURCE FILES\n"); - U64 count = 0; - RDI_SourceFile *v = rdi_table_from_name(rdi, SourceFiles, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " source_file[%I64u]:\n", idx); - rdi_stringize_source_file(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: LINE TABLES - if(dump_flags & DumpFlag_LineTables) - { - str8_list_pushf(arena, &dump, "# LINE TABLES\n"); - U64 count = 0; - RDI_LineTable *v = rdi_table_from_name(rdi, LineTables, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " line_table[%I64u]:\n", idx); - rdi_stringize_line_table(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: SOURCE LINE MAPS - if(dump_flags & DumpFlag_SourceLineMaps) - { - str8_list_pushf(arena, &dump, "# SOURCE LINE MAPS\n"); - U64 count = 0; - RDI_SourceLineMap *v = rdi_table_from_name(rdi, SourceLineMaps, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " source_line_map[%I64u]:\n", idx); - rdi_stringize_source_line_map(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: UNITS - if(dump_flags & DumpFlag_Units) - { - str8_list_pushf(arena, &dump, "# UNITS\n"); - U64 count = 0; - RDI_Unit *v = rdi_table_from_name(rdi, Units, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " unit[%I64u]:\n", idx); - rdi_stringize_unit(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: UNIT VMAP - if(dump_flags & DumpFlag_UnitVMap) - { - str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); - U64 count = 0; - RDI_VMapEntry *v = rdi_table_from_name(rdi, UnitVMap, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", v[idx].voff, v[idx].idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: TYPE NODES - if(dump_flags & DumpFlag_TypeNodes) - { - str8_list_pushf(arena, &dump, "# TYPE NODES:\n"); - U64 count = 0; - RDI_TypeNode *v = rdi_table_from_name(rdi, TypeNodes, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " type[%I64u]:\n", idx); - rdi_stringize_type_node(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: UDT DATA - if(dump_flags & DumpFlag_UDTs) - { - U64 all_members_count = 0; - RDI_Member *all_members = rdi_table_from_name(rdi, Members, &all_members_count); - U64 all_enum_members_count = 0; - RDI_EnumMember *all_enum_members = rdi_table_from_name(rdi, EnumMembers, &all_enum_members_count); - U64 all_udts_count = 0; - RDI_UDT *all_udts = rdi_table_from_name(rdi, UDTs, &all_udts_count); - RDI_UDTMemberBundle member_bundle = {0}; - { - member_bundle.members = all_members; - member_bundle.enum_members = all_enum_members; - member_bundle.member_count = (RDI_U32)all_members_count; - member_bundle.enum_member_count = (RDI_U32)all_enum_members_count; - } - str8_list_pushf(arena, &dump, "# UDTS:\n"); - for(U64 idx = 0; idx < all_udts_count; idx += 1) - { - str8_list_pushf(arena, &dump, " udt[%I64u]:\n", idx); - rdi_stringize_udt(arena, &dump, rdi, &member_bundle, &all_udts[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: GLOBAL VARIABLES - if(dump_flags & DumpFlag_GlobalVariables) - { - str8_list_pushf(arena, &dump, "# GLOBAL VARIABLES:\n"); - RDI_U64 count = 0; - RDI_GlobalVariable *v = rdi_table_from_name(rdi, GlobalVariables, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " global_variable[%I64u]:\n", idx); - rdi_stringize_global_variable(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: GLOBAL VMAP - if(dump_flags & DumpFlag_GlobalVMap) - { - str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); - U64 count = 0; - RDI_VMapEntry *v = rdi_table_from_name(rdi, GlobalVMap, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", v[idx].voff, v[idx].idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: THREAD LOCAL VARIABLES - if(dump_flags & DumpFlag_ThreadVariables) - { - str8_list_pushf(arena, &dump, "# THREAD VARIABLES:\n"); - U64 count = 0; - RDI_ThreadVariable *v = rdi_table_from_name(rdi, ThreadVariables, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " thread_variable[%I64u]:\n", idx); - rdi_stringize_thread_variable(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: PROCEDURES - if(dump_flags & DumpFlag_Procedures) - { - str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); - U64 count = 0; - RDI_Procedure *v = rdi_table_from_name(rdi, Procedures, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " procedure[%I64u]:\n", idx); - rdi_stringize_procedure(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: SCOPES - if(dump_flags & DumpFlag_Scopes) - { - U64 scopes_count = 0; - RDI_Scope *scopes = rdi_table_from_name(rdi, Scopes, &scopes_count); - U64 scopes_voffs_count = 0; - U64 *scopes_voffs = rdi_table_from_name(rdi, ScopeVOffData, &scopes_voffs_count); - U64 locals_count = 0; - RDI_Local *locals = rdi_table_from_name(rdi, Locals, &locals_count); - U64 location_block_count = 0; - RDI_LocationBlock *location_blocks = rdi_table_from_name(rdi, LocationBlocks, &location_block_count); - U64 location_data_size = 0; - RDI_U8 *location_data = rdi_table_from_name(rdi, LocationData, &location_data_size); - RDI_ScopeBundle scope_bundle = {0}; - { - scope_bundle.scopes = scopes; - scope_bundle.scope_count = scopes_count; - scope_bundle.scope_voffs = scopes_voffs; - scope_bundle.scope_voff_count = scopes_voffs_count; - scope_bundle.locals = locals; - scope_bundle.local_count = locals_count; - scope_bundle.location_blocks = location_blocks; - scope_bundle.location_block_count = location_block_count; - scope_bundle.location_data = location_data; - scope_bundle.location_data_size = location_data_size; - } - str8_list_pushf(arena, &dump, "# SCOPES:\n"); - for(U64 idx = 0; idx < scopes_count; idx += 1) - { - if(scopes[idx].parent_scope_idx == 0) - { - rdi_stringize_scope(arena, &dump, rdi, tli->arch, &scope_bundle, &scopes[idx], 1); - } - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: SCOPE VMAP - if(dump_flags & DumpFlag_ScopeVMap) - { - str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); - U64 count = 0; - RDI_VMapEntry *v = rdi_table_from_name(rdi, ScopeVMap, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", v[idx].voff, v[idx].idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: INLINE SITES - if(dump_flags & DumpFlag_InlineSites) - { - str8_list_pushf(arena, &dump, "# INLINE SITES:\n"); - U64 count = 0; - RDI_InlineSite *v = rdi_table_from_name(rdi, InlineSites, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - str8_list_pushf(arena, &dump, " inline_site[%I64u]:\n", idx); - rdi_stringize_inline_site(arena, &dump, rdi, &v[idx], 2); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: NAME MAPS - if(dump_flags & DumpFlag_NameMaps) - { - str8_list_pushf(arena, &dump, "# NAME MAP:\n"); - U64 count = 0; - RDI_NameMap *v = rdi_table_from_name(rdi, NameMaps, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - RDI_ParsedNameMap name_map = {0}; - rdi_parsed_from_name_map(rdi, &v[idx], &name_map); - str8_list_pushf(arena, &dump, " name_map[%I64u]:\n", idx); - RDI_NameMapBucket *bucket = name_map.buckets; - for(U32 j = 0; j < name_map.bucket_count; j += 1, bucket += 1) - { - if(bucket->node_count > 0) - { - str8_list_pushf(arena, &dump, " bucket[%u]:\n", j); - RDI_NameMapNode *node = name_map.nodes + bucket->first_node; - RDI_NameMapNode *node_opl = node + bucket->node_count; - for(;node < node_opl; node += 1) - { - String8 string = {0}; - string.str = rdi_string_from_idx(rdi, node->string_idx, &string.size); - str8_list_pushf(arena, &dump, " match \"%.*s\": ", str8_varg(string)); - if(node->match_count == 1) - { - str8_list_pushf(arena, &dump, "%u", node->match_idx_or_idx_run_first); - } - else - { - RDI_U32 idx_count = 0; - RDI_U32 *idx_run = - rdi_idx_run_from_first_count(rdi, node->match_idx_or_idx_run_first, - node->match_count, &idx_count); - if(idx_count > 0) - { - RDI_U32 last = idx_count - 1; - for(U32 k = 0; k < last; k += 1) - { - str8_list_pushf(arena, &dump, "%u, ", idx_run[k]); - } - str8_list_pushf(arena, &dump, "%u", idx_run[last]); - } - } - str8_list_pushf(arena, &dump, "\n"); - } - } - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - //- rjf: STRINGS - if(dump_flags & DumpFlag_Strings) - { - str8_list_pushf(arena, &dump, "# STRINGS:\n"); - U64 count = 0; - U32 *v = rdi_table_from_name(rdi, StringTable, &count); - for(U64 idx = 0; idx < count; idx += 1) - { - String8 string = {0}; - string.str = rdi_string_from_idx(rdi, (RDI_U32)idx, &string.size); - str8_list_pushf(arena, &dump, " string[%I64u]: \"%S\"\n", idx, string); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - ////////////////////////////// - //- rjf: write dump to stdout - // - for(String8Node *n = dump.first; n != 0; n = n->next) - { - fwrite(n->string.str, 1, n->string.size, stdout); - } -} diff --git a/src/rdi_format/rdi_format.mdesk b/src/rdi_format/rdi_format.mdesk index 2a515898..aabc166d 100644 --- a/src/rdi_format/rdi_format.mdesk +++ b/src/rdi_format/rdi_format.mdesk @@ -60,9 +60,9 @@ "////////////////////////////////////////////////////////////////"; "//~ Format Constants"; ""; - "// \"raddbg\0\0\""; + "// \"raddbg\\0\\0\""; "#define RDI_MAGIC_CONSTANT 0x0000676264646172"; - "#define RDI_ENCODING_VERSION 10"; + "#define RDI_ENCODING_VERSION 11"; ""; "////////////////////////////////////////////////////////////////"; "//~ Format Types & Functions"; @@ -785,6 +785,7 @@ RDI_TypeModifierFlagTable: { {Const `1<<0`} {Volatile `1<<1`} + {Restrict `1<<2`} } @table(name type_lhs type_rhs desc) @@ -1026,12 +1027,14 @@ RDI_ThreadVariableMemberTable: @table(name type desc) RDI_ProcedureMemberTable: { - {name_string_idx RDI_U32 ""} - {link_name_string_idx RDI_U32 ""} - {link_flags RDI_LinkFlags ""} - {type_idx RDI_U32 ""} - {root_scope_idx RDI_U32 ""} - {container_idx RDI_U32 ""} + {name_string_idx RDI_U32 ""} + {link_name_string_idx RDI_U32 ""} + {link_flags RDI_LinkFlags ""} + {type_idx RDI_U32 ""} + {root_scope_idx RDI_U32 ""} + {container_idx RDI_U32 ""} + {frame_base_location_first RDI_U32 ""} + {frame_base_location_opl RDI_U32 ""} } @table(name type desc) @@ -1242,55 +1245,58 @@ RDI_LocationRegMemberTable: @table(name value num_decodes num_pops num_pushes) RDI_EvalOpTable: { - {Stop 0 0 0 0} - {Noop 1 0 0 0} - {Cond 2 1 1 0} - {Skip 3 2 0 0} - {MemRead 4 1 1 1} - {RegRead 5 4 0 1} - {RegReadDyn 6 0 1 1} - {FrameOff 7 1 0 1} - {ModuleOff 8 4 0 1} - {TLSOff 9 4 0 1} - {ObjectOff 10 0 0 0} - {CFA 11 0 0 0} - {ConstU8 12 1 0 1} - {ConstU16 13 2 0 1} - {ConstU32 14 4 0 1} - {ConstU64 15 8 0 1} - {ConstU128 16 16 0 1} - {ConstString 17 1 0 1} - {Abs 18 1 1 1} - {Neg 19 1 1 1} - {Add 20 1 2 1} - {Sub 21 1 2 1} - {Mul 22 1 2 1} - {Div 23 1 2 1} - {Mod 24 1 2 1} - {LShift 25 1 2 1} - {RShift 26 1 2 1} - {BitAnd 27 1 2 1} - {BitOr 28 1 2 1} - {BitXor 29 1 2 1} - {BitNot 30 1 1 1} - {LogAnd 31 1 2 1} - {LogOr 32 1 2 1} - {LogNot 33 1 1 1} - {EqEq 34 1 2 1} - {NtEq 35 1 2 1} - {LsEq 36 1 2 1} - {GrEq 37 1 2 1} - {Less 38 1 2 1} - {Grtr 39 1 2 1} - {Trunc 40 1 1 1} - {TruncSigned 41 1 1 1} - {Convert 42 2 1 1} - {Pick 43 1 0 1} - {Pop 44 0 1 0} - {Insert 45 1 0 0} - {ValueRead 46 1 2 1} - {ByteSwap 47 1 1 1} - {COUNT 48 0 0 0} + {Stop 0 0 0 0} + {Noop 1 0 0 0} + {Cond 2 1 1 0} + {Skip 3 2 0 0} + {MemRead 4 1 1 1} + {RegRead 5 4 0 1} + {RegReadDyn 6 0 1 1} + {FrameOff 7 8 0 1} + {ModuleOff 8 4 0 1} + {TLSOff 9 4 0 1} + {ObjectOff 10 0 0 0} + {CFA 11 0 0 0} + {ConstU8 12 1 0 1} + {ConstU16 13 2 0 1} + {ConstU32 14 4 0 1} + {ConstU64 15 8 0 1} + {ConstU128 16 16 0 1} + {ConstString 17 1 0 1} + {Abs 18 1 1 1} + {Neg 19 1 1 1} + {Add 20 1 2 1} + {Sub 21 1 2 1} + {Mul 22 1 2 1} + {Div 23 1 2 1} + {Mod 24 1 2 1} + {LShift 25 1 2 1} + {RShift 26 1 2 1} + {BitAnd 27 1 2 1} + {BitOr 28 1 2 1} + {BitXor 29 1 2 1} + {BitNot 30 1 1 1} + {LogAnd 31 1 2 1} + {LogOr 32 1 2 1} + {LogNot 33 1 1 1} + {EqEq 34 1 2 1} + {NtEq 35 1 2 1} + {LsEq 36 1 2 1} + {GrEq 37 1 2 1} + {Less 38 1 2 1} + {Grtr 39 1 2 1} + {Trunc 40 1 1 1} + {TruncSigned 41 1 1 1} + {Convert 42 2 1 1} + {Pick 43 1 0 1} + {Pop 44 0 1 0} + {Insert 45 1 0 0} + {ValueRead 46 1 2 1} + {ByteSwap 47 1 1 1} + {CallSiteValue 48 4 0 0} + {PartialValue 49 4 0 0} + {PartialValueBit 50 8 0 0} + {COUNT 51 0 0 0} } // NOTE(rjf): "ck" -> "conversion kind, when converted to type group", used in square matrix form @@ -1370,7 +1376,7 @@ rdi_eval_typegroup_conversion_kind_matrix: @data(`struct {RDI_U8 *str; RDI_U64 size;}`) @c_file rdi_eval_conversion_kind_message_string_table: { - @expand(RDI_EvalTypeGroupTable a) `{(RDI_U8 *)"$(a.error_string)", sizeof("$(a.error_string)")}` + @expand(RDI_EvalConversionKindTable a) `{(RDI_U8 *)"$(a.error_string)", sizeof("$(a.error_string)")}` } //////////////////////////////// @@ -1466,6 +1472,7 @@ RDI_PROC RDI_U32 rdi_addr_size_from_arch(RDI_Arch arch); RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_kind_from_typegroups(RDI_EvalTypeGroup in, RDI_EvalTypeGroup out); RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out); +RDI_PROC RDI_U8 *rdi_string_from_type_kind(RDI_TypeKind kind, RDI_U64 *size_out); ``` @gen(functions) @c_file @@ -1483,6 +1490,23 @@ rdi_hash(RDI_U8 *ptr, RDI_U64 size) } ``` +@gen(functions) @c_file +{ + `RDI_PROC RDI_U8 *`; + `rdi_string_from_type_kind(RDI_TypeKind kind, RDI_U64 *size_out)`; + `{`; + `RDI_U8 *result = 0;`; + `*size_out = 0;`; + `switch (kind)`; + `{`; + `default:{}break;`; + @expand(RDI_TypeKindTable a) ` case RDI_TypeKind_$(a.name): {result = (RDI_U8*)"$(a.name)"; *size_out = sizeof("$(a.name)")-1;}break;`, + `}`; + `return result;`; + `}`; + ``; +} + @gen(functions) @c_file { `RDI_PROC RDI_U32`; diff --git a/src/rdi_from_dwarf/rdi_dwarf.c b/src/rdi_from_dwarf/rdi_dwarf.c deleted file mode 100644 index eb257f0f..00000000 --- a/src/rdi_from_dwarf/rdi_dwarf.c +++ /dev/null @@ -1,1892 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ Dwarf Decode Helpers - -static U64 -dwarf_leb128_decode_U64(U8 *ptr, U8 *opl){ - U64 r = 0; - switch (opl - ptr){ - case 10: r |= ((U64)(ptr[9]&0x7F) << 63); - case 9: r |= ((U64)(ptr[8]&0x7F) << 56); - case 8: r |= ((U64)(ptr[7]&0x7F) << 49); - case 7: r |= ((U64)(ptr[6]&0x7F) << 42); - case 6: r |= ((U64)(ptr[5]&0x7F) << 35); - case 5: r |= ((U64)(ptr[4]&0x7F) << 28); - case 4: r |= ((U64)(ptr[3]&0x7F) << 21); - case 3: r |= ((U64)(ptr[2]&0x7F) << 14); - case 2: r |= ((U64)(ptr[1]&0x7F) << 7); - case 1: r |= ((U64)(ptr[0]&0x7F) ); - case 0: default: break; - } - return(r); -} - -static S64 -dwarf_leb128_decode_S64(U8 *ptr, U8 *opl){ - U64 u = dwarf_leb128_decode_U32(ptr, opl); - U64 s = (U64)(opl - ptr)*7; - B32 neg = ((u & (1llu << s)) != 0); - if (neg){ - switch (opl - ptr){ - case 9: u |= ~0x7FFFFFFFFFFFFFFFllu; break; - case 8: u |= ~0x00FFFFFFFFFFFFFFllu; break; - case 7: u |= ~ 0x01FFFFFFFFFFFFllu; break; - case 6: u |= ~ 0x03FFFFFFFFFFllu; break; - case 5: u |= ~ 0x07FFFFFFFFllu; break; - case 4: u |= ~ 0x0FFFFFFFllu; break; - case 3: u |= ~ 0x1FFFFFllu; break; - case 2: u |= ~ 0x3FFFllu; break; - case 1: u |= ~ 0x7Fllu; break; - } - } - S64 r = (S64)(u); - return(r); -} - -static U32 -dwarf_leb128_decode_U32(U8 *ptr, U8 *opl){ - U32 r = 0; - switch (opl - ptr){ - case 5: r |= ((U32)(ptr[4]&0x7F) << 28); - case 4: r |= ((U32)(ptr[3]&0x7F) << 21); - case 3: r |= ((U32)(ptr[2]&0x7F) << 14); - case 2: r |= ((U32)(ptr[1]&0x7F) << 7); - case 1: r |= ((U32)(ptr[0]&0x7F) ); - case 0: default: break; - } - return(r); -} - - -//////////////////////////////// -//~ Dwarf Parser Functions - -static DWARF_Parsed* -dwarf_parsed_from_elf(Arena *arena, ELF_Parsed *elf){ - DWARF_Parsed *result = 0; - - if (elf != 0){ - //- extract debug info - U32 debug_section_idx[DWARF_SectionCode_COUNT] = {0}; - String8 debug_section_name[DWARF_SectionCode_COUNT] = {0}; - String8 debug_data[DWARF_SectionCode_COUNT] = {0}; - for (U64 i = 1; i < DWARF_SectionCode_COUNT; i += 1){ - DWARF_SectionNameRow *row = dwarf_section_name_table + i; - U32 idx = 0; - for (U32 j = 0; idx == 0 && j < DWARF_SECTION_NAME_VARIANT_COUNT; j += 1){ - idx = elf_section_idx_from_name(elf, row->name[j]); - } - debug_section_idx[i] = idx; - debug_section_name[i] = elf_section_name_from_idx(elf, idx); - debug_data[i] = elf_section_data_from_idx(elf, idx); - } - - //- fill result - { - result = push_array(arena, DWARF_Parsed, 1); - result->elf = elf; - MemoryCopyArray(result->debug_section_idx, debug_section_idx); - MemoryCopyArray(result->debug_section_name, debug_section_name); - MemoryCopyArray(result->debug_data, debug_data); - } - } - - return(result); -} - -static DWARF_IndexParsed* -dwarf_index_from_data(Arena *arena, String8 data){ - DWARF_IndexParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_SupParsed* -dwarf_sup_from_data(Arena *arena, String8 data){ - DWARF_SupParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_InfoParsed* -dwarf_info_from_data(Arena *arena, String8 data){ - // supported version numbers: 4,5 - - - // empty unit list - DWARF_InfoUnit *first = 0; - DWARF_InfoUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // remember header offset - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // rest of header depends on version - U64 abbrev_off = 0; - U8 address_size = 0; - U8 unit_type = 0; - U64 unit_dwo_id = 0; - U64 unit_type_signature = 0; - U64 unit_type_offset = 0; - switch (version){ - case 4: - { - // abbrev_off - if (is_64bit){ - abbrev_off = MemoryConsume(U64, ptr, unit_opl); - } - else{ - abbrev_off = MemoryConsume(U32, ptr, unit_opl); - } - - // address_size - address_size = MemoryConsume(U8, ptr, unit_opl); - }break; - - case 5: - { - // unit_type - unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl); - - // address_size - address_size = MemoryConsume(U8, ptr, unit_opl); - - // abbrev_off - if (is_64bit){ - abbrev_off = MemoryConsume(U64, ptr, unit_opl); - } - else{ - abbrev_off = MemoryConsume(U32, ptr, unit_opl); - } - - // rest of header depends on unit_type - switch (unit_type){ - case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: - { - unit_dwo_id = MemoryConsume(U64, ptr, unit_opl); - }break; - case DWARF_UnitType_type: case DWARF_UnitType_split_type: - { - unit_type_signature = MemoryConsume(U64, ptr, unit_opl); - if (is_64bit){ - unit_type_offset = MemoryConsume(U64, ptr, unit_opl); - } - else{ - unit_type_offset = MemoryConsume(U32, ptr, unit_opl); - } - }break; - } - }break; - } - - // offset size - U8 offset_size = is_64bit?8:4; - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit unit - DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->offset_size = offset_size; - unit->version = version; - unit->unit_type = unit_type; - unit->address_size = address_size; - unit->abbrev_off = abbrev_off; - - switch (unit_type){ - case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: - { - unit->dwo_id = unit_dwo_id; - }break; - case DWARF_UnitType_type: case DWARF_UnitType_split_type: - { - unit->type_signature = unit_type_signature; - unit->type_offset = unit_type_offset; - }break; - } - - // advance to end of unit - ptr = unit_opl; - } - - // fill result - DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_PubNamesParsed* -dwarf_pubnames_from_data(Arena *arena, String8 data){ - // supported version numbers: 2 - - - // empty unit list - DWARF_PubNamesUnit *first = 0; - DWARF_PubNamesUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // remember header offset - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // info_off - U64 info_off = 0; - if (is_64bit){ - info_off = MemoryConsume(U64, ptr, unit_opl); - } - else{ - info_off = MemoryConsume(U32, ptr, unit_opl); - } - - // info_length - U64 info_length = 0; - if (is_64bit){ - info_length = MemoryConsume(U64, ptr, unit_opl); - } - else{ - info_length = MemoryConsume(U32, ptr, unit_opl); - } - - // offset size - U8 offset_size = is_64bit?8:4; - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit unit - DWARF_PubNamesUnit *unit = push_array(arena, DWARF_PubNamesUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->offset_size = offset_size; - unit->version = version; - unit->info_off = info_off; - unit->info_length = info_length; - - // advance to end of unit - ptr = unit_opl; - } - - // fill result - DWARF_PubNamesParsed *result = push_array(arena, DWARF_PubNamesParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_NamesParsed* -dwarf_names_from_data(Arena *arena, String8 data){ - // supported version numbers: 5 - - - // empty unit list - DWARF_NamesUnit *first = 0; - DWARF_NamesUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // remember header offset - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // *padding* - MemoryConsume(U16, ptr, unit_opl); - - // comp_unit_count - U32 comp_unit_count = MemoryConsume(U32, ptr, unit_opl); - - // local_type_unit_count - U32 local_type_unit_count = MemoryConsume(U32, ptr, unit_opl); - - // foreign_type_unit_count - U32 foreign_type_unit_count = MemoryConsume(U32, ptr, unit_opl); - - // bucket_count - U32 bucket_count = MemoryConsume(U32, ptr, unit_opl); - - // name_count - U32 name_count = MemoryConsume(U32, ptr, unit_opl); - - // abbrev_table_size - U32 abbrev_table_size = MemoryConsume(U32, ptr, unit_opl); - - // augmentation_string_size - U32 augmentation_string_size = MemoryConsume(U32, ptr, unit_opl); - - // augmentation_string - U8 *augmentation_string = ptr; - { - U8 *ptr_raw = ptr + augmentation_string_size; - ptr = ClampTop(ptr_raw, unit_opl); - } - - // offset size - U8 offset_size = is_64bit?8:4; - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit unit - DWARF_NamesUnit *unit = push_array(arena, DWARF_NamesUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->version = version; - unit->comp_unit_count = comp_unit_count; - unit->local_type_unit_count = local_type_unit_count; - unit->foreign_type_unit_count = foreign_type_unit_count; - unit->bucket_count = bucket_count; - unit->name_count = name_count; - unit->abbrev_table_size = abbrev_table_size; - unit->augmentation_string = str8_cstring_capped(augmentation_string, unit_opl); - - // advance to end of unit - ptr = unit_opl; - } - - // fill result - DWARF_NamesParsed *result = push_array(arena, DWARF_NamesParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_ArangesParsed* -dwarf_aranges_from_data(Arena *arena, String8 data){ - // supported version numbers: 2 - - - // empty unit list - DWARF_ArangesUnit *first = 0; - DWARF_ArangesUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // remember header offset - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // info_off - U64 info_off = 0; - if (is_64bit){ - info_off = MemoryConsume(U64, ptr, unit_opl); - } - else{ - info_off = MemoryConsume(U32, ptr, unit_opl); - } - - // address_size - U8 address_size = MemoryConsume(U8, ptr, unit_opl); - - // segment_selector_size - U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl); - - // offset size - U8 offset_size = is_64bit?8:4; - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit unit - DWARF_ArangesUnit *unit = push_array(arena, DWARF_ArangesUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->version = version; - unit->address_size = address_size; - unit->segment_selector_size = segment_selector_size; - unit->offset_size = offset_size; - unit->info_off = info_off; - - // advance to end of unit - ptr = unit_opl; - } - - // fill result - DWARF_ArangesParsed *result = push_array(arena, DWARF_ArangesParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_LineParsed* -dwarf_line_from_data(Arena *arena, String8 data){ - // supported version numbers: 4, 5 - - - // empty unit list - DWARF_LineUnit *first = 0; - DWARF_LineUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // remember header offset - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // offset size - U8 offset_size = is_64bit?8:4; - - // rest of header depends on version - U8 minimum_instruction_length = 0; - U8 maximum_operations_per_instruction = 0; - U8 default_is_stmt = 0; - S8 line_base = 0; - U8 line_range = 0; - U8 opcode_base = 0; - U8 *standard_opcode_lengths = 0; - // v4 - String8List include_directories = {0}; - DWARF_V4LineFileNamesList file_names = {0}; - // v5 - U8 address_size = 0; - U8 segment_selector_size = 0; - U8 directory_entry_format_count = 0; - DWARF_V5LinePathEntryFormat *directory_entry_format = 0; - U64 directories_count = 0; - U8 file_name_entry_format_count = 0; - DWARF_V5LinePathEntryFormat *file_name_entry_format = 0; - U64 file_names_count = 0; - - switch (version){ - case 4: - { - // header_length - U64 header_length = 0; - if (is_64bit){ - header_length = MemoryConsume(U64, ptr, unit_opl); - } - else{ - header_length = MemoryConsume(U32, ptr, unit_opl); - } - - // header opl - U8 *header_opl_raw = ptr + header_length; - U8 *header_opl = ClampTop(header_opl_raw, unit_opl); - - // minimum_instruction_length - minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); - - // maximum_operations_per_instruction - maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl); - - // default_is_stmt - default_is_stmt = MemoryConsume(U8, ptr, header_opl); - - // line_base - line_base = MemoryConsume(S8, ptr, header_opl); - - // line_range - line_range = MemoryConsume(U8, ptr, header_opl); - - // opcode_base - opcode_base = MemoryConsume(U8, ptr, header_opl); - - // standard_opcode_lengths - if (opcode_base > 1){ - standard_opcode_lengths = ptr; - ptr += opcode_base - 1; - } - - // include_directories - for (;ptr < header_opl;){ - // null byte ends entries - if (*ptr == 0){ - ptr += 1; - break; - } - - // extract dir range - U8 *dir_first = ptr; - for (;ptr < header_opl && *ptr != 0;) ptr += 1; - U8 *dir_opl = ptr; - if (ptr < header_opl){ - ptr += 1; - } - - // attach dir to list - String8 dir = str8_range(dir_first, dir_opl); - str8_list_push(arena, &include_directories, dir); - } - - // file_names - for (;ptr < header_opl;){ - // null byte ends entries - if (*ptr == 0){ - ptr += 1; - break; - } - - // extract file_name range - U8 *file_name_first = ptr; - for (;ptr < header_opl && *ptr != 0;) ptr += 1; - U8 *file_name_opl = ptr; - if (ptr < header_opl){ - ptr += 1; - } - - // extract include directory index - U64 include_directory_idx = 0; - DWARF_LEB128_DECODE_ADV(U64, include_directory_idx, ptr, header_opl); - - // extract last modified time - U64 last_modified_time = 0; - DWARF_LEB128_DECODE_ADV(U64, last_modified_time, ptr, header_opl); - - // extract file size - U64 file_size = 0; - DWARF_LEB128_DECODE_ADV(U64, file_size, ptr, header_opl); - - // emit file name entry - DWARF_V4LineFileNamesEntry *entry = push_array(arena, DWARF_V4LineFileNamesEntry, 1); - SLLQueuePush(file_names.first, file_names.last, entry); - file_names.count += 1; - entry->file_name = str8_range(file_name_first, file_name_opl); - entry->include_directory_idx = include_directory_idx; - entry->last_modified_time = last_modified_time; - entry->file_size = file_size; - } - - ptr = header_opl; - }break; - - case 5: - { - // address_size - address_size = MemoryConsume(U8, ptr, unit_opl); - - // segment_selector_size - segment_selector_size = MemoryConsume(U8, ptr, unit_opl); - - // header_length - U64 header_length = 0; - if (is_64bit){ - header_length = MemoryConsume(U64, ptr, unit_opl); - } - else{ - header_length = MemoryConsume(U32, ptr, unit_opl); - } - - // header opl - U8 *header_opl_raw = ptr + header_length; - U8 *header_opl = ClampTop(header_opl_raw, unit_opl); - - // minimum_instruction_length - minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); - - // maximum_operations_per_instruction - maximum_operations_per_instruction = MemoryConsume(U8, ptr, header_opl); - - // default_is_stmt - default_is_stmt = MemoryConsume(U8, ptr, header_opl); - - // line_base - line_base = MemoryConsume(S8, ptr, header_opl); - - // line_range - line_range = MemoryConsume(U8, ptr, header_opl); - - // opcode_base - opcode_base = MemoryConsume(U8, ptr, header_opl); - - // standard_opcode_lengths - if (opcode_base > 1){ - standard_opcode_lengths = ptr; - ptr += opcode_base - 1; - } - - // directory_entry_format_count - directory_entry_format_count = MemoryConsume(U8, ptr, header_opl); - - // directory_entry_format - { - directory_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat, - directory_entry_format_count); - DWARF_V5LinePathEntryFormat *entry = directory_entry_format; - DWARF_V5LinePathEntryFormat *entry_opl = - directory_entry_format + directory_entry_format_count; - for (;entry < entry_opl && ptr < header_opl; entry += 1){ - DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl); - DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl); - } - } - - // directories_count - DWARF_LEB128_DECODE_ADV(U64, directories_count, ptr, header_opl); - - // directories - DWARF_V5Directory *directories = push_array(arena, DWARF_V5Directory, directories_count); - dwarf__line_v5_directories(address_size, offset_size, - directory_entry_format, directory_entry_format_count, - directories, directories_count, - &ptr, header_opl); - - // file_name_entry_format_count - file_name_entry_format_count = MemoryConsume(U8, ptr, header_opl); - - // file_name_entry_format - { - file_name_entry_format = push_array(arena, DWARF_V5LinePathEntryFormat, - file_name_entry_format_count); - DWARF_V5LinePathEntryFormat *entry = file_name_entry_format; - for (;ptr < header_opl; entry += 1){ - DWARF_LEB128_DECODE_ADV(U64, entry->content_type, ptr, header_opl); - DWARF_LEB128_DECODE_ADV(U64, entry->form, ptr, header_opl); - } - } - - // file_names_count - DWARF_LEB128_DECODE_ADV(U64, file_names_count, ptr, header_opl); - - // file_names - DWARF_V5Directory *file_names = push_array(arena, DWARF_V5Directory, file_names_count); - dwarf__line_v5_directories(address_size, offset_size, - directory_entry_format, directory_entry_format_count, - file_names, file_names_count, - &ptr, header_opl); - }break; - } - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit unit - DWARF_LineUnit *unit = push_array(arena, DWARF_LineUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->version = version; - - // advance to end of unit - ptr = unit_opl; - } - - // fill result - DWARF_LineParsed *result = push_array(arena, DWARF_LineParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_MacInfoParsed* -dwarf_mac_info_from_data(Arena *arena, String8 data){ - DWARF_MacInfoParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_MacroParsed* -dwarf_macro_from_data(Arena *arena, String8 data){ - DWARF_MacroParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_FrameParsed* -dwarf_frame_from_data(Arena *arena, String8 data){ - DWARF_FrameParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_RangesParsed* -dwarf_ranges_from_data(Arena *arena, String8 data){ - DWARF_RangesParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_StrOffsetsParsed* -dwarf_str_offsets_from_data(Arena *arena, String8 data){ - DWARF_StrOffsetsParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_AddrParsed* -dwarf_addr_from_data(Arena *arena, String8 data){ - // supported version numbers: 5 - - - // addr unit list - DWARF_AddrUnit *first = 0; - DWARF_AddrUnit *last = 0; - U64 count = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - U64 hdr_off = (ptr - data.str); - - // initial length - U8 *unit_opl = 0; - B32 is_64bit = 0; - dwarf__initial_length(data, &ptr, &unit_opl, &is_64bit); - - // version - U8 version = MemoryConsume(U16, ptr, unit_opl); - - // address size - U8 address_size = MemoryConsume(U8, ptr, unit_opl); - - // segment selector size - U8 segment_selector_size = MemoryConsume(U8, ptr, unit_opl); - - // offset size - U32 offset_size = is_64bit?8:4; - - // unit offsets - U64 base_off = (ptr - data.str); - U64 opl_off = (unit_opl - data.str); - - // emit addr unit - DWARF_AddrUnit *unit = push_array(arena, DWARF_AddrUnit, 1); - SLLQueuePush(first, last, unit); - count += 1; - - unit->hdr_off = hdr_off; - unit->base_off = base_off; - unit->opl_off = opl_off; - - unit->offset_size = offset_size; - unit->dwarf_version = version; - unit->address_size = address_size; - unit->segment_selector_size = segment_selector_size; - - // advance to next unit - ptr = unit_opl; - } - - // fill result - DWARF_AddrParsed *result = push_array(arena, DWARF_AddrParsed, 1); - result->unit_first = first; - result->unit_last = last; - result->unit_count = count; - return(result); -} - -static DWARF_RngListsParsed* -dwarf_rng_lists_from_data(Arena *arena, String8 data){ - DWARF_RngListsParsed *result = 0; - // TODO(allen): - return(result); -} - -static DWARF_LocListsParsed* -dwarf_loc_lists_from_data(Arena *arena, String8 data){ - DWARF_LocListsParsed *result = 0; - // TODO(allen): - return(result); -} - - -// parse helpers - -static void -dwarf__initial_length(String8 data, U8 **ptr_inout, U8 **unit_opl_out, B32 *is_64bit_out){ - U8 *unit_opl = 0; - B32 is_64bit = 0; - - U8 *opl = data.str + data.size; - U8 *ptr = *ptr_inout; - { - U64 length = 0; - U32 m = MemoryConsume(U32, ptr, opl); - if (m == 0xFFFFFFFF){ - is_64bit = 1; - length = MemoryConsume(U64, ptr, opl); - } - else{ - length = ClampTop(m, 0xFFFFFFF0); - } - if (length > 0){ - U64 unit_opl_off_raw = (ptr - data.str) + length; - U64 unit_opl_off = ClampTop(unit_opl_off_raw, data.size); - unit_opl = data.str + unit_opl_off; - } - else{ - unit_opl = ptr; - } - } - - *ptr_inout = ptr; - *unit_opl_out = unit_opl; - *is_64bit_out = is_64bit; -} - -static void -dwarf__line_v5_directories(U64 address_size, U64 offset_size, - DWARF_V5LinePathEntryFormat *format, U64 format_count, - DWARF_V5Directory *directories_out, U64 dir_count, - U8 **ptr_io, U8 *opl){ - - U8 *ptr = *ptr_io; - - DWARF_V5Directory *directory_ptr = directories_out; - for (U32 i = 0; i < dir_count; i += 1, directory_ptr += 1){ - DWARF_V5LinePathEntryFormat *fmt = format; - for (U32 j = 0; j < format_count; j += 1){ - - // form decode - DWARF_FormDecodeRules rules = - dwarf_form_decode_rule(fmt->form, address_size, offset_size); - - // execute decoding - DWARF_FormDecoded decoded = dwarf_form_decode(&rules, &ptr, opl, 0, 0); - - // store to correct field - U64 *target = 0; - switch (fmt->content_type){ - case DWARF_LineEntryFormat_path: - { - if (decoded.dataptr != 0){ - directory_ptr->path_str = str8(decoded.dataptr, decoded.val); - } - else{ - directory_ptr->path_off = decoded.val; - directory_ptr->path_sec_form = fmt->form; - } - }break; - - case DWARF_LineEntryFormat_directory_index: - { - target = &directory_ptr->directory_index; - }goto v5_directory_u64; - - case DWARF_LineEntryFormat_timestamp: - { - target = &directory_ptr->timestamp; - }goto v5_directory_u64; - - case DWARF_LineEntryFormat_size: - { - target = &directory_ptr->size; - }goto v5_directory_u64; - - v5_directory_u64: - { - if (decoded.dataptr != 0){ - U64 size = ClampTop(decoded.val, 8); - MemoryCopy(target, decoded.dataptr, size); - } - else{ - *target = decoded.val; - } - }break; - - case DWARF_LineEntryFormat_MD5: - { - if (decoded.dataptr != 0){ - U64 size = ClampTop(decoded.val, 16); - MemoryCopy(directory_ptr->md5_checksum, decoded.dataptr, size); - } - }break; - } - } - } - - *ptr_io = ptr; -} - - -// debug sections - -static String8 -dwarf_name_from_debug_section(DWARF_Parsed *dwarf, DWARF_SectionCode sec_code){ - String8 result = str8_lit("invalid_debug_section"); - if (sec_code < DWARF_SectionCode_COUNT){ - if (dwarf->debug_section_idx[sec_code] != 0){ - result = dwarf->debug_section_name[sec_code]; - } - } - return(result); -} - - -// abbrev functions - -static DWARF_AbbrevUnit* -dwarf_abbrev_unit_from_offset(DWARF_AbbrevParsed *abbrev, U64 offset){ - DWARF_AbbrevUnit *result = 0; - for (DWARF_AbbrevUnit *unit = abbrev->unit_first; - unit != 0; - unit = unit->next){ - if (unit->offset == offset){ - result = unit; - break; - } - } - return(result); -} - -static DWARF_AbbrevDecl* -dwarf_abbrev_decl_from_code(DWARF_AbbrevUnit *unit, U32 abbrev_code){ - DWARF_AbbrevDecl *result = 0; - for (DWARF_AbbrevDecl *decl = unit->first; - decl != 0; - decl = decl->next){ - if (decl->abbrev_code == abbrev_code){ - result = decl; - break; - } - } - return(result); -} - -// attribute decoding functions - -static DWARF_AttributeClassFlags -dwarf_attribute_class_from_form(DWARF_AttributeForm form){ - DWARF_AttributeClassFlags result = 0; - switch (form){ -#define X(N,C,f) case C: result = DWARF_AttributeClassFlag_##f; break; - DWARF_AttributeFormXList(X) -#undef X - } - return(result); -} - -static DWARF_AttributeClassFlags -dwarf_attribute_class_from_name(DWARF_AttributeName name){ - DWARF_AttributeClassFlags result = 0; - switch (name){ -#define X(N,C,f1,f2,f3,f4) case C: result = 0\ -|DWARF_AttributeClassFlag_##f1\ -|DWARF_AttributeClassFlag_##f2\ -|DWARF_AttributeClassFlag_##f3\ -|DWARF_AttributeClassFlag_##f4\ -;break; - DWARF_AttributeNameXList(X) -#undef X - } - return(result); -} - -// form decoding functions - -static DWARF_FormDecodeRules -dwarf_form_decode_rule(DWARF_AttributeForm form, U64 address_size, U64 offset_size){ - DWARF_FormDecodeRules result = {0}; - switch (form){ - case DWARF_AttributeForm_null: - case DWARF_AttributeForm_indirect:{}break; - - case DWARF_AttributeForm_addr: result.size = address_size; break; - case DWARF_AttributeForm_addrx: result.uleb128 = 1; break; - case DWARF_AttributeForm_addrx1: result.size = 1; break; - case DWARF_AttributeForm_addrx2: result.size = 2; break; - case DWARF_AttributeForm_addrx3: result.size = 3; break; - case DWARF_AttributeForm_addrx4: result.size = 4; break; - - case DWARF_AttributeForm_sec_offset: result.size = offset_size; break; - - case DWARF_AttributeForm_block1: result.size = 1; result.block = 1; break; - case DWARF_AttributeForm_block2: result.size = 2; result.block = 1; break; - case DWARF_AttributeForm_block4: result.size = 4; result.block = 1; break; - case DWARF_AttributeForm_block: result.uleb128 = 1; result.block = 1; break; - - case DWARF_AttributeForm_data1: result.size = 1; break; - case DWARF_AttributeForm_data2: result.size = 2; break; - case DWARF_AttributeForm_data4: result.size = 4; break; - case DWARF_AttributeForm_data8: result.size = 8; break; - case DWARF_AttributeForm_data16: result.size = 16; break; - - case DWARF_AttributeForm_sdata: result.sleb128 = 1; break; - case DWARF_AttributeForm_udata: result.uleb128 = 1; break; - - case DWARF_AttributeForm_implicit_const: result.in_abbrev = 1; break; - - case DWARF_AttributeForm_exprloc: result.uleb128 = 1; result.block = 1; break; - - case DWARF_AttributeForm_flag: result.size = 1; break; - case DWARF_AttributeForm_flag_present: result.auto_1 = 1; break; - - case DWARF_AttributeForm_loclistx: result.uleb128 = 1; break; - case DWARF_AttributeForm_rnglistx: result.uleb128 = 1; break; - - case DWARF_AttributeForm_ref1: result.size = 1; break; - case DWARF_AttributeForm_ref2: result.size = 2; break; - case DWARF_AttributeForm_ref4: result.size = 4; break; - case DWARF_AttributeForm_ref8: result.size = 8; break; - case DWARF_AttributeForm_ref_udata: result.uleb128 = 1; break; - - case DWARF_AttributeForm_ref_addr: result.size = offset_size; break; - - case DWARF_AttributeForm_ref_sig8: result.size = 8; break; - - case DWARF_AttributeForm_ref_sup4: result.size = 4; break; - case DWARF_AttributeForm_ref_sup8: result.size = 8; break; - - case DWARF_AttributeForm_string: result.null_terminated = 1; break; - - case DWARF_AttributeForm_strp: result.size = offset_size; break; - case DWARF_AttributeForm_line_strp: result.size = offset_size; break; - case DWARF_AttributeForm_strp_sup: result.size = offset_size; break; - - case DWARF_AttributeForm_strx: result.uleb128 = 1; break; - case DWARF_AttributeForm_strx1: result.size = 1; break; - case DWARF_AttributeForm_strx2: result.size = 2; break; - case DWARF_AttributeForm_strx3: result.size = 3; break; - case DWARF_AttributeForm_strx4: result.size = 4; break; - } - - return(result); -} - -static DWARF_FormDecoded -dwarf_form_decode(DWARF_FormDecodeRules *rules, U8 **ptr_io, U8 *opl, - DWARF_AbbrevDecl *abbrev_decl, U32 attrib_i){ - - // local copy of ptr - U8 *ptr = *ptr_io; - - // apply rules - U64 val = 0; - U8 *dataptr = 0; - - B32 success = 1; - if (rules->size > 0){ - if (ptr + rules->size <= opl){ - MemoryCopy(&val, ptr, rules->size); - ptr += rules->size; - } - else{ - success = 0; - } - } - else if (rules->uleb128 || rules->sleb128){ - U8 *val_ptr = ptr; - DWARF_LEB128_ADV(ptr, opl, success); - if (success){ - if (rules->uleb128){ - val = dwarf_leb128_decode_U64(val_ptr, ptr); - } - else{ - val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr); - } - } - } - else if (rules->in_abbrev){ - if (abbrev_decl != 0){ - if (abbrev_decl->implicit_const != 0){ - val = (U64)abbrev_decl->implicit_const[attrib_i]; - } - } - else{ - success = 0; - } - } - else if (rules->auto_1){ - val = 1; - } - if (rules->block){ - dataptr = ptr; - ptr += val; - } - else if (rules->null_terminated){ - dataptr = ptr; - for (;ptr < opl && *ptr != 0;) ptr += 1; - val = (U64)(ptr - dataptr); - if (ptr < opl){ - ptr += 1; - } - } - - // store out ptr - *ptr_io = ptr; - - // fill result - DWARF_FormDecoded result = {0}; - result.val = val; - result.dataptr = dataptr; - result.error = !success; - return(result); -} - - -// string functions - -static String8 -dwarf_string_from_unit_type(DWARF_UnitType type){ - String8 result = str8_lit("unrecognized_type"); - switch (type){ -#define X(N,C) case C: result = str8_lit(#N); break; - DWARF_UnitTypeXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_tag(DWARF_Tag tag){ - String8 result = str8_lit("unrecognized_tag"); - switch (tag){ -#define X(N,C) case C: result = str8_lit(#N); break; - DWARF_TagXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_attribute_name(DWARF_AttributeName name){ - String8 result = str8_lit("unrecognized_attribute_name"); - switch (name){ -#define X(N,C,f1,f2,f3,f4) case C: result = str8_lit(#N); break; - DWARF_AttributeNameXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_attribute_form(DWARF_AttributeForm form){ - String8 result = str8_lit("unrecognized_attribute_form"); - switch (form){ -#define X(N,C,k) case C: result = str8_lit(#N); break; - DWARF_AttributeFormXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_line_std_op(DWARF_LineStdOp op){ - String8 result = str8_lit("unrecognized_line_std_op"); - switch (op){ -#define X(N,C) case C: result = str8_lit(#N); break; - DWARF_LineStdOpXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_line_ext_op(DWARF_LineExtOp op){ - String8 result = str8_lit("unrecognized_line_ext_op"); - switch (op){ -#define X(N,C) case C: result = str8_lit(#N); break; - DWARF_LineExtOpXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format){ - String8 result = str8_lit("unrecognized_line_entry_format"); - switch (format){ -#define X(N,C) case C: result = str8_lit(#N); break; - DWARF_LineEntryFormatXList(X) -#undef X - } - return(result); -} - -static String8 -dwarf_string_from_section_code(DWARF_SectionCode sec_code){ - String8 result = str8_lit("unrecognized_section_code"); - switch (sec_code){ - case DWARF_SectionCode_COUNT:{}break; -#define X(Nc,Vf,N0,N1,N2) case DWARF_SectionCode_##Nc: result = str8_lit(#Nc); break; - DWARF_SectionNameXList(X,0,0) -#undef X - } - return(result); -} - - - - - -#if 0 -static DWARF_InfoParsed* -dwarf_info_from_data(Arena *arena, String8 data, DWARF_InfoParams *params, - DWARF_AbbrevParsed *abbrev){ - - // unit index range to extract - U64 unit_idx_min = params->unit_idx_min; - U64 unit_idx_max = params->unit_idx_max; - - // empty unit list - DWARF_InfoUnit *unit_first = 0; - DWARF_InfoUnit *unit_last = 0; - U64 unit_count = 0; - B32 decoding_error = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // early escape on unit idx - if (unit_idx > unit_idx_max){ - break; - } - - // determine whether to full parse this unit - B32 full_parse = (unit_idx_min <= unit_idx); - - // header fields - U8 *unit_opl = 0; - B32 is_64bit = 0; - U16 version = 0; - U64 abbrev_offset = 0; - U32 address_size = 0; - DWARF_UnitType unit_type = DWARF_UnitType_null; - U64 unit_dwo_id = 0; - U64 unit_type_signature = 0; - U64 unit_type_offset = 0; - - // initial length - dwarf__initial_length(&ptr, opl, &unit_opl, &is_64bit); - - // if this is not a full parse we may use - // unit_opl to skip to the next unit now - if (full_parse){ - - // version (part of header) - version = MemoryConsume(U16, ptr, unit_opl); - - // rest of header depends on version - switch (version){ - case 4: - { - // abbrev_offset (part of header) - if (is_64bit){ - abbrev_offset = MemoryConsume(U64, ptr, unit_opl); - } - else{ - abbrev_offset = MemoryConsume(U32, ptr, unit_opl); - } - - // address_size (part of header) - address_size = MemoryConsume(U8, ptr, unit_opl); - }break; - - case 5: - { - // unit_type (part of header) - unit_type = (DWARF_UnitType)MemoryConsume(U8, ptr, unit_opl); - - // address_size (part of header) - address_size = MemoryConsume(U8, ptr, unit_opl); - - // abbrev_offset (part of header) - if (is_64bit){ - abbrev_offset = MemoryConsume(U64, ptr, unit_opl); - } - else{ - abbrev_offset = MemoryConsume(U32, ptr, unit_opl); - } - - // rest of header depends on unit_type - switch (unit_type){ - case DWARF_UnitType_skeleton: - case DWARF_UnitType_split_compile: - { - unit_dwo_id = MemoryConsume(U64, ptr, unit_opl); - }break; - case DWARF_UnitType_type: - case DWARF_UnitType_split_type: - { - unit_type_signature = MemoryConsume(U64, ptr, unit_opl); - if (is_64bit){ - unit_type_offset = MemoryConsume(U64, ptr, unit_opl); - } - else{ - unit_type_offset = MemoryConsume(U32, ptr, unit_opl); - } - }break; - } - }break; - } - - // offset size - U32 offset_size = is_64bit?8:4; - - // find matching abbrev unit - DWARF_AbbrevUnit *abbrev_unit = dwarf_abbrev_unit_from_offset(abbrev, abbrev_offset); - if (abbrev_unit == 0){ - // TODO: preserve error info - decoding_error = 1; - } - - // consume info entries - DWARF_InfoEntry *entry_root = 0; - U64 entry_count = 0; - - DWARF_InfoEntry *entry_consptr = 0; - if (abbrev_unit != 0){ - for (;ptr < unit_opl;){ - B32 success = 1; - - // mark beginning of entry - U8 *entry_start_ptr = ptr; - - // extract abbrev code - U8 *abbrev_code_ptr = ptr; - DWARF_LEB128_ADV(ptr, unit_opl, success); - if (!success){ - // TODO: preserve error info - decoding_error = 1; - goto exit_unit_loop; - } - - U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, ptr); - - // null abbrev code means pop - if (abbrev_code == 0){ - if (entry_consptr == 0){ - goto exit_unit_loop; - } - else{ - entry_consptr = entry_consptr->parent; - goto skip_entry; - } - } - - // get abbrev decl - DWARF_AbbrevDecl *abbrev_decl = dwarf_abbrev_decl_from_code(abbrev_unit, abbrev_code); - if (abbrev_decl == 0){ - // TODO: preserve error info - decoding_error = 1; - goto exit_unit_loop; - } - - // allocate entry - U32 attrib_count = abbrev_decl->attrib_count; - DWARF_InfoEntry *entry = push_array(arena, DWARF_InfoEntry, 1); - DWARF_InfoAttribVal *attrib_vals = - push_array_no_zero(arena, DWARF_InfoAttribVal, attrib_count); - - // save entry offset - entry->info_offset = (U64)(entry_start_ptr - data.str); - - // set root at beginning - if (entry_root == 0){ - entry_root = entry; - } - - // attribute loop - DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; - DWARF_InfoAttribVal *attrib_val = attrib_vals; - for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ - - // determine decoding rules - U32 size = 0; - B8 uleb128 = 0; - B8 sleb128 = 0; - B8 in_abbrev = 0; - B8 auto_1 = 0; - B8 block = 0; - B8 null_terminated = 0; - { - DWARF_AttributeForm form = attrib_spec->form; - switch (form){ - case DWARF_AttributeForm_addr: size = address_size; break; - case DWARF_AttributeForm_addrx: uleb128 = 1; break; - case DWARF_AttributeForm_addrx1: size = 1; break; - case DWARF_AttributeForm_addrx2: size = 2; break; - case DWARF_AttributeForm_addrx3: size = 3; break; - case DWARF_AttributeForm_addrx4: size = 4; break; - - case DWARF_AttributeForm_sec_offset: size = offset_size; break; - - case DWARF_AttributeForm_block1: size = 1; block = 1; break; - case DWARF_AttributeForm_block2: size = 2; block = 1; break; - case DWARF_AttributeForm_block4: size = 4; block = 1; break; - case DWARF_AttributeForm_block: uleb128 = 1; block = 1; break; - - case DWARF_AttributeForm_data1: size = 1; break; - case DWARF_AttributeForm_data2: size = 2; break; - case DWARF_AttributeForm_data4: size = 4; break; - case DWARF_AttributeForm_data8: size = 8; break; - case DWARF_AttributeForm_data16: size = 16; break; - - case DWARF_AttributeForm_sdata: sleb128 = 1; break; - case DWARF_AttributeForm_udata: uleb128 = 1; break; - - case DWARF_AttributeForm_implicit_const: in_abbrev = 1; break; - - case DWARF_AttributeForm_exprloc: uleb128 = 1; block = 1; break; - - case DWARF_AttributeForm_flag: size = 1; break; - case DWARF_AttributeForm_flag_present: auto_1 = 1; break; - - case DWARF_AttributeForm_loclistx: uleb128 = 1; break; - case DWARF_AttributeForm_rnglistx: uleb128 = 1; break; - - case DWARF_AttributeForm_ref1: size = 1; break; - case DWARF_AttributeForm_ref2: size = 2; break; - case DWARF_AttributeForm_ref4: size = 4; break; - case DWARF_AttributeForm_ref8: size = 8; break; - case DWARF_AttributeForm_ref_udata: uleb128 = 1; break; - - case DWARF_AttributeForm_ref_addr: size = offset_size; break; - - case DWARF_AttributeForm_ref_sig8: size = 8; break; - - case DWARF_AttributeForm_ref_sup4: size = 4; break; - case DWARF_AttributeForm_ref_sup8: size = 8; break; - - case DWARF_AttributeForm_string: null_terminated = 1; break; - - case DWARF_AttributeForm_strp: size = offset_size; break; - case DWARF_AttributeForm_line_strp: size = offset_size; break; - case DWARF_AttributeForm_strp_sup: size = offset_size; break; - - case DWARF_AttributeForm_strx: uleb128 = 1; break; - case DWARF_AttributeForm_strx1: size = 1; break; - case DWARF_AttributeForm_strx2: size = 2; break; - case DWARF_AttributeForm_strx3: size = 3; break; - case DWARF_AttributeForm_strx4: size = 4; break; - } - } - - // execute decoding rules - U64 val = 0; - U8 *dataptr = 0; - { - if (size > 0){ - if (ptr + size <= unit_opl){ - MemoryCopy(&val, ptr, size); - ptr += size; - } - else{ - // TODO: preserve error info - decoding_error = 1; - goto exit_unit_loop; - } - } - else if (uleb128 || sleb128){ - U8 *val_ptr = ptr; - DWARF_LEB128_ADV(ptr, unit_opl, success); - if (!success){ - // TODO: preserve error info - decoding_error = 1; - goto exit_unit_loop; - } - else{ - if (uleb128){ - val = dwarf_leb128_decode_U64(val_ptr, ptr); - } - else{ - val = (U64)dwarf_leb128_decode_S64(val_ptr, ptr); - } - } - } - else if (in_abbrev){ - if (abbrev_decl->implicit_const != 0){ - val = (U64)abbrev_decl->implicit_const[i]; - } - } - else if (auto_1){ - val = 1; - } - if (block){ - dataptr = ptr; - ptr += val; - } - else if (null_terminated){ - dataptr = ptr; - for (;ptr < unit_opl && *ptr != 0;) ptr += 1; - val = (U64)(ptr - dataptr); - } - } - - // save attribute - attrib_val->val = val; - attrib_val->dataptr = dataptr; - } - - // emit entry - if (entry_consptr != 0){ - SLLQueuePush_N(entry_consptr->first_child, entry_consptr->last_child, - entry, next_sibling); - entry_consptr->child_count += 1; - entry->parent = entry_consptr; - } - entry_count += 1; - entry->abbrev_decl = abbrev_decl; - entry->attrib_vals = attrib_vals; - - // move consptr down if has children - if (abbrev_decl->has_children){ - entry_consptr = entry; - } - - skip_entry:; - } - } - exit_unit_loop:; - - // TODO: notice errors, emit them, and exit loop here - if (decoding_error){ - break; - } - - // extract root attributes - U64 language = 0; - U64 str_offsets_base = 0; - U64 line_info_offset = 0; - U64 vbase = 0; - U64 addr_base = 0; - U64 rnglists_base = 0; - U64 loclists_base = 0; - if (entry_root != 0){ - - // pull out attributes - DWARF_AbbrevDecl *root_abbrev_decl = entry_root->abbrev_decl; - DWARF_AbbrevAttribSpec *attrib_specs = root_abbrev_decl->attrib_specs; - DWARF_InfoAttribVal *attrib_vals = entry_root->attrib_vals; - U32 attrib_count = root_abbrev_decl->attrib_count; - - // examine each attribute - DWARF_AbbrevAttribSpec *attrib_spec = attrib_specs; - DWARF_InfoAttribVal *attrib_val = attrib_vals; - for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ - - // determine if there is a root attribute to extract here - U64 *target_u64 = 0; - switch (attrib_spec->name){ - case DWARF_AttributeName_language: target_u64 = &language; break; - case DWARF_AttributeName_str_offsets_base: target_u64 = &str_offsets_base; break; - case DWARF_AttributeName_stmt_list: target_u64 = &line_info_offset; break; - case DWARF_AttributeName_low_pc: target_u64 = &vbase; break; - case DWARF_AttributeName_addr_base: target_u64 = &addr_base; break; - case DWARF_AttributeName_rnglists_base: target_u64 = &rnglists_base; break; - case DWARF_AttributeName_loclists_base: target_u64 = &loclists_base; break; - } - - // set target from attrib value - if (target_u64 != 0){ - *target_u64 = attrib_val->val; - } - } - } - - // allocate unit - DWARF_InfoUnit *unit = push_array(arena, DWARF_InfoUnit, 1); - - // fill & emit unit - SLLQueuePush(unit_first, unit_last, unit); - unit_count += 1; - // [header] - unit->dwarf_version = version; - unit->offset_size = offset_size; - unit->address_size = address_size; - // [root attributes] - unit->language = (DWARF_Language)language; - unit->str_offsets_base = str_offsets_base; - unit->line_info_offset = line_info_offset; - unit->vbase = vbase; - unit->addr_base = addr_base; - unit->rnglists_base = rnglists_base; - unit->loclists_base = loclists_base; - // [entries] - unit->entry_root = entry_root; - unit->entry_count = entry_count; - - } - - // set ptr to end of this unit - ptr = unit_opl; - } - - // fill result - DWARF_InfoParsed *result = push_array(arena, DWARF_InfoParsed, 1); - result->unit_first = unit_first; - result->unit_last = unit_last; - result->unit_count = unit_count; - result->decoding_error = decoding_error; - return(result); -} - -static DWARF_AbbrevParsed* -dwarf_abbrev_from_data(Arena *arena, String8 data, DWARF_AbbrevParams *params){ - /* .debug_abbrev - ** Layout - ** List(Tag) - ** Tag = { id:ULEB128, tag:ULEB128, has_children:B8, ListNullTerminated(Attribute) } - ** Attribute = { name:ULEB128, form:ULEB128, (val:SLEB128)? } - */ - - // unit index range to extract - U64 unit_idx_min = params->unit_idx_min; - U64 unit_idx_max = params->unit_idx_max; - - // empty unit list - DWARF_AbbrevUnit *unit_first = 0; - DWARF_AbbrevUnit *unit_last = 0; - U64 unit_count = 0; - B32 decoding_error = 0; - - // whole section loop - U64 unit_idx = 0; - U8 *ptr = data.str; - U8 *opl = data.str + data.size; - for (;ptr < opl; unit_idx += 1){ - - // early escape on unit idx - if (unit_idx > unit_idx_max){ - break; - } - - // determine whether to full parse this unit - B32 full_parse = (unit_idx_min <= unit_idx); - - // save unit offset - U64 abbrev_unit_offset = (U64)(ptr - data.str); - - // allocate unit - DWARF_AbbrevUnit *unit = push_array(arena, DWARF_AbbrevUnit, 1); - - // empty abbrev list - DWARF_AbbrevDecl *abbrev_first = 0; - DWARF_AbbrevDecl *abbrev_last = 0; - U64 abbrev_count = 0; - - // abbrev decl loop - for (;ptr < opl;){ - B32 success = 1; - - // mark abbrev_code field - U8 *abbrev_code_ptr = ptr; - DWARF_LEB128_ADV(ptr, opl, success); - - // null abbrev code means end of unit - if (success && *abbrev_code_ptr == 0){ - break; - } - - // mark tag - U8 *tag_ptr = ptr; - DWARF_LEB128_ADV(ptr, opl, success); - U8 *end_tag_ptr = ptr; - - // extract has_children - B8 has_children = 0; - if (ptr < opl){ - has_children = *ptr; - ptr += 1; - } - else{ - success = 0; - } - - // count attributes - U8 *attrib_start_ptr = ptr; - U32 attrib_count = 0; - B32 has_implicit_const = 0; - if (success){ - for (;;){ - // decode normal attribute layout - U8 *attrib_name = ptr; - DWARF_LEB128_ADV(ptr, opl, success); - U8 *attrib_form = ptr; - DWARF_LEB128_ADV(ptr, opl, success); - - // handle special case implicit_const - if (success && *attrib_form == (U8)DWARF_AttributeForm_implicit_const){ - DWARF_LEB128_ADV(ptr, opl, success); - has_implicit_const = 1; - } - - // termination conditions - if (ptr == opl || - (*attrib_name == 0 && *attrib_form == 0)){ - break; - } - - // increment - attrib_count += 1; - } - } - - // build the abbreviation declaration - if (full_parse && success){ - - // allocate abbrev - DWARF_AbbrevDecl *abbrev = push_array(arena, DWARF_AbbrevDecl, 1); - DWARF_AbbrevAttribSpec *attribs = - push_array_no_zero(arena, DWARF_AbbrevAttribSpec, attrib_count); - U64 *implicit_const = 0; - if (has_implicit_const){ - implicit_const = push_array(arena, U64, attrib_count); - } - - // extract abbrev fields - U32 abbrev_code = dwarf_leb128_decode_U32(abbrev_code_ptr, tag_ptr); - U32 tag = dwarf_leb128_decode_U32(tag_ptr, end_tag_ptr); - - U8 *attrib_ptr = attrib_start_ptr; - DWARF_AbbrevAttribSpec *attrib = attribs; - for (U32 i = 0; i < attrib_count; i += 1, attrib += 1){ - // mark attribute fields - U8 *attrib_name = attrib_ptr; - DWARF_LEB128_ADV_NOCAP(attrib_ptr); - U8 *attrib_form = attrib_ptr; - DWARF_LEB128_ADV_NOCAP(attrib_ptr); - - // extract attribute fields - U32 name = dwarf_leb128_decode_U32(attrib_name, attrib_form); - U32 form = dwarf_leb128_decode_U32(attrib_form, attrib_ptr); - - // fill attribute spec - attrib->name = (DWARF_AttributeName)name; - attrib->form = (DWARF_AttributeForm)form; - - // handle special case implicit_const - if (form == DWARF_AttributeForm_implicit_const){ - U8 *attrib_value = attrib_ptr; - DWARF_LEB128_ADV_NOCAP(attrib_ptr); - S64 value = dwarf_leb128_decode_S64(attrib_form, attrib_ptr); - implicit_const[i] = value; - } - } - - // fill abbreviation - SLLQueuePush(abbrev_first, abbrev_last, abbrev); - abbrev_count += 1; - abbrev->abbrev_code = abbrev_code; - abbrev->tag = (DWARF_Tag)tag; - abbrev->has_children = has_children; - abbrev->attrib_count = attrib_count; - abbrev->attrib_specs = attribs; - abbrev->implicit_const = implicit_const; - } - - // handle failure - if (!success){ - // TODO: emit error message - decoding_error = 1; - goto done_parse; - } - } - - // fill unit - if (full_parse){ - SLLQueuePush(unit_first, unit_last, unit); - unit_count += 1; - unit->offset = abbrev_unit_offset; - unit->first = abbrev_first; - unit->last = abbrev_last; - unit->count = abbrev_count; - } - } - - done_parse:; - - // fill result - DWARF_AbbrevParsed *result = push_array(arena, DWARF_AbbrevParsed, 1); - result->unit_first = unit_first; - result->unit_last = unit_last; - result->unit_count = unit_count; - result->decoding_error = decoding_error; - return(result); -} -#endif diff --git a/src/rdi_from_dwarf/rdi_dwarf.h b/src/rdi_from_dwarf/rdi_dwarf.h deleted file mode 100644 index 405cd817..00000000 --- a/src/rdi_from_dwarf/rdi_dwarf.h +++ /dev/null @@ -1,1493 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_DWARF_H -#define RDI_DWARF_H - -// https://dwarfstd.org/doc/DWARF4.pdf -// https://dwarfstd.org/doc/DWARF5.pdf - -// TODO(allen): -// [ ] function to parse info just for unit headers & root attributes -// [ ] put together unit info from all sections in one structure -// [ ] actually check version numbers in unit header parsers - -#pragma pack(push,1) - -//////////////////////////////// -//~ Dwarf Format Code X Lists - -// unit type X(name, code) -#define DWARF_UnitTypeXList(X)\ -X(null, 0x00)\ -X(compile, 0x01)\ -X(type, 0x02)\ -X(partial, 0x03)\ -X(skeleton, 0x04)\ -X(split_compile, 0x05)\ -X(split_type, 0x06)\ -X(lo_user, 0x80)\ -X(hi_user, 0xff) - -typedef enum DWARF_UnitType{ -#define X(N,C) DWARF_UnitType_##N = C, - DWARF_UnitTypeXList(X) -#undef X -} DWARF_UnitType; - - -// tag X(name, code) -#define DWARF_TagXList(X)\ -X(null, 0x00)\ -X(array_type, 0x01)\ -X(class_type, 0x02)\ -X(entry_point, 0x03)\ -X(enumeration_type, 0x04)\ -X(formal_parameter, 0x05)\ -X(imported_declaration, 0x08)\ -X(label, 0x0a)\ -X(lexical_block, 0x0b)\ -X(member, 0x0d)\ -X(pointer_type, 0x0f)\ -X(reference_type, 0x10)\ -X(compile_unit, 0x11)\ -X(string_type, 0x12)\ -X(structure_type, 0x13)\ -X(subroutine_type, 0x15)\ -X(typedef, 0x16)\ -X(union_type, 0x17)\ -X(unspecified_parameters, 0x18)\ -X(variant, 0x19)\ -X(common_block, 0x1a)\ -X(common_inclusion, 0x1b)\ -X(inheritance, 0x1c)\ -X(inlined_subroutine, 0x1d)\ -X(module, 0x1e)\ -X(ptr_to_member_type, 0x1f)\ -X(set_type, 0x20)\ -X(subrange_type, 0x21)\ -X(with_stmt, 0x22)\ -X(access_declaration, 0x23)\ -X(base_type, 0x24)\ -X(catch_block, 0x25)\ -X(const_type, 0x26)\ -X(constant, 0x27)\ -X(enumerator, 0x28)\ -X(file_type, 0x29)\ -X(friend, 0x2a)\ -X(namelist, 0x2b)\ -X(namelist_item, 0x2c)\ -X(packed_type, 0x2d)\ -X(subprogram, 0x2e)\ -X(template_type_parameter, 0x2f)\ -X(template_value_parameter, 0x30)\ -X(thrown_type, 0x31)\ -X(try_block, 0x32)\ -X(variant_part, 0x33)\ -X(variable, 0x34)\ -X(volatile_type, 0x35)\ -X(dwarf_procedure, 0x36)\ -X(restrict_type, 0x37)\ -X(interface_type, 0x38)\ -X(namespace, 0x39)\ -X(imported_module, 0x3a)\ -X(unspecified_type, 0x3b)\ -X(partial_unit, 0x3c)\ -X(imported_unit, 0x3d)\ -X(condition, 0x3f)\ -X(shared_type, 0x40)\ -X(type_unit, 0x41)\ -X(rvalue_reference_type, 0x42)\ -X(template_alias, 0x43)\ -X(coarray_type, 0x44)\ -X(generic_subrange, 0x45)\ -X(dynamic_type, 0x46)\ -X(atomic_type, 0x47)\ -X(call_site, 0x48)\ -X(call_site_parameter, 0x49)\ -X(skeleton_unit, 0x4a)\ -X(immutable_type, 0x4b)\ -X(lo_user, 0x4080)\ -X(hi_user, 0xffff) - -typedef enum DWARF_Tag{ -#define X(N,C) DWARF_Tag_##N = C, - DWARF_TagXList(X) -#undef X -} DWARF_Tag; - - -// attribute classes: X(name,code) -#define DWARF_AttributeClassXList(X)\ -X(address, 0)\ -X(addrptr, 1)\ -X(block, 2)\ -X(constant, 3)\ -X(exprloc, 4)\ -X(flag, 5)\ -X(lineptr, 6)\ -X(loclist, 7)\ -X(loclistsptr, 8)\ -X(macptr, 9)\ -X(reference, 10)\ -X(rnglist, 11)\ -X(rnglistsptr, 12)\ -X(string, 13)\ -X(stroffsetsptr, 14) - -typedef U32 DWARF_AttributeClassFlags; -enum{ -#define X(N,C) DWARF_AttributeClassFlag_##N = (1 << C), - DWARF_AttributeClassXList(X) -#undef X - - DWARF_AttributeClassFlag_0 = 0, - DWARF_AttributeClassFlag_specialcase = ~0, - DWARF_AttributeClassFlag_sec_offset_classes = - (DWARF_AttributeClassFlag_addrptr | - DWARF_AttributeClassFlag_lineptr | - DWARF_AttributeClassFlag_loclist | - DWARF_AttributeClassFlag_loclistsptr | - DWARF_AttributeClassFlag_macptr | - DWARF_AttributeClassFlag_rnglist | - DWARF_AttributeClassFlag_rnglistsptr | - DWARF_AttributeClassFlag_stroffsetsptr | - 0), - -}; - - -// attribute name: X(name, code, classflag1, classflag2, classflag3, classflag4) -#define DWARF_AttributeNameXList(X)\ -X(null, 0x00, 0, 0, 0, 0)\ -X(sibling, 0x01, reference, 0, 0, 0)\ -X(location, 0x02, exprloc, loclist, 0, 0)\ -X(name, 0x03, string, 0, 0, 0)\ -X(ordering, 0x09, constant, 0, 0, 0)\ -X(byte_size, 0x0b, constant, exprloc, reference, 0)\ -X(bit_size, 0x0d, constant, exprloc, reference, 0)\ -X(stmt_list, 0x10, lineptr, 0, 0, 0)\ -X(low_pc, 0x11, address, 0, 0, 0)\ -X(high_pc, 0x12, address, constant, 0, 0)\ -X(language, 0x13, constant, 0, 0, 0)\ -X(discr, 0x15, reference, 0, 0, 0)\ -X(discr_value, 0x16, constant, 0, 0, 0)\ -X(visibility, 0x17, constant, 0, 0, 0)\ -X(import, 0x18, reference, 0, 0, 0)\ -X(string_length, 0x19, exprloc, loclist, reference, 0)\ -X(common_reference, 0x1a, reference, 0, 0, 0)\ -X(comp_dir, 0x1b, string, 0, 0, 0)\ -X(const_value, 0x1c, block, constant, string, 0)\ -X(containing_type, 0x1d, reference, 0, 0, 0)\ -X(default_value, 0x1e, constant, reference, flag, 0)\ -X(inline, 0x20, constant, 0, 0, 0)\ -X(is_optional, 0x21, flag, 0, 0, 0)\ -X(lower_bound, 0x22, constant, exprloc, reference, 0)\ -X(producer, 0x25, string, 0, 0, 0)\ -X(prototyped, 0x27, flag, 0, 0, 0)\ -X(return_addr, 0x2a, exprloc, loclist, 0, 0)\ -X(start_scope, 0x2c, constant, rnglist, 0, 0)\ -X(bit_stride, 0x2e, constant, exprloc, reference, 0)\ -X(upper_bound, 0x2f, constant, exprloc, reference, 0)\ -X(abstract_origin, 0x31, reference, 0, 0, 0)\ -X(accessibility, 0x32, constant, 0, 0, 0)\ -X(address_class, 0x33, constant, 0, 0, 0)\ -X(artificial, 0x34, flag, 0, 0, 0)\ -X(base_types, 0x35, reference, 0, 0, 0)\ -X(calling_convention, 0x36, constant, 0, 0, 0)\ -X(count, 0x37, constant, exprloc, reference, 0)\ -X(data_member_location, 0x38, constant, exprloc, loclist, 0)\ -X(decl_column, 0x39, constant, 0, 0, 0)\ -X(decl_file, 0x3a, constant, 0, 0, 0)\ -X(decl_line, 0x3b, constant, 0, 0, 0)\ -X(declaration, 0x3c, flag, 0, 0, 0)\ -X(discr_list, 0x3d, block, 0, 0, 0)\ -X(encoding, 0x3e, constant, 0, 0, 0)\ -X(external, 0x3f, flag, 0, 0, 0)\ -X(frame_base, 0x40, exprloc, loclist, 0, 0)\ -X(friend, 0x41, reference, 0, 0, 0)\ -X(identifier_case, 0x42, constant, 0, 0, 0)\ -X(namelist_item, 0x44, reference, 0, 0, 0)\ -X(priority, 0x45, reference, 0, 0, 0)\ -X(segment, 0x46, exprloc, loclist, 0, 0)\ -X(specification, 0x47, reference, 0, 0, 0)\ -X(static_link, 0x48, exprloc, loclist, 0, 0)\ -X(type, 0x49, reference, 0, 0, 0)\ -X(use_location, 0x4a, exprloc, loclist, 0, 0)\ -X(variable_parameter, 0x4b, flag, 0, 0, 0)\ -X(virtuality, 0x4c, constant, 0, 0, 0)\ -X(vtable_elem_location, 0x4d, exprloc, loclist, 0, 0)\ -X(allocated, 0x4e, constant, exprloc, reference, 0)\ -X(associated, 0x4f, constant, exprloc, reference, 0)\ -X(data_location, 0x50, exprloc, 0, 0, 0)\ -X(byte_stride, 0x51, constant, exprloc, reference, 0)\ -X(entry_pc, 0x52, address, constant, 0, 0)\ -X(use_UTF8, 0x53, flag, 0, 0, 0)\ -X(extension, 0x54, reference, 0, 0, 0)\ -X(ranges, 0x55, rnglist, 0, 0, 0)\ -X(trampoline, 0x56, address, flag, reference, string)\ -X(call_column, 0x57, constant, 0, 0, 0)\ -X(call_file, 0x58, constant, 0, 0, 0)\ -X(call_line, 0x59, constant, 0, 0, 0)\ -X(description, 0x5a, string, 0, 0, 0)\ -X(binary_scale, 0x5b, constant, 0, 0, 0)\ -X(decimal_scale, 0x5c, constant, 0, 0, 0)\ -X(small, 0x5d, reference, 0, 0, 0)\ -X(decimal_sign, 0x5e, constant, 0, 0, 0)\ -X(digit_count, 0x5f, constant, 0, 0, 0)\ -X(picture_string, 0x60, string, 0, 0, 0)\ -X(mutable, 0x61, flag, 0, 0, 0)\ -X(threads_scaled, 0x62, flag, 0, 0, 0)\ -X(explicit, 0x63, flag, 0, 0, 0)\ -X(object_pointer, 0x64, reference, 0, 0, 0)\ -X(endianity, 0x65, constant, 0, 0, 0)\ -X(elemental, 0x66, flag, 0, 0, 0)\ -X(pure, 0x67, flag, 0, 0, 0)\ -X(recursive, 0x68, flag, 0, 0, 0)\ -X(signature, 0x69, reference, 0, 0, 0)\ -X(main_subprogram, 0x6a, flag, 0, 0, 0)\ -X(data_bit_offset, 0x6b, constant, 0, 0, 0)\ -X(const_expr, 0x6c, flag, 0, 0, 0)\ -X(enum_class, 0x6d, flag, 0, 0, 0)\ -X(linkage_name, 0x6e, string, 0, 0, 0)\ -X(string_length_bit_size, 0x6f, constant, 0, 0, 0)\ -X(string_length_byte_size, 0x70, constant, 0, 0, 0)\ -X(rank, 0x71, constant, exprloc, 0, 0)\ -X(str_offsets_base, 0x72, stroffsetsptr, 0, 0, 0)\ -X(addr_base, 0x73, addrptr, 0, 0, 0)\ -X(rnglists_base, 0x74, rnglistsptr, 0, 0, 0)\ -X(dwo_name, 0x76, string, 0, 0, 0)\ -X(reference, 0x77, flag, 0, 0, 0)\ -X(rvalue_reference, 0x78, flag, 0, 0, 0)\ -X(macros, 0x79, macptr, 0, 0, 0)\ -X(call_all_calls, 0x7a, flag, 0, 0, 0)\ -X(call_all_source_calls, 0x7b, flag, 0, 0, 0)\ -X(call_all_tail_calls, 0x7c, flag, 0, 0, 0)\ -X(call_return_pc, 0x7d, address, 0, 0, 0)\ -X(call_value, 0x7e, exprloc, 0, 0, 0)\ -X(call_origin, 0x7f, exprloc, 0, 0, 0)\ -X(call_parameter, 0x80, reference, 0, 0, 0)\ -X(call_pc, 0x81, address, 0, 0, 0)\ -X(call_tail_call, 0x82, flag, 0, 0, 0)\ -X(call_target, 0x83, exprloc, 0, 0, 0)\ -X(call_target_clobbered, 0x84, exprloc, 0, 0, 0)\ -X(call_data_location, 0x85, exprloc, 0, 0, 0)\ -X(call_data_value, 0x86, exprloc, 0, 0, 0)\ -X(noreturn, 0x87, flag, 0, 0, 0)\ -X(alignment, 0x88, constant, 0, 0, 0)\ -X(export_symbols, 0x89, flag, 0, 0, 0)\ -X(deleted, 0x8a, flag, 0, 0, 0)\ -X(defaulted, 0x8b, constant, 0, 0, 0)\ -X(loclists_base, 0x8c, loclistsptr, 0, 0, 0)\ -X(lo_user, 0x2000, 0, 0, 0, 0)\ -X(hi_user, 0x3fff, 0, 0, 0, 0) - -typedef enum DWARF_AttributeName{ -#define X(N,C,f1,f2,f3,f4) DWARF_AttributeName_##N = C, - DWARF_AttributeNameXList(X) -#undef X -} DWARF_AttributeName; - - -// attribute forms: X(name, code, classflag) -#define DWARF_AttributeFormXList(X)\ -X(null, 0x00, 0)\ -X(addr, 0x01, address)\ -X(block2, 0x03, block)\ -X(block4, 0x04, block)\ -X(data2, 0x05, constant)\ -X(data4, 0x06, constant)\ -X(data8, 0x07, constant)\ -X(string, 0x08, string)\ -X(block, 0x09, block)\ -X(block1, 0x0a, block)\ -X(data1, 0x0b, constant)\ -X(flag, 0x0c, flag)\ -X(sdata, 0x0d, constant)\ -X(strp, 0x0e, string)\ -X(udata, 0x0f, constant)\ -X(ref_addr, 0x10, reference)\ -X(ref1, 0x11, reference)\ -X(ref2, 0x12, reference)\ -X(ref4, 0x13, reference)\ -X(ref8, 0x14, reference)\ -X(ref_udata, 0x15, reference)\ -X(indirect, 0x16, specialcase)\ -X(sec_offset, 0x17, sec_offset_classes)\ -X(exprloc, 0x18, exprloc)\ -X(flag_present, 0x19, flag)\ -X(strx, 0x1a, string)\ -X(addrx, 0x1b, address)\ -X(ref_sup4, 0x1c, reference)\ -X(strp_sup, 0x1d, string)\ -X(data16, 0x1e, constant)\ -X(line_strp, 0x1f, string)\ -X(ref_sig8, 0x20, reference)\ -X(implicit_const, 0x21, specialcase)\ -X(loclistx, 0x22, loclist)\ -X(rnglistx, 0x23, rnglist)\ -X(ref_sup8, 0x24, reference)\ -X(strx1, 0x25, string)\ -X(strx2, 0x26, string)\ -X(strx3, 0x27, string)\ -X(strx4, 0x28, string)\ -X(addrx1, 0x29, address)\ -X(addrx2, 0x2a, address)\ -X(addrx3, 0x2b, address)\ -X(addrx4, 0x2c, address) - -typedef enum DWARF_AttributeForm{ -#define X(N,C,f) DWARF_AttributeForm_##N = C, - DWARF_AttributeFormXList(X) -#undef X -} DWARF_AttributeForm; - - -// ops: X(name, code, opnum) -#define DWARF_OpXList(X)\ -X(addr, 0x03, 1)\ -X(deref, 0x06, 0)\ -X(const1u, 0x08, 1)\ -X(const1s, 0x09, 1)\ -X(const2u, 0x0a, 1)\ -X(const2s, 0x0b, 1)\ -X(const4u, 0x0c, 1)\ -X(const4s, 0x0d, 1)\ -X(const8u, 0x0e, 1)\ -X(const8s, 0x0f, 1)\ -X(constu, 0x10, 1)\ -X(consts, 0x11, 1)\ -X(dup, 0x12, 0)\ -X(drop, 0x13, 0)\ -X(over, 0x14, 0)\ -X(pick, 0x15, 1)\ -X(swap, 0x16, 0)\ -X(rot, 0x17, 0)\ -X(xderef, 0x18, 0)\ -X(abs, 0x19, 0)\ -X(and, 0x1a, 0)\ -X(div, 0x1b, 0)\ -X(minus, 0x1c, 0)\ -X(mod, 0x1d, 0)\ -X(mul, 0x1e, 0)\ -X(neg, 0x1f, 0)\ -X(not, 0x20, 0)\ -X(or, 0x21, 0)\ -X(plus, 0x22, 0)\ -X(plus_uconst, 0x23, 1)\ -X(shl, 0x24, 0)\ -X(shr, 0x25, 0)\ -X(shra, 0x26, 0)\ -X(xor, 0x27, 0)\ -X(bra, 0x28, 1)\ -X(eq, 0x29, 0)\ -X(ge, 0x2a, 0)\ -X(gt, 0x2b, 0)\ -X(le, 0x2c, 0)\ -X(lt, 0x2d, 0)\ -X(ne, 0x2e, 0)\ -X(skip, 0x2f, 1)\ -X(lit0, 0x30, 0)\ -X(lit1, 0x31, 0)\ -X(lit31, 0x4f, 0)\ -X(reg0, 0x50, 0)\ -X(reg1, 0x51, 0)\ -X(reg31, 0x6f, 0)\ -X(breg0, 0x70, 1)\ -X(breg1, 0x71, 1)\ -X(breg31, 0x8f, 1)\ -X(regx, 0x90, 1)\ -X(fbreg, 0x91, 1)\ -X(bregx, 0x92, 2)\ -X(piece, 0x93, 1)\ -X(deref_size, 0x94, 1)\ -X(xderef_size, 0x95, 1)\ -X(nop, 0x96, 0)\ -X(push_object_address, 0x97, 0)\ -X(call2, 0x98, 1)\ -X(call4, 0x99, 1)\ -X(call_ref, 0x9a, 1)\ -X(form_tls_address, 0x9b, 0)\ -X(call_frame_cfa, 0x9c, 0)\ -X(bit_piece, 0x9d, 2)\ -X(implicit_value, 0x9e, 2)\ -X(stack_value, 0x9f, 0)\ -X(implicit_pointer, 0xa0, 2)\ -X(addrx, 0xa1, 1)\ -X(constx, 0xa2, 1)\ -X(entry_value, 0xa3, 2)\ -X(const_type, 0xa4, 3)\ -X(regval_type, 0xa5, 2)\ -X(deref_type, 0xa6, 2)\ -X(xderef_type, 0xa7, 2)\ -X(convert, 0xa8, 1)\ -X(reinterpret, 0xa9, 1)\ -X(lo_user, 0xe0, 0)\ -X(hi_user, 0xff, 0) - -typedef enum DWARF_Op{ -#define X(N,C,k) DWARF_Op_##N = C, - DWARF_OpXList(X) -#undef X -} DWARF_Op; - - -// location list entry: X(name, code) -#define DWARF_LocationListEntryXList(X)\ -X(end_of_list, 0x00)\ -X(base_addressx, 0x01)\ -X(startx_endx, 0x02)\ -X(startx_length, 0x03)\ -X(offset_pair, 0x04)\ -X(default_location, 0x05)\ -X(base_address, 0x06)\ -X(start_end, 0x07)\ -X(start_length, 0x08) - -typedef enum DWARF_LocationListEntry{ -#define X(N,C) DWARF_LocationListEntry_##N = C, - DWARF_LocationListEntryXList(X) -#undef X -} DWARF_LocationListEntry; - - -// base type: X(name, code) -#define DWARF_BaseTypeXList(X)\ -X(address, 0x01)\ -X(boolean, 0x02)\ -X(complex_float, 0x03)\ -X(float, 0x04)\ -X(signed, 0x05)\ -X(signed_char, 0x06)\ -X(unsigned, 0x07)\ -X(unsigned_char, 0x08)\ -X(imaginary_float, 0x09)\ -X(packed_decimal, 0x0a)\ -X(numeric_string, 0x0b)\ -X(edited, 0x0c)\ -X(signed_fixed, 0x0d)\ -X(unsigned_fixed, 0x0e)\ -X(decimal_float, 0x0f)\ -X(UTF, 0x10)\ -X(UCS, 0x11)\ -X(ASCII, 0x12)\ -X(lo_user, 0x80)\ -X(hi_user, 0xff) - -typedef enum DWARF_BaseType{ -#define X(N,C) DWARF_BaseType_##N = C, - DWARF_BaseTypeXList(X) -#undef X -} DWARF_BaseType; - - -// decimal sign: X(name, code) -#define DWARF_DecimalSignXList(X)\ -X(unsigned, 0x01)\ -X(leading_overpunch, 0x02)\ -X(trailing_overpunch, 0x03)\ -X(leading_separate, 0x04)\ -X(trailing_separate, 0x05) - -typedef enum DWARF_DecimalSign{ -#define X(N,C) DWARF_DecimalSign_##N = C, - DWARF_DecimalSignXList(X) -#undef X -} DWARF_DecimalSign; - - -// endianity: X(name, code) -#define DWARF_EndianityXList(X)\ -X(default, 0x00)\ -X(big, 0x01)\ -X(little, 0x02)\ -X(lo_user, 0x40)\ -X(hi_user, 0xff) - -typedef enum DWARF_Endianity{ -#define X(N,C) DWARF_Endianity_##N = C, - DWARF_EndianityXList(X) -#undef X -} DWARF_Endianity; - - -// access: X(name, code) -#define DWARF_AccessXList(X)\ -X(public, 0x01)\ -X(protected, 0x02)\ -X(private, 0x03) - -typedef enum DWARF_Access{ -#define X(N,C) DWARF_Access_##N = C, - DWARF_AccessXList(X) -#undef X -} DWARF_Access; - - -// visibility: X(name, code) -#define DWARF_VisibilityXList(X)\ -X(local, 0x01)\ -X(exported, 0x02)\ -X(qualified, 0x03) - -typedef enum DWARF_Visibility{ -#define X(N,C) DWARF_Visibility_##N = C, - DWARF_VisibilityXList(X) -#undef X -} DWARF_Visibility; - - -// virtuality: X(name, code) -#define DWARF_VirtualityXList(X)\ -X(none, 0x00)\ -X(virtual, 0x01)\ -X(pure_virtual, 0x02) - -typedef enum DWARF_Virtuality{ -#define X(N,C) DWARF_Virtuality_##N = C, - DWARF_VirtualityXList(X) -#undef X -} DWARF_Virtuality; - - -// language: X(name, code, deflowerbound) -#define DWARF_LanguageXList(X)\ -X(C89, 0x0001, 0)\ -X(C, 0x0002, 0)\ -X(Ada83, 0x0003, 1)\ -X(C_plus_plus, 0x0004, 0)\ -X(Cobol74, 0x0005, 1)\ -X(Cobol85, 0x0006, 1)\ -X(Fortran77, 0x0007, 1)\ -X(Fortran90, 0x0008, 1)\ -X(Pascal83, 0x0009, 1)\ -X(Modula2, 0x000a, 1)\ -X(Java, 0x000b, 0)\ -X(C99, 0x000c, 0)\ -X(Ada95, 0x000d, 1)\ -X(Fortran95, 0x000e, 1)\ -X(PLI, 0x000f, 1)\ -X(ObjC, 0x0010, 0)\ -X(ObjC_plus_plus, 0x0011, 0)\ -X(UPC, 0x0012, 0)\ -X(D, 0x0013, 0)\ -X(Python, 0x0014, 0)\ -X(OpenCL, 0x0015, 0)\ -X(Go, 0x0016, 0)\ -X(Modula3, 0x0017, 1)\ -X(Haskell, 0x0018, 0)\ -X(C_plus_plus_03, 0x0019, 0)\ -X(C_plus_plus_11, 0x001a, 0)\ -X(OCaml, 0x001b, 0)\ -X(Rust, 0x001c, 0)\ -X(C11, 0x001d, 0)\ -X(Swift, 0x001e, 0)\ -X(Julia, 0x001f, 1)\ -X(Dylan, 0x0020, 0)\ -X(C_plus_plus_14, 0x0021, 0)\ -X(Fortran03, 0x0022, 1)\ -X(Fortran08, 0x0023, 1)\ -X(RenderScript, 0x0024, 0)\ -X(BLISS, 0x0025, 0)\ -X(lo_user, 0x8000, 0)\ -X(hi_user, 0xffff, 0) - -typedef enum DWARF_Language{ -#define X(N,C,k) DWARF_Language_##N = C, - DWARF_LanguageXList(X) -#undef X -} DWARF_Language; - - -// identifier case: X(name, code) -#define DWARF_IdentifierCaseXList(X)\ -X(case_sensitive, 0x00)\ -X(up_case, 0x01)\ -X(down_case, 0x02)\ -X(case_insensitive, 0x03) - -typedef enum DWARF_IdentifierCase{ -#define X(N,C) DWARF_IdentifierCase_##N = C, - DWARF_IdentifierCaseXList(X) -#undef X -} DWARF_IdentifierCase; - - -// calling convention: X(name, code) -#define DWARF_CallingConventionXList(X)\ -X(normal, 0x01)\ -X(program, 0x02)\ -X(nocall, 0x03)\ -X(pass_by_reference, 0x04)\ -X(pass_by_value, 0x05)\ -X(lo_user, 0x40)\ -X(hi_user, 0xff) - -typedef enum DWARF_CallingConvention{ -#define X(N,C) DWARF_CallingConvention_##N = C, - DWARF_CallingConventionXList(X) -#undef X -} DWARF_CallingConvention; - - -// inline: X(name, code) -#define DWARF_InlineXList(X)\ -X(not_inlined, 0x00)\ -X(inlined, 0x01)\ -X(declared_not_inlined, 0x02)\ -X(declared_inlined, 0x03) - -typedef enum DWARF_Inline{ -#define X(N,C) DWARF_Inline_##N = C, - DWARF_InlineXList(X) -#undef X -} DWARF_Inline; - - -// array ordering: X(name, code) -#define DWARF_ArrayOrderingXList(X)\ -X(row_major, 0x00)\ -X(col_major, 0x01) - -typedef enum DWARF_ArrayOrdering{ -#define X(N,C) DWARF_ArrayOrdering_##N = C, - DWARF_ArrayOrderingXList(X) -#undef X -} DWARF_ArrayOrdering; - - -// discriminant: X(name, code) -#define DWARF_DiscriminantXList(X)\ -X(label, 0x00)\ -X(range, 0x01) - -typedef enum DWARF_Discriminant{ -#define X(N,C) DWARF_Discriminant_##N = C, - DWARF_DiscriminantXList(X) -#undef X -} DWARF_Discriminant; - - -// name index: X(name, code) -#define DWARF_NameIndexXList(X)\ -X(compile_unit, 1)\ -X(type_unit, 2)\ -X(die_offset, 3)\ -X(parent, 4)\ -X(type_hash, 5)\ -X(lo_user, 0x2000)\ -X(hi_user, 0x3fff) - -typedef enum DWARF_NameIndex{ -#define X(N,C) DWARF_NameIndex_##N = C, - DWARF_NameIndexXList(X) -#undef X -} DWARF_NameIndex; - - -// defaulted: X(name, code) -#define DWARF_DefaultedXList(X)\ -X(no, 0x00)\ -X(in_class, 0x01)\ -X(out_of_class, 0x02) - -typedef enum DWARF_Defaulted{ -#define X(N,C) DWARF_Defaulted_##N = C, - DWARF_DefaultedXList(X) -#undef X -} DWARF_Defaulted; - -// call frame instruction: X(N, hi2bits, matchlow, low6bits, operand1, operand2) -// "CFA" -#define DWARF_CallFrameInsnXList(X)\ -X(advance_loc, 0x1, 0, 0, NULL, NULL)\ -X(offset, 0x2, 0, 0, ULEB, NULL)\ -X(restore, 0x3, 0, 0, NULL, NULL)\ -X(nop, 0x0, 1, 0, NULL, NULL)\ -X(set_loc, 0x0, 1, 0x01, ADDRESS, NULL)\ -X(advance_loc1, 0x0, 1, 0x02, 1BYTE, NULL)\ -X(advance_loc2, 0x0, 1, 0x03, 2BYTE, NULL)\ -X(advance_loc4, 0x0, 1, 0x04, 4BYTE, NULL)\ -X(offset_extended, 0x0, 1, 0x05, ULEB, ULEB)\ -X(restore_extended, 0x0, 1, 0x06, ULEB, NULL)\ -X(undefined, 0x0, 1, 0x07, ULEB, NULL)\ -X(same_value, 0x0, 1, 0x08, ULEB, NULL)\ -X(register, 0x0, 1, 0x09, ULEB, ULEB)\ -X(remember_state, 0x0, 1, 0x0a, NULL, NULL)\ -X(restore_state, 0x0, 1, 0x0b, NULL, NULL)\ -X(def_cfa, 0x0, 1, 0x0c, ULEB, ULEB)\ -X(def_cfa_register, 0x0, 1, 0x0d, ULEB, NULL)\ -X(def_cfa_offset, 0x0, 1, 0x0e, ULEB, NULL)\ -X(def_cfa_expression,0x0, 1, 0x0f, BLOCK, NULL)\ -X(expression, 0x0, 1, 0x10, ULEB, BLOCK)\ -X(offset_extended_sf,0x0, 1, 0x11, ULEB, SLEB)\ -X(def_cfa_sf, 0x0, 1, 0x12, ULEB, SLEB)\ -X(def_cfa_offset_sf, 0x0, 1, 0x13, SLEB, NULL)\ -X(val_offset, 0x0, 1, 0x14, ULEB, ULEB)\ -X(val_offset_sf, 0x0, 1, 0x15, ULEB, SLEB)\ -X(val_expression, 0x0, 1, 0x16, ULEB, BLOCK)\ -X(lo_user, 0x0, 1, 0x1c, NULL, NULL)\ -X(hi_user, 0x0, 1, 0x3f, NULL, NULL) - -// line number encoding codes -// (DWARF4.pdf + 7.21) (DWARF5.pdf + 7.22) - -// X(name, code) (V4 & V5) -#define DWARF_LineStdOpXList(X) \ -X(copy, 0x01)\ -X(advance_pc, 0x02)\ -X(advance_line, 0x03)\ -X(set_file, 0x04)\ -X(set_column, 0x05)\ -X(negate_stmt, 0x06)\ -X(set_basic_block, 0x07)\ -X(const_add_pc, 0x08)\ -X(fixed_advance_pc, 0x09)\ -X(set_prologue_end, 0x0a)\ -X(set_epilogue_begin, 0x0b)\ -X(set_isa, 0x0c) - -typedef enum DWARF_LineStdOp{ -#define X(N,C) DWARF_LineStdOp_##N = C, - DWARF_LineStdOpXList(X) -#undef X -} DWARF_LineStdOp; - -// X(name, code) (V4 & V5) -#define DWARF_LineExtOpXList(X) \ -X(end_sequence, 0x01)\ -X(set_address, 0x02)\ -X(define_file, 0x03)\ -X(set_discriminator, 0x04)\ -X(lo_user, 0x80)\ -X(hi_user, 0xff) - -typedef enum DWARF_LineExtOp{ -#define X(N,C) DWARF_LineExtOp_##N = C, - DWARF_LineExtOpXList(X) -#undef X -} DWARF_LineExtOp; - -// X(name, code) (V5) -#define DWARF_LineEntryFormatXList(X) \ -X(path, 0x1)\ -X(directory_index, 0x2)\ -X(timestamp, 0x3)\ -X(size, 0x4)\ -X(MD5, 0x5)\ -X(lo_user, 0x2000)\ -X(hi_user, 0x3fff) - -typedef enum DWARF_LineEntryFormat{ -#define X(N,C) DWARF_LineEntryFormat_##N = C, - DWARF_LineEntryFormatXList(X) -#undef X -} DWARF_LineEntryFormat; - -//////////////////////////////// -//~ Dwarf Parser Codes and Data Tables - -#define DWARF_SECTION_NAME_VARIANT_COUNT 3 - -// X(section_code_name, versionflags, section_name0, section_name1, section_name2) -#define DWARF_SectionNameXList(X,V4,V5)\ -X(Null, 0, "", "", "")\ -X(Loc, V4, ".debug_loc", ".debug_loc.dwo", "__debug_loc")\ -X(Str, V4|V5, ".debug_str", ".debug_str.dwo", "__debug_str")\ -X(LineStr, V5, ".debug_line_str", ".debug_line_str.dwo", "__debug_line_str")\ -X(CmpUnitIdx, V5, ".debug_cu_index", ".debug_cu_index.dwo", "__debug_cu_index")\ -X(TypeIdx, V5, ".debug_tu_index", ".debug_tu_index.dwo", "__debug_tu_index")\ -X(Supplement, V5, ".debug_sup", ".debug_sup.dwo", "__debug_sup")\ -X(Info, V4|V5, ".debug_info", ".debug_info.dwo", "__debug_info")\ -X(Abbrev, V4|V5, ".debug_abbrev", ".debug_abbrev.dwo", "__debug_abbrev")\ -X(PubNames, V4, ".debug_pubnames", ".debug_pubnames.dwo", "__debug_pubnames")\ -X(PubTypes, V4, ".debug_pubtypes", ".debug_pubtypes.dwo", "__debug_pubtypes")\ -X(Names, V5, ".debug_names", ".debug_names.dwo", "__debug_names")\ -X(Aranges, V4|V5, ".debug_aranges", ".debug_aranges.dwo", "__debug_aranges")\ -X(Line, V4|V5, ".debug_line", ".debug_line.dwo", "__debug_line")\ -X(MacInfo, V4, ".debug_macinfo", ".debug_macinfo.dwo", "__debug_macinfo")\ -X(Macro, V5, ".debug_macro", ".debug_macro.dwo", "__debug_macro")\ -X(Frame, V4|V5, ".debug_frame", ".debug_frame.dwo", "__debug_frame")\ -X(Ranges, V4, ".debug_ranges", ".debug_ranges.dwo", "__debug_ranges")\ -X(StrOffsets, V5, ".debug_str_offsets", ".debug_str_offsets.dwo", "__debug_str_offsets")\ -X(Addr, V5, ".debug_addr", ".debug_addr.dwo", "__debug_addr")\ -X(RngLists, V5, ".debug_rnglists", ".debug_rnglists.dwo", "__debug_rnglists")\ -X(LocLists, V5, ".debug_loclists", ".debug_loclists.dwo", "__debug_loclists") - - -typedef enum DWARF_SectionCode{ -#define X(c,vf,n0,n1,n2) DWARF_SectionCode_##c, - DWARF_SectionNameXList(X,0,0) -#undef X - DWARF_SectionCode_COUNT -} DWARF_SectionCode; - -typedef struct DWARF_SectionNameRow{ - String8 name[DWARF_SECTION_NAME_VARIANT_COUNT]; -} DWARF_SectionNameRow; - -read_only global DWARF_SectionNameRow dwarf_section_name_table[] = { -#define X(c,vf,n0,n1,n2) \ -{ { str8_lit_comp(n0), str8_lit_comp(n1), str8_lit_comp(n2) } }, - DWARF_SectionNameXList(X,0,0) -#undef X -}; - - -#pragma pack(pop) - - -//////////////////////////////// -//~ Dwarf Parser Types - -typedef struct DWARF_Parsed{ - ELF_Parsed *elf; - U32 debug_section_idx[DWARF_SectionCode_COUNT]; - String8 debug_section_name[DWARF_SectionCode_COUNT]; - String8 debug_data[DWARF_SectionCode_COUNT]; -} DWARF_Parsed; - - -// form decoding - -typedef struct DWARF_FormDecodeRules{ - union{ - // form decode fields - struct{ - U8 size; - B8 uleb128; - B8 sleb128; - B8 in_abbrev; - B8 auto_1; - B8 block; - B8 null_terminated; - }; - - // for alignment and padding to 8 - U64 x; - }; -} DWARF_FormDecodeRules; - -typedef struct DWARF_FormDecoded{ - U64 val; - U8 *dataptr; - B32 error; -} DWARF_FormDecoded; - - -// index section: .debug_cu_index .debug_tu_index -// (DWARF5.pdf + 7.3.5) - -// ** not implemented yet ** - -typedef struct DWARF_IndexParsed{ - U32 dummy; -} DWARF_IndexParsed; - - -// supplementary section: .debug_sup -// (DWARF5.pdf + 7.3.6) - -// ** not implemented yet ** - -typedef struct DWARF_SupParsed{ - U32 dummy; -} DWARF_SupParsed; - - -// info section: .debug_info -// (DWARF4.pdb + 7.5) (DWARF5.pdf + 7.5) - -typedef struct DWARF_InfoAttribVal{ - U64 val; - U8 *dataptr; -} DWARF_InfoAttribVal; - -typedef struct DWARF_InfoEntry{ - struct DWARF_InfoEntry *next_sibling; - struct DWARF_InfoEntry *first_child; - struct DWARF_InfoEntry *last_child; - U64 child_count; - struct DWARF_InfoEntry *parent; - - U64 info_offset; - struct DWARF_AbbrevDecl *abbrev_decl; - DWARF_InfoAttribVal *attrib_vals; -} DWARF_InfoEntry; - -#if 0 -typedef struct DWARF_InfoUnit{ - struct DWARF_InfoUnit *next; - - // header - U32 version; - U32 offset_size; - U32 address_size; - - // root attributes - DWARF_Language language; - U64 line_info_offset; - U64 vbase; - U64 str_offsets_base; - U64 addr_base; - U64 rnglists_base; - U64 loclists_base; - - // info entries - DWARF_InfoEntry *entry_root; - U64 entry_count; -} DWARF_InfoUnit; -#endif - -#if 0 -typedef struct DWARF_InfoParams{ - U64 unit_idx_min; - U64 unit_idx_max; -} DWARF_InfoParams; -#endif - -typedef struct DWARF_InfoUnit{ - struct DWARF_InfoUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 offset_size; - U8 version; - U8 unit_type; // (DWARF_UnitType) - U8 address_size; - U64 abbrev_off; - - union{ - // unit_type: skeleton, split_compile - U64 dwo_id; - // unit_type: type, split_type - struct{ - U64 type_signature; - U64 type_offset; - }; - }; -} DWARF_InfoUnit; - -typedef struct DWARF_InfoParsed{ - DWARF_InfoUnit *unit_first; - DWARF_InfoUnit *unit_last; - U64 unit_count; -} DWARF_InfoParsed; - - -// abbreviations section: .debug_abbrev -// (DWARF4.pdf + 7.5.3) (DWARF5.pdf + 7.5.3) - -typedef struct DWARF_AbbrevAttribSpec{ - DWARF_AttributeName name; - DWARF_AttributeForm form; -} DWARF_AbbrevAttribSpec; - -typedef struct DWARF_AbbrevDecl{ - struct DWARF_AbbrevDecl *next; - U32 abbrev_code; - DWARF_Tag tag; - B8 has_children; - U8 __filler__; - U16 attrib_count; - DWARF_AbbrevAttribSpec *attrib_specs; - S64 *implicit_const; -} DWARF_AbbrevDecl; - -typedef struct DWARF_AbbrevUnit{ - struct DWARF_AbbrevUnit *next; - U64 offset; - DWARF_AbbrevDecl *first; - DWARF_AbbrevDecl *last; - U64 count; -} DWARF_AbbrevUnit; - -#if 0 -typedef struct DWARF_AbbrevParams{ - U64 unit_idx_min; - U64 unit_idx_max; -} DWARF_AbbrevParams; -#endif - -typedef struct DWARF_AbbrevParsed{ - DWARF_AbbrevUnit *unit_first; - DWARF_AbbrevUnit *unit_last; - U64 unit_count; - B32 decoding_error; -} DWARF_AbbrevParsed; - - -// name lookup tables (V4): .debug_pubnames .debug_pubtypes -// (DWARF4.pdf + 7.19) - -typedef struct DWARF_PubNamesUnit{ - struct DWARF_PubNamesUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 offset_size; - U8 version; - U64 info_off; - U64 info_length; -} DWARF_PubNamesUnit; - -typedef struct DWARF_PubNamesParsed{ - DWARF_PubNamesUnit *unit_first; - DWARF_PubNamesUnit *unit_last; - U64 unit_count; -} DWARF_PubNamesParsed; - - -// name lookup tables (V5): .debug_names -// (DWARF5.pdf + 6.1.1.4.1 & 7.19) - -typedef struct DWARF_NamesUnit{ - struct DWARF_NamesUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 version; - U32 comp_unit_count; - U32 local_type_unit_count; - U32 foreign_type_unit_count; - U32 bucket_count; - U32 name_count; - U32 abbrev_table_size; - String8 augmentation_string; - -} DWARF_NamesUnit; - -typedef struct DWARF_NamesParsed{ - DWARF_NamesUnit *unit_first; - DWARF_NamesUnit *unit_last; - U64 unit_count; -} DWARF_NamesParsed; - - -// address range table: .debug_aranges -// (DWARF4.pdf + 7.20) (DWARF5.pdf + 7.21) - -typedef struct DWARF_ArangesUnit{ - struct DWARF_ArangesUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 version; - U8 address_size; - U8 segment_selector_size; - U8 offset_size; - U64 info_off; -} DWARF_ArangesUnit; - -typedef struct DWARF_ArangesParsed{ - DWARF_ArangesUnit *unit_first; - DWARF_ArangesUnit *unit_last; - U64 unit_count; -} DWARF_ArangesParsed; - - -// line number information: .debug_line -// (DWARF4.pdf + 6.2.4 & 7.21) (DWARF5.pdf + 6.2.4 & 7.22) - -typedef struct DWARF_V4LineFileNamesEntry{ - struct DWARF_V4LineFileNamesEntry *next; - String8 file_name; - U64 include_directory_idx; - U64 last_modified_time; - U64 file_size; -} DWARF_V4LineFileNamesEntry; - -typedef struct DWARF_V4LineFileNamesList{ - DWARF_V4LineFileNamesEntry *first; - DWARF_V4LineFileNamesEntry *last; - U64 count; -} DWARF_V4LineFileNamesList; - -typedef struct DWARF_V5LinePathEntryFormat{ - U32 content_type; /* DWARF_LineEntryFormat */ - U32 form; /* DWARF_AttributeForm */ -} DWARF_V5LinePathEntryFormat; - -typedef struct DWARF_V5Directory{ - String8 path_str; - U64 path_off; - U64 path_sec_form; - U64 directory_index; - U64 timestamp; - U64 size; - U8 md5_checksum[16]; -} DWARF_V5Directory; - -typedef struct DWARF_LineUnit{ - struct DWARF_LineUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 version; - -} DWARF_LineUnit; - -typedef struct DWARF_LineParsed{ - DWARF_LineUnit *unit_first; - DWARF_LineUnit *unit_last; - U64 unit_count; -} DWARF_LineParsed; - - -// macro information (V4): .debug_macinfo -// (DWARF4.pdf + 7.22) - -// ** not implemented yet ** - -typedef struct DWARF_MacInfoParsed{ - U32 dummy; -} DWARF_MacInfoParsed; - - -// macro information (V5): .debug_macro -// (DWARF5.pdf + 7.23) - -// ** not implemented yet ** - -typedef struct DWARF_MacroParsed{ - U32 dummy; -} DWARF_MacroParsed; - - -// call frame information: .debug_frame -// (DWARF4.pdf + 7.23) (DWARF5.pdf + 7.24) - -// ** not implemented yet ** - -typedef struct DWARF_FrameParsed{ - U32 dummy; -} DWARF_FrameParsed; - - -// range lists (V4): .debug_ranges -// (DWARF4.pdf + 7.24) - -// ** not implemented yet ** - -typedef struct DWARF_RangesParsed{ - U32 dummy; -} DWARF_RangesParsed; - - -// string offsets table: .debug_str_offsets -// (DWARF5.pdf + 7.26) - -// ** not implemented yet ** - -typedef struct DWARF_StrOffsetsParsed{ - U32 dummy; -} DWARF_StrOffsetsParsed; - - -// address table: .debug_addr -// (DWARF5.pdf + 7.27) - -typedef struct DWARF_AddrUnit{ - struct DWARF_AddrUnit *next; - - U64 hdr_off; - U64 base_off; - U64 opl_off; - - U8 offset_size; - U8 dwarf_version; - U8 address_size; - U8 segment_selector_size; -} DWARF_AddrUnit; - -typedef struct DWARF_AddrParsed{ - DWARF_AddrUnit *unit_first; - DWARF_AddrUnit *unit_last; - U64 unit_count; -} DWARF_AddrParsed; - - -// range lists (V5): .debug_rnglists -// (DWARF5.pdf + 7.28 & 7.25) - -// ** not implemented yet ** - -typedef struct DWARF_RngListsParsed{ - U32 dummy; -} DWARF_RngListsParsed; - - -// location lists: .debug_loclists -// (DWARF5.pdf + 7.29) - -// ** not implemented yet ** - -typedef struct DWARF_LocListsParsed{ - U32 dummy; -} DWARF_LocListsParsed; - - -//////////////////////////////// -//~ Dwarf Decode Helpers - -#define DWARF_LEB128_ADV(p,o,s) do{ (s)=1; for(;; (p)+=1){\ -if ((p) == (o)) { (s)=0; break; } \ -if (((*(p))&0x80) == 0) { (p)+=1; break; } \ -} }while(0) - -#define DWARF_LEB128_ADV_NOCAP(p) for((p)+=1; ((*(p-1))&0x80) != 0; (p)+=1) - -static U64 dwarf_leb128_decode_U64(U8 *ptr, U8 *opl); -static S64 dwarf_leb128_decode_S64(U8 *ptr, U8 *opl); -static U32 dwarf_leb128_decode_U32(U8 *ptr, U8 *opl); - -#define dwarf_leb128_decode(T,ptr,opl) dwarf_leb128_decode_##T(ptr,opl) - -#define DWARF_LEB128_DECODE_ADV(T,x,p,o) do{ \ -U8 *first__ = (p); B32 success__; \ -DWARF_LEB128_ADV(p,o,success__); \ -if (success__) \ -(x) = dwarf_leb128_decode(T,first__, (p)); \ -}while(0) - - -//////////////////////////////// -//~ allen: ELF/DW Unwind Types -// -// TODO(rjf): OLD TYPES FROM UNWINDER CODE. bucketing this here, and deferring dwarf-based -// unwinding info to future DWARF/linux work. -// -#if 0 - -// * applies to (any X: unwind(ELF/DW, X)) - -// EH: Exception Frames -typedef U8 UNW_DW_EhPtrEnc; -enum{ - UNW_DW_EhPtrEnc_TYPE_MASK = 0x0F, - UNW_DW_EhPtrEnc_PTR = 0x00, // Pointer sized unsigned value - UNW_DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value - UNW_DW_EhPtrEnc_UDATA2 = 0x02, // Unsigned 16-bit value - UNW_DW_EhPtrEnc_UDATA4 = 0x03, // Unsigned 32-bit value - UNW_DW_EhPtrEnc_UDATA8 = 0x04, // Unsigned 64-bit value - UNW_DW_EhPtrEnc_SIGNED = 0x08, // Signed pointer - UNW_DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value - UNW_DW_EhPtrEnc_SDATA2 = 0x0A, // Signed 16-bit value - UNW_DW_EhPtrEnc_SDATA4 = 0x0B, // Signed 32-bit value - UNW_DW_EhPtrEnc_SDATA8 = 0x0C, // Signed 64-bit value -}; -enum{ - UNW_DW_EhPtrEnc_MODIF_MASK = 0x70, - UNW_DW_EhPtrEnc_PCREL = 0x10, // Value is relative to the current program counter. - UNW_DW_EhPtrEnc_TEXTREL = 0x20, // Value is relative to the .text section. - UNW_DW_EhPtrEnc_DATAREL = 0x30, // Value is relative to the .got or .eh_frame_hdr section. - UNW_DW_EhPtrEnc_FUNCREL = 0x40, // Value is relative to the function. - UNW_DW_EhPtrEnc_ALIGNED = 0x50, // Value is aligned to an address unit sized boundary. -}; -enum{ - UNW_DW_EhPtrEnc_INDIRECT = 0x80, // This flag indicates that value is stored in virtual memory. - UNW_DW_EhPtrEnc_OMIT = 0xFF, -}; - -typedef struct UNW_DW_EhPtrCtx{ - U64 raw_base_vaddr; // address where pointer is being read - U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64) - U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64) - U64 func_vaddr; // base address of function where IP is located -} UNW_DW_EhPtrCtx; - -// CIE: Common Information Entry -typedef struct UNW_DW_CIEUnpacked{ - U8 version; - UNW_DW_EhPtrEnc lsda_encoding; - UNW_DW_EhPtrEnc addr_encoding; - - B8 has_augmentation_size; - U64 augmentation_size; - String8 augmentation; - - U64 code_align_factor; - S64 data_align_factor; - U64 ret_addr_reg; - - U64 handler_ip; - - U64 cfi_range_min; - U64 cfi_range_max; -} UNW_DW_CIEUnpacked; - -typedef struct UNW_DW_CIEUnpackedNode{ - struct UNW_DW_CIEUnpackedNode *next; - UNW_DW_CIEUnpacked cie; - U64 offset; -} UNW_DW_CIEUnpackedNode; - -// FDE: Frame Description Entry -typedef struct UNW_DW_FDEUnpacked{ - U64 ip_voff_min; - U64 ip_voff_max; - U64 lsda_ip; - - U64 cfi_range_min; - U64 cfi_range_max; -} UNW_DW_FDEUnpacked; - -// CFI: Call Frame Information -typedef struct UNW_DW_CFIRecords{ - B32 valid; - UNW_DW_CIEUnpacked cie; - UNW_DW_FDEUnpacked fde; -} UNW_DW_CFIRecords; - -typedef enum UNW_DW_CFICFARule{ - UNW_DW_CFICFARule_REGOFF, - UNW_DW_CFICFARule_EXPR, -} UNW_DW_CFICFARule; - -typedef struct UNW_DW_CFICFACell{ - UNW_DW_CFICFARule rule; - union{ - struct{ - U64 reg_idx; - S64 offset; - }; - U64 expr_min; - U64 expr_max; - }; -} UNW_DW_CFICFACell; - -typedef enum UNW_DW_CFIRegisterRule{ - UNW_DW_CFIRegisterRule_SAME_VALUE, - UNW_DW_CFIRegisterRule_UNDEFINED, - UNW_DW_CFIRegisterRule_OFFSET, - UNW_DW_CFIRegisterRule_VAL_OFFSET, - UNW_DW_CFIRegisterRule_REGISTER, - UNW_DW_CFIRegisterRule_EXPRESSION, - UNW_DW_CFIRegisterRule_VAL_EXPRESSION, -} UNW_DW_CFIRegisterRule; - -typedef struct UNW_DW_CFICell{ - UNW_DW_CFIRegisterRule rule; - union{ - S64 n; - struct{ - U64 expr_min; - U64 expr_max; - }; - }; -} UNW_DW_CFICell; - -typedef struct UNW_DW_CFIRow{ - struct UNW_DW_CFIRow *next; - UNW_DW_CFICell *cells; - UNW_DW_CFICFACell cfa_cell; -} UNW_DW_CFIRow; - -typedef struct UNW_DW_CFIMachine{ - U64 cells_per_row; - UNW_DW_CIEUnpacked *cie; - UNW_DW_EhPtrCtx *ptr_ctx; - UNW_DW_CFIRow *initial_row; - U64 fde_ip; -} UNW_DW_CFIMachine; - -typedef U8 UNW_DW_CFADecode; -enum{ - UNW_DW_CFADecode_NOP = 0x0, - // 1,2,4,8 reserved for literal byte sizes - UNW_DW_CFADecode_ADDRESS = 0x9, - UNW_DW_CFADecode_ULEB128 = 0xA, - UNW_DW_CFADecode_SLEB128 = 0xB, -}; - -typedef U16 UNW_DW_CFAControlBits; -enum{ - UNW_DW_CFAControlBits_DEC1_MASK = 0x00F, - UNW_DW_CFAControlBits_DEC2_MASK = 0x0F0, - UNW_DW_CFAControlBits_IS_REG_0 = 0x100, - UNW_DW_CFAControlBits_IS_REG_1 = 0x200, - UNW_DW_CFAControlBits_IS_REG_2 = 0x400, - UNW_DW_CFAControlBits_NEW_ROW = 0x800, -}; -#endif - -//////////////////////////////// -//~ Dwarf Parser Functions - -static DWARF_Parsed* dwarf_parsed_from_elf(Arena *arena, ELF_Parsed *elf); - -static DWARF_IndexParsed* dwarf_index_from_data(Arena *arena, String8 data); -static DWARF_SupParsed* dwarf_sup_from_data(Arena *arena, String8 data); -static DWARF_InfoParsed* dwarf_info_from_data(Arena *arena, String8 data); -static DWARF_PubNamesParsed* dwarf_pubnames_from_data(Arena *arena, String8 data); -static DWARF_NamesParsed* dwarf_names_from_data(Arena *arena, String8 data); -static DWARF_ArangesParsed* dwarf_aranges_from_data(Arena *arena, String8 data); -static DWARF_LineParsed* dwarf_line_from_data(Arena *arena, String8 data); -static DWARF_MacInfoParsed* dwarf_mac_info_from_data(Arena *arena, String8 data); -static DWARF_MacroParsed* dwarf_macro_from_data(Arena *arena, String8 data); -static DWARF_FrameParsed* dwarf_frame_from_data(Arena *arena, String8 data); -static DWARF_RangesParsed* dwarf_ranges_from_data(Arena *arena, String8 data); -static DWARF_StrOffsetsParsed* dwarf_str_offsets_from_data(Arena *arena, String8 data); -static DWARF_AddrParsed* dwarf_addr_from_data(Arena *arena, String8 data); -static DWARF_RngListsParsed* dwarf_rng_lists_from_data(Arena *arena, String8 data); -static DWARF_LocListsParsed* dwarf_loc_lists_from_data(Arena *arena, String8 data); - - -// parse helpers - -// (DWARF4.pdf + 7.2.2) (DWARF5.pdf + 7.2.2) -static void dwarf__initial_length(String8 data, - U8 **ptr_inout, U8 **unit_opl_out, B32 *is_64bit_out); - -static void -dwarf__line_v5_directories(U64 address_size, U64 offset_size, - DWARF_V5LinePathEntryFormat *format, U64 format_count, - DWARF_V5Directory *directories_out, U64 dir_count, - U8 **ptr_io, U8 *opl); - -// debug sections - -static String8 dwarf_name_from_debug_section(DWARF_Parsed *dwarf, DWARF_SectionCode sec_code); - -// abbrev functions - -static DWARF_AbbrevUnit* dwarf_abbrev_unit_from_offset(DWARF_AbbrevParsed *abbrev, U64 off); -static DWARF_AbbrevDecl* dwarf_abbrev_decl_from_code(DWARF_AbbrevUnit *unit, U32 code); - -// attribute decoding functions - -static DWARF_AttributeClassFlags dwarf_attribute_class_from_form(DWARF_AttributeForm form); -static DWARF_AttributeClassFlags dwarf_attribute_class_from_name(DWARF_AttributeName name); - -// form decoding functions - -static DWARF_FormDecodeRules -dwarf_form_decode_rule(DWARF_AttributeForm form, U64 address_size, U64 offset_size); - -static DWARF_FormDecoded -dwarf_form_decode(DWARF_FormDecodeRules *rules, U8 **ptr_io, U8 *opl, - DWARF_AbbrevDecl *abbrev_decl, U32 attrib_i); - -// string functions - -static String8 dwarf_string_from_unit_type(DWARF_UnitType type); -static String8 dwarf_string_from_tag(DWARF_Tag tag); -static String8 dwarf_string_from_attribute_name(DWARF_AttributeName name); -static String8 dwarf_string_from_attribute_form(DWARF_AttributeForm form); -static String8 dwarf_string_from_line_std_op(DWARF_LineStdOp op); -static String8 dwarf_string_from_line_ext_op(DWARF_LineExtOp op); -static String8 dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format); -static String8 dwarf_string_from_section_code(DWARF_SectionCode sec_code); - -#endif //RDI_DWARF_H - diff --git a/src/rdi_from_dwarf/rdi_dwarf_stringize.c b/src/rdi_from_dwarf/rdi_dwarf_stringize.c deleted file mode 100644 index 67865813..00000000 --- a/src/rdi_from_dwarf/rdi_dwarf_stringize.c +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ DWARF Stringize Functions - -static char dwarf_spaces[] = " "; - -static void -dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent){ - String8 unit_type_string = dwarf_string_from_unit_type((DWARF_UnitType)unit->unit_type); - - str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); - str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); - str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); - str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, - unit->offset_size); - str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); - str8_list_pushf(arena, out, "%.*sunit_type=%.*s\n", indent, dwarf_spaces, - str8_varg(unit_type_string)); - str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, - unit->address_size); - str8_list_pushf(arena, out, "%.*sabbrev_off=0x%llx\n", indent, dwarf_spaces, - unit->abbrev_off); - - switch (unit->unit_type){ - case DWARF_UnitType_skeleton: case DWARF_UnitType_split_compile: - { - str8_list_pushf(arena, out, "%.*sdwo_id=%llu\n", indent, dwarf_spaces, unit->dwo_id); - }break; - - case DWARF_UnitType_type: case DWARF_UnitType_split_type: - { - str8_list_pushf(arena, out, "%.*stype_signature=%llu\n", indent, dwarf_spaces, - unit->type_signature); - str8_list_pushf(arena, out, "%.*stype_offset=%llu\n", indent, dwarf_spaces, - unit->type_offset); - }break; - } -} - -static void -dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit, - U32 indent){ - str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); - str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); - str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); - str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size); - str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); - str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off); - str8_list_pushf(arena, out, "%.*sinfo_length=0x%llx\n", indent, dwarf_spaces, - unit->info_length); -} - -static void -dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent){ - str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); - str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); - str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); - str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); - str8_list_pushf(arena, out, "%.*scomp_unit_count=%u\n", indent, dwarf_spaces, - unit->comp_unit_count); - str8_list_pushf(arena, out, "%.*slocal_type_unit_count=%u\n", indent, dwarf_spaces, - unit->local_type_unit_count); - str8_list_pushf(arena, out, "%.*sforeign_type_unit_count=%u\n", indent, dwarf_spaces, - unit->foreign_type_unit_count); - str8_list_pushf(arena, out, "%.*sbucket_count=%u\n", indent, dwarf_spaces, - unit->bucket_count); - str8_list_pushf(arena, out, "%.*sname_count=%u\n", indent, dwarf_spaces, unit->name_count); - str8_list_pushf(arena, out, "%.*sabbrev_table_size=%u\n", indent, dwarf_spaces, - unit->abbrev_table_size); - str8_list_pushf(arena, out, "%.*saugmentation_string=%.*s\n", indent, dwarf_spaces, - str8_varg(unit->augmentation_string)); -} - -static void -dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent){ - str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); - str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); - str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); - str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->version); - str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, - unit->address_size); - str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces, - unit->segment_selector_size); - str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, unit->offset_size); - str8_list_pushf(arena, out, "%.*sinfo_off=0x%llx\n", indent, dwarf_spaces, unit->info_off); -} - -static void -dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent){ - str8_list_pushf(arena, out, "%.*shdr_off=0x%llx\n", indent, dwarf_spaces, unit->hdr_off); - str8_list_pushf(arena, out, "%.*sbase_off=0x%llx\n", indent, dwarf_spaces, unit->base_off); - str8_list_pushf(arena, out, "%.*sopl_off=0x%llx\n", indent, dwarf_spaces, unit->opl_off); - str8_list_pushf(arena, out, "%.*soffset_size=%u\n", indent, dwarf_spaces, - unit->offset_size); - str8_list_pushf(arena, out, "%.*sversion=%u\n", indent, dwarf_spaces, unit->dwarf_version); - str8_list_pushf(arena, out, "%.*saddress_size=%u\n", indent, dwarf_spaces, - unit->address_size); - str8_list_pushf(arena, out, "%.*ssegment_selector_size=%u\n", indent, dwarf_spaces, - unit->segment_selector_size); -} diff --git a/src/rdi_from_dwarf/rdi_dwarf_stringize.h b/src/rdi_from_dwarf/rdi_dwarf_stringize.h deleted file mode 100644 index 30a13254..00000000 --- a/src/rdi_from_dwarf/rdi_dwarf_stringize.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_DWARF_STRINGIZE_H -#define RDI_DWARF_STRINGIZE_H - -//////////////////////////////// -//~ DWARF Stringize Functions - -static void -dwarf_stringize_info(Arena *arena, String8List *out, DWARF_InfoUnit *unit, U32 indent); - -static void -dwarf_stringize_pubnames(Arena *arena, String8List *out, DWARF_PubNamesUnit *unit, - U32 indent); - -static void -dwarf_stringize_names(Arena *arena, String8List *out, DWARF_NamesUnit *unit, U32 indent); - -static void -dwarf_stringize_aranges(Arena *arena, String8List *out, DWARF_ArangesUnit *unit, U32 indent); - -static void -dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 indent); - - - -#endif //RDI_DWARF_STRINGIZE_H diff --git a/src/rdi_from_dwarf/rdi_elf.c b/src/rdi_from_dwarf/rdi_elf.c deleted file mode 100644 index bda90ef1..00000000 --- a/src/rdi_from_dwarf/rdi_elf.c +++ /dev/null @@ -1,557 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ ELF Parser Functions - -static ELF_Parsed* -elf_parsed_from_data(Arena *arena, String8 elf_data){ - //- test magic number - B32 has_good_magic_number = 0; - if (elf_data.size >= sizeof(ELF_NIDENT) && - MemoryMatch(elf_data.str, elf_magic, sizeof(elf_magic))){ - has_good_magic_number = 1; - } - - //- determine elf class - U8 elf_class = ELF_Class_NONE; - if (has_good_magic_number){ - elf_class = elf_data.str[ELF_Identification_CLASS]; - } - - //- extract header information - B32 decoded_header = 0; - - U8 e_data_encoding = ELF_DataEncoding_NONE; - U16 e_machine = ELF_Machine_NONE; - - U64 e_entry = 0; - - U64 e_shoff = 0; - U16 e_shentsize = 0; - U16 e_shnum = 0; - - U64 e_phoff = 0; - U16 e_phentsize = 0; - U16 e_phnum = 0; - - U16 e_shstrndx = 0; - - switch (elf_class){ - case ELF_Class_NONE: /* not good */ break; - - case ELF_Class_32: - { - if (elf_data.size >= sizeof(ELF_Ehdr32)){ - ELF_Ehdr32 *hdr = (ELF_Ehdr32*)elf_data.str; - - decoded_header = 1; - e_data_encoding = hdr->e_ident[ELF_Identification_DATA]; - e_machine = hdr->e_machine; - e_entry = hdr->e_entry; - e_phoff = hdr->e_phoff; - e_shoff = hdr->e_shoff; - e_phentsize = hdr->e_phentsize; - e_phnum = hdr->e_phnum; - e_shentsize = hdr->e_shentsize; - e_shnum = hdr->e_shnum; - e_shstrndx = hdr->e_shstrndx; - } - }break; - - case ELF_Class_64: - { - if (elf_data.size >= sizeof(ELF_Ehdr64)){ - ELF_Ehdr64 *hdr = (ELF_Ehdr64*)elf_data.str; - - decoded_header = 1; - e_data_encoding = hdr->e_ident[ELF_Identification_DATA]; - e_machine = hdr->e_machine; - e_entry = hdr->e_entry; - e_phoff = hdr->e_phoff; - e_shoff = hdr->e_shoff; - e_phentsize = hdr->e_phentsize; - e_phnum = hdr->e_phnum; - e_shentsize = hdr->e_shentsize; - e_shnum = hdr->e_shnum; - e_shstrndx = hdr->e_shstrndx; - } - }break; - } - - //- validate & translate header values - B32 header_is_good = 0; - Arch arch = Arch_Null; - if (decoded_header){ - header_is_good = 1; - - // only supporting little-endian versions right now - if (header_is_good){ - if (e_data_encoding != ELF_DataEncoding_2LSB){ - header_is_good = 0; - } - } - - // make sure this is a supported machine type - if (header_is_good){ - switch (e_machine){ - default: header_is_good = 0; - case ELF_Machine_386: arch = Arch_x86; break; - case ELF_Machine_X86_64: arch = Arch_x64; break; - } - } - - // make sure section & segment sizes are correct - if (header_is_good){ - switch (elf_class){ - case ELF_Class_32: - { - if (e_shentsize != sizeof(ELF_Shdr32) || - e_phentsize != sizeof(ELF_Phdr32)){ - header_is_good = 0; - } - }break; - case ELF_Class_64: - { - if (e_shentsize != sizeof(ELF_Shdr64) || - e_phentsize != sizeof(ELF_Phdr64)){ - header_is_good = 0; - } - }break; - } - } - } - - //- extract extra information from the special first section - U64 section_count_raw = e_shnum; - U32 section_header_string_table_index = e_shstrndx; - if (header_is_good){ - if (e_shoff <= elf_data.size && e_shentsize <= elf_data.size && - e_shoff + e_shentsize <= elf_data.size){ - U64 size = 0; - U32 link = 0; - switch (elf_class){ - case ELF_Class_32: - { - ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + e_shoff); - size = shdr->sh_size; - link = shdr->sh_link; - }break; - case ELF_Class_64: - { - ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + e_shoff); - size = shdr->sh_size; - link = shdr->sh_link; - }break; - } - - // extended section count - if (size != 0){ - section_count_raw = size; - } - - // extended section header string table index - if (link != 0){ - section_header_string_table_index = link; - } - } - } - - //- clamp section & program arrays to size - U64 section_foff = 0; - U64 section_size = 0; - U64 section_count = 0; - - U64 segment_foff = 0; - U64 segment_size = 0; - U64 segment_count = 0; - - if (header_is_good){ - if (e_shentsize > 0){ - U64 section_opl_raw = e_shoff + e_shentsize*section_count_raw; - U64 section_opl = ClampTop(section_opl_raw, elf_data.size); - if (section_opl > e_shoff){ - section_foff = e_shoff; - section_size = e_shentsize; - section_count = (section_opl - e_shoff)/e_shentsize; - } - } - - if (e_phentsize > 0){ - U64 segment_opl_raw = e_phoff + e_phentsize*e_phnum; - U64 segment_opl = ClampTop(segment_opl_raw, elf_data.size); - if (segment_opl > e_phoff){ - segment_foff = e_phoff; - segment_size = e_phentsize; - segment_count = (segment_opl - e_phoff)/e_phentsize; - } - } - } - - //- determine the vbase for this file - U64 vbase = 0; - if (header_is_good){ - // find the first LOAD segment - U64 load_segment_off = 0; - { - U64 segment_cursor = segment_foff; - U64 segment_opl = segment_foff + segment_size*segment_count; - for (;segment_cursor < segment_opl; segment_cursor += segment_size){ - U32 p_type = *(U32*)(elf_data.str + segment_cursor); - if (p_type == ELF_SegmentType_LOAD){ - load_segment_off = segment_cursor; - break; - } - } - } - - // use the segment's p_vaddr to determine vbase - if (load_segment_off != 0){ - switch (elf_class){ - case ELF_Class_32: - { - ELF_Phdr32 *phdr = (ELF_Phdr32*)(elf_data.str + load_segment_off); - vbase = phdr->p_vaddr; - }break; - case ELF_Class_64: - { - ELF_Phdr64 *phdr = (ELF_Phdr64*)(elf_data.str + load_segment_off); - vbase = phdr->p_vaddr; - }break; - } - } - } - - //- locate the section header string table - U64 section_name_table_foff = 0; - U64 section_name_table_opl = 0; - if (header_is_good){ - if (section_header_string_table_index < section_count){ - U64 sec_foff = section_foff + section_header_string_table_index*section_size; - switch (elf_class){ - case ELF_Class_32: - { - ELF_Shdr32 *shdr = (ELF_Shdr32*)(elf_data.str + sec_foff); - section_name_table_foff = shdr->sh_offset; - section_name_table_opl = shdr->sh_offset + shdr->sh_size; - }break; - case ELF_Class_64: - { - ELF_Shdr64 *shdr = (ELF_Shdr64*)(elf_data.str + sec_foff); - section_name_table_foff = shdr->sh_offset; - section_name_table_opl = shdr->sh_offset + shdr->sh_size; - }break; - } - } - } - - //- format sections data - ELF_Shdr64 *sections = 0; - if (header_is_good && section_count > 0){ - switch (elf_class){ - case ELF_Class_32: - { - sections = push_array(arena, ELF_Shdr64, section_count); - { - ELF_Shdr32 *shdr32 = (ELF_Shdr32*)(elf_data.str + section_foff); - ELF_Shdr64 *shdr64 = sections; - for (U64 i = 0; i < section_count; i += 1, shdr32 += 1, shdr64 += 1){ - shdr64->sh_name = shdr32->sh_name; - shdr64->sh_type = shdr32->sh_type; - shdr64->sh_flags = shdr32->sh_flags; - shdr64->sh_addr = shdr32->sh_addr; - shdr64->sh_offset = shdr32->sh_offset; - shdr64->sh_size = shdr32->sh_size; - shdr64->sh_link = shdr32->sh_link; - shdr64->sh_info = shdr32->sh_info; - shdr64->sh_addralign = shdr32->sh_addralign; - shdr64->sh_entsize = shdr32->sh_entsize; - } - } - }break; - case ELF_Class_64: - { - sections = (ELF_Shdr64*)(elf_data.str + section_foff); - }break; - } - } - - //- extract section names - String8 *section_names = 0; - if (sections != 0 && section_count > 0){ - U8 *string_table_opl = elf_data.str + section_name_table_opl; - - section_names = push_array(arena, String8, section_count); - String8 *sec_name = section_names; - ELF_Shdr64 *sec = sections; - for (U64 i = 0; - i < section_count; - i += 1, sec += 1, sec_name += 1){ - U64 name_foff = section_name_table_foff + sec->sh_name; - if (section_name_table_foff <= name_foff && name_foff < section_name_table_opl){ - U8 *base = elf_data.str + name_foff; - U8 *opl = base; - for (;opl < string_table_opl && *opl != 0; opl += 1); - sec_name->str = base; - sec_name->size = (U64)(opl - base); - } - } - } - - //- format segments data - ELF_Phdr64 *segments = 0; - if (header_is_good && segment_count > 0){ - switch (elf_class){ - case ELF_Class_32: - { - segments = push_array(arena, ELF_Phdr64, segment_count); - { - ELF_Phdr32 *phdr32 = (ELF_Phdr32*)(elf_data.str + segment_foff); - ELF_Phdr64 *phdr64 = segments; - for (U64 i = 0; i < segment_count; i += 1, phdr32 += 1, phdr64 += 1){ - phdr64->p_type = phdr32->p_type; - phdr64->p_flags = phdr32->p_flags; - phdr64->p_offset = phdr32->p_offset; - phdr64->p_vaddr = phdr32->p_vaddr; - phdr64->p_paddr = phdr32->p_paddr; - phdr64->p_filesz = phdr32->p_filesz; - phdr64->p_memsz = phdr32->p_memsz; - phdr64->p_align = phdr32->p_align; - } - } - }break; - case ELF_Class_64: - { - segments = (ELF_Phdr64*)(elf_data.str + segment_foff); - }break; - } - } - - //- find special sections - U64 strtab_idx = 0; - U64 symtab_idx = 0; - U64 dynsym_idx = 0; - if (section_names != 0){ - for (U64 i = 0; i < section_count; i += 1){ - String8 name = section_names[i]; - if (str8_match(name, str8_lit(".strtab"), 0)){ - strtab_idx = i; - } - else if (str8_match(name, str8_lit(".symtab"), 0)){ - symtab_idx = i; - } - else if (str8_match(name, str8_lit(".dynsym"), 0)){ - dynsym_idx = i; - } - } - } - - - //- fill result - ELF_Parsed *result = 0; - if (header_is_good){ - result = push_array(arena, ELF_Parsed, 1); - result->data = elf_data; - result->elf_class = elf_class; - result->arch = arch; - result->sections = sections; - result->section_names = section_names; - result->section_foff = section_foff; - result->section_count = section_count; - result->segments = segments; - result->segment_foff = segment_foff; - result->segment_count = segment_count; - result->vbase = vbase; - result->entry_vaddr = e_entry; - result->section_name_table_foff = section_name_table_foff; - result->section_name_table_opl = section_name_table_opl; - result->strtab_idx = strtab_idx; - result->symtab_idx = symtab_idx; - result->dynsym_idx = dynsym_idx; - } - - return(result); -} - -static ELF_SectionArray -elf_section_array_from_elf(ELF_Parsed *elf){ - ELF_SectionArray result = {0}; - if (elf != 0){ - result.sections = elf->sections; - result.count = elf->section_count; - } - return(result); -} - -static String8Array -elf_section_name_array_from_elf(ELF_Parsed *elf){ - String8Array result = {0}; - if (elf != 0){ - result.v = elf->section_names; - result.count = elf->section_count; - } - return(result); -} - -static ELF_SegmentArray -elf_segment_array_from_elf(ELF_Parsed *elf){ - ELF_SegmentArray result = {0}; - if (elf != 0){ - result.segments = elf->segments; - result.count = elf->segment_count; - } - return(result); -} - -static String8 -elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset){ - String8 result = {0}; - if (elf != 0){ - if (offset > 0){ - U64 foff = elf->section_name_table_foff + offset; - if (elf->section_name_table_foff <= foff && foff < elf->section_name_table_opl){ - U8 *base = elf->data.str + foff; - U8 *section_opl = elf->data.str + elf->section_name_table_opl; - U8 *opl = base; - for (;opl < section_opl && *opl != 0; opl += 1); - result.str = base; - result.size = opl - base; - } - } - } - return(result); -} - -static String8 -elf_section_name_from_idx(ELF_Parsed *elf, U32 idx){ - String8 result = {0}; - if (elf != 0){ - if (idx < elf->section_count){ - result = elf->section_names[idx]; - } - } - return(result); -} - -static U32 -elf_section_idx_from_name(ELF_Parsed *elf, String8 name){ - U32 result = 0; - if (elf != 0){ - String8 *sec_name = elf->section_names; - U64 count = elf->section_count; - for (U64 i = 0; i < count; i += 1, sec_name += 1){ - if (str8_match(*sec_name, name, 0)){ - result = i; - break; - } - } - } - return(result); -} - -static String8 -elf_section_data_from_idx(ELF_Parsed *elf, U32 idx){ - String8 result = {0}; - if (elf != 0){ - if (idx < elf->section_count){ - ELF_Shdr64 *shdr = elf->sections + idx; - U64 off_raw = shdr->sh_offset; - U64 size = shdr->sh_size; - if (shdr->sh_flags & ELF_SectionType_NOBITS){ - size = 0; - } - U64 opl_raw = off_raw + size; - U64 opl = ClampTop(opl_raw, elf->data.size); - U64 off = ClampTop(off_raw, opl); - result.str = elf->data.str + off; - result.size = opl - off; - } - } - return(result); -} - -static ELF_SymArray -elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data){ - // converge to sym64 layout - ELF_Sym64 *symbols = 0; - U64 count = 0; - switch (elf_class){ - default:{}break; - - case ELF_Class_32: - { - count = data.size/sizeof(ELF_Sym32); - symbols = push_array(arena, ELF_Sym64, count); - { - ELF_Sym32 *sym32 = (ELF_Sym32*)(data.str); - ELF_Sym64 *sym64 = symbols; - for (U64 i = 0; i < count; i += 1, sym32 += 1, sym64 += 1){ - sym64->st_name = sym32->st_name; - sym64->st_value = sym32->st_value; - sym64->st_size = sym32->st_size; - sym64->st_info = sym32->st_info; - sym64->st_other = sym32->st_other; - sym64->st_shndx = sym32->st_shndx; - } - } - }break; - - case ELF_Class_64: - { - count = data.size/sizeof(ELF_Sym64); - symbols = (ELF_Sym64*)(data.str); - }break; - } - - // fill result - ELF_SymArray result = {0}; - result.symbols = symbols; - result.count = count; - return(result); -} - -// string functions - -static String8 -elf_string_from_section_type(ELF_SectionType section_type){ - String8 result = str8_lit("INVALID_SECTION_TYPE"); - switch (section_type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SectionTypeXList(X) -#undef X - } - return(result); -} - -static String8 -elf_string_from_symbol_binding(ELF_SymbolBinding binding){ - String8 result = str8_lit("INVALID_SYMBOL_BINDING"); - switch (binding){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolBindingXList(X) -#undef X - } - return(result); -} - -static String8 -elf_string_from_symbol_type(ELF_SymbolType type){ - String8 result = str8_lit("INVALID_SYMBOL_TYPE"); - switch (type){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolTypeXList(X) -#undef X - } - return(result); -} - -static String8 -elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility){ - String8 result = str8_lit("INVALID_SYMBOL_VISIBILITY"); - switch (visibility){ -#define X(N,C) case C: result = str8_lit(#N); break; - ELF_SymbolVisibilityXList(X) -#undef X - } - return(result); -} diff --git a/src/rdi_from_dwarf/rdi_elf.h b/src/rdi_from_dwarf/rdi_elf.h deleted file mode 100644 index 8643f8bf..00000000 --- a/src/rdi_from_dwarf/rdi_elf.h +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RDI_ELF_H -#define RDI_ELF_H - -// https://refspecs.linuxfoundation.org/elf/elf.pdf - -//////////////////////////////// -//~ Elf Format Types - -// elf header - -#define ELF_NIDENT 16 - -typedef struct ELF_Ehdr32{ - U8 e_ident[ELF_NIDENT]; - U16 e_type; - U16 e_machine; - U32 e_version; - U32 e_entry; - U32 e_phoff; - U32 e_shoff; - U32 e_flags; - U16 e_ehsize; - U16 e_phentsize; - U16 e_phnum; - U16 e_shentsize; - U16 e_shnum; - U16 e_shstrndx; -} ELF_Ehdr32; - -typedef struct ELF_Ehdr64{ - U8 e_ident[ELF_NIDENT]; - U16 e_type; - U16 e_machine; - U32 e_version; - U64 e_entry; - U64 e_phoff; - U64 e_shoff; - U32 e_flags; - U16 e_ehsize; - U16 e_phentsize; - U16 e_phnum; - U16 e_shentsize; - U16 e_shnum; - U16 e_shstrndx; -} ELF_Ehdr64; - -typedef enum ELF_Type{ - ELF_Type_NONE = 0, - ELF_Type_REL = 1, - ELF_Type_EXEC = 2, - ELF_Type_DYN = 3, - ELF_Type_CORE = 4, - ELF_Type_LOOS = 0xfe00, - ELF_Type_HIOS = 0xfeff, - ELF_Type_LOPROC = 0xff00, - ELF_Type_HIPROC = 0xffff, -} ELF_Type; - -typedef enum ELF_Machine{ - ELF_Machine_NONE = 0, - ELF_Machine_M32 = 1, - ELF_Machine_SPARC = 2, - ELF_Machine_386 = 3, - ELF_Machine_68K = 4, - ELF_Machine_88K = 5, - ELF_Machine_860 = 7, - ELF_Machine_MIPS = 8, - ELF_Machine_S370 = 9, - ELF_Machine_MIPS_RS3_LE = 10, - ELF_Machine_PARISC = 15, - ELF_Machine_VPP500 = 17, - ELF_Machine_SPARC32PLUS = 18, - ELF_Machine_960 = 19, - ELF_Machine_PPC = 20, - ELF_Machine_PPC64 = 21, - ELF_Machine_S390 = 22, - ELF_Machine_V800 = 36, - ELF_Machine_FR20 = 37, - ELF_Machine_RH32 = 38, - ELF_Machine_RCE = 39, - ELF_Machine_ARM = 40, - ELF_Machine_ALPHA = 41, - ELF_Machine_SH = 42, - ELF_Machine_SPARCV9 = 43, - ELF_Machine_TRICORE = 44, - ELF_Machine_ARC = 45, - ELF_Machine_H8_300 = 46, - ELF_Machine_H8_300H = 47, - ELF_Machine_H8S = 48, - ELF_Machine_H8_500 = 49, - ELF_Machine_IA_64 = 50, - ELF_Machine_MIPS_X = 51, - ELF_Machine_COLDFIRE = 52, - ELF_Machine_68HC12 = 53, - ELF_Machine_MMA = 54, - ELF_Machine_PCP = 55, - ELF_Machine_NCPU = 56, - ELF_Machine_NDR1 = 57, - ELF_Machine_STARCORE = 58, - ELF_Machine_ME16 = 59, - ELF_Machine_ST100 = 60, - ELF_Machine_TINYJ = 61, - ELF_Machine_X86_64 = 62, - ELF_Machine_PDSP = 63, - ELF_Machine_PDP10 = 64, - ELF_Machine_PDP11 = 65, - ELF_Machine_FX66 = 66, - ELF_Machine_ST9PLUS = 67, - ELF_Machine_ST7 = 68, - ELF_Machine_68HC16 = 69, - ELF_Machine_68HC11 = 70, - ELF_Machine_68HC08 = 71, - ELF_Machine_68HC05 = 72, - ELF_Machine_SVX = 73, - ELF_Machine_ST19 = 74, - ELF_Machine_VAX = 75, - ELF_Machine_CRIS = 76, - ELF_Machine_JAVELIN = 77, - ELF_Machine_FIREPATH = 78, - ELF_Machine_ZSP = 79, - ELF_Machine_MMIX = 80, - ELF_Machine_HUANY = 81, - ELF_Machine_PRISM = 82, - ELF_Machine_AVR = 83, - ELF_Machine_FR30 = 84, - ELF_Machine_D10V = 85, - ELF_Machine_D30V = 86, - ELF_Machine_V850 = 87, - ELF_Machine_M32R = 88, - ELF_Machine_MN10300 = 89, - ELF_Machine_MN10200 = 90, - ELF_Machine_PJ = 91, - ELF_Machine_OPENRISC = 92, - ELF_Machine_ARC_A5 = 93, - ELF_Machine_XTENSA = 94, - ELF_Machine_VIDEOCORE = 95, - ELF_Machine_TMM_GPP = 96, - ELF_Machine_NS32K = 97, - ELF_Machine_TPC = 98, - ELF_Machine_SNP1K = 99, - ELF_Machine_ST200 = 100, -} ELF_Machine; - -typedef enum ELF_Version{ - ELF_Version_NONE = 0, - ELF_Version_CURRENT = 1, -} ELF_Version; - -typedef enum ELF_Identification{ - ELF_Identification_MAG0 = 0, - ELF_Identification_MAG1 = 1, - ELF_Identification_MAG2 = 2, - ELF_Identification_MAG3 = 3, - ELF_Identification_CLASS = 4, - ELF_Identification_DATA = 5, - ELF_Identification_VERSION = 6, - ELF_Identification_OSABI = 7, - ELF_Identification_ABIVERSION = 8, - ELF_Identification_PAD = 9, -} ELF_Identification; - -read_only global U8 elf_magic[] = {0x7F, 'E', 'L', 'F'}; - -typedef enum ELF_Class{ - ELF_Class_NONE = 0, - ELF_Class_32 = 1, - ELF_Class_64 = 2, -} ELF_Class; - -typedef enum ELF_DataEncoding{ - ELF_DataEncoding_NONE = 0, - ELF_DataEncoding_2LSB = 1, - ELF_DataEncoding_2MSB = 2, -} ELF_DataEncoding; - -typedef enum ELF_OsAbi{ - ELF_OsAbi_NONE = 0, - ELF_OsAbi_HPUX = 1, - ELF_OsAbi_NETBSD = 2, - ELF_OsAbi_LINUX = 3, - ELF_OsAbi_SOLARIS = 6, - ELF_OsAbi_AIX = 7, - ELF_OsAbi_IRIX = 8, - ELF_OsAbi_FREEBSD = 9, - ELF_OsAbi_TRU64 = 10, - ELF_OsAbi_MODESTO = 11, - ELF_OsAbi_OPENBSD = 12, - ELF_OsAbi_OPENVMS = 13, - ELF_OsAbi_NSK = 14, -} ELF_OsAbi; - -// sections - -typedef enum ELF_ReservedSectionIndex{ - ELF_ReservedSectionIndex_UNDEF = 0, - ELF_ReservedSectionIndex_LORESERVE = 0xFF00, - ELF_ReservedSectionIndex_LOPROC = 0xFF00, - ELF_ReservedSectionIndex_HIPROC = 0xFF1F, - ELF_ReservedSectionIndex_LOOS = 0xFF20, - ELF_ReservedSectionIndex_HIOS = 0xFF3F, - ELF_ReservedSectionIndex_ABS = 0xFFF1, - ELF_ReservedSectionIndex_COMMON = 0xFFF2, - ELF_ReservedSectionIndex_XINDEX = 0xFFFF, - ELF_ReservedSectionIndex_HIRESERVE = 0xFFFF, -} ELF_ReservedSectionIndex; - -typedef struct ELF_Shdr32{ - U32 sh_name; - U32 sh_type; - U32 sh_flags; - U32 sh_addr; - U32 sh_offset; - U32 sh_size; - U32 sh_link; - U32 sh_info; - U32 sh_addralign; - U32 sh_entsize; -} ELF_Shdr32; - -typedef struct ELF_Shdr64{ - U32 sh_name; - U32 sh_type; - U64 sh_flags; - U64 sh_addr; - U64 sh_offset; - U64 sh_size; - U32 sh_link; - U32 sh_info; - U64 sh_addralign; - U64 sh_entsize; -} ELF_Shdr64; - -// X(name, code) -#define ELF_SectionTypeXList(X)\ -X(NULL, 0)\ -X(PROGBITS, 1)\ -X(SYMTAB, 2)\ -X(STRTAB, 3)\ -X(RELA, 4)\ -X(HASH, 5)\ -X(DYNAMIC, 6)\ -X(NOTE, 7)\ -X(NOBITS, 8)\ -X(REL, 9)\ -X(SHLIB, 10)\ -X(DYNSYM, 11)\ -X(INIT_ARRAY, 14)\ -X(FINI_ARRAY, 15)\ -X(PREINIT_ARRAY, 16)\ -X(GROUP, 17)\ -X(SYMTAB_SHNDX, 18)\ -X(LOOS, 0x60000000)\ -X(HIOS, 0x6FFFFFFF)\ -X(LOPROC, 0x70000000)\ -X(HIPROC, 0x7FFFFFFF)\ -X(LOUSER, 0x80000000)\ -X(HIUSER, 0x8FFFFFFF) - -typedef enum ELF_SectionType{ -#define X(N,C) ELF_SectionType_##N = C, - ELF_SectionTypeXList(X) -#undef X -} ELF_SectionType; - -typedef enum ELF_SectionAttributeFlags{ - ELF_SectionAttributeFlag_WRITE = 0x001, - ELF_SectionAttributeFlag_ALLOC = 0x002, - ELF_SectionAttributeFlag_EXECINSTR = 0x004, - ELF_SectionAttributeFlag_MERGE = 0x010, - ELF_SectionAttributeFlag_STRINGS = 0x020, - ELF_SectionAttributeFlag_INFO_LINK = 0x040, - ELF_SectionAttributeFlag_LINK_ORDER = 0x080, - ELF_SectionAttributeFlag_OS_NONCONFORMING = 0x100, - ELF_SectionAttributeFlag_GROUP = 0x200, - ELF_SectionAttributeFlag_TLS = 0x400, - ELF_SectionAttributeFlag_MASKOS = 0x0FF00000, - ELF_SectionAttributeFlag_MASKPROC = 0xF0000000, -} ELF_SectionAttributeFlags; - -typedef enum ELF_SectionGroupFlags{ - ELF_SectionGroupFlag_COMDAT = 0x1, - ELF_SectionGroupFlag_MASKOS = 0x0FF00000, - ELF_SectionGroupFlag_MASKPROC = 0xF0000000, -} ELF_SectionGroupFlags; - -typedef enum ELF_ReservedSymbolTableIndex{ - ELF_ReservedSymbolTableIndex_UNDEF = 0, -} ELF_ReservedSymbolTableIndex; - -// symbol table - -typedef struct ELF_Sym32{ - U32 st_name; - U32 st_value; - U32 st_size; - U8 st_info; - U8 st_other; - U16 st_shndx; -} ELF_Sym32; - -typedef struct ELF_Sym64{ - U32 st_name; - U8 st_info; - U8 st_other; - U16 st_shndx; - U64 st_value; - U64 st_size; -} ELF_Sym64; - -#define ELF_SymBindingFromInfo(x) (ELF_SymbolBinding)((x)>>4) -#define ELF_SymTypeFromInfo(x) (ELF_SymbolType)((x)&0xF) -#define ELF_SymInfoFromBindingType(b,t) ((((b)<<4)&0xF)|((t)&0xF)) - -#define ELF_SymVisibilityFromOther(x) ((x)&0x3) -#define ELF_SymOtherFromVisibility(x) ((x)&0x3) - -#define ELF_SymbolBindingXList(X)\ -X(LOCAL, 0)\ -X(GLOBAL, 1)\ -X(WEAK, 2)\ -X(LOOS, 10)\ -X(HIOS, 12)\ -X(LOPROC, 13)\ -X(HIPROC, 15)\ - -typedef enum ELF_SymbolBinding{ -#define X(N,C) ELF_SymbolBinding_##N = C, - ELF_SymbolBindingXList(X) -#undef X -} ELF_SymbolBinding; - -#define ELF_SymbolTypeXList(X)\ -X(NOTYPE, 0)\ -X(OBJECT, 1)\ -X(FUNC, 2)\ -X(SECTION, 3)\ -X(FILE, 4)\ -X(COMMON, 5)\ -X(TLS, 6)\ -X(LOOS, 10)\ -X(HIOS, 12)\ -X(LOPROC, 13)\ -X(HIPROC, 15) - -typedef enum ELF_SymbolType{ -#define X(N,C) ELF_SymbolType_##N = C, - ELF_SymbolTypeXList(X) -#undef X -} ELF_SymbolType; - -#define ELF_SymbolVisibilityXList(X)\ -X(DEFAULT, 0)\ -X(INTERNAL, 1)\ -X(HIDDEN, 2)\ -X(PROTECTED, 3) - -typedef enum ELF_SymbolVisibility{ -#define X(N,C) ELF_SymbolVisibility_##N = C, - ELF_SymbolVisibilityXList(X) -#undef X -} ELF_SymbolVisibility; - -// relocation - -typedef struct ELF_Rel32{ - U32 r_offset; - U32 r_info; -} ELF_Rel32; - -typedef struct ELF_Rela32{ - U32 r_offset; - U32 r_info; - S32 r_addend; -} ELF_Rela32; - -typedef struct ELF_Rel64{ - U64 r_offset; - U64 r_info; -} ELF_Rel64; - -typedef struct ELF_Rela64{ - U64 r_offset; - U64 r_info; - S64 r_addend; -} ELF_Rela64; - -#define ELF_RelSymIndexFromInfo32(x) ((x)>>8) -#define ELF_RelTypeFromInfo32(x) ((x)&0xF) -#define ELF_RelInfoFromSymIndexType32(n,t) (((n)<<8)|((t)&0xF)) - -#define ELF_RelSymIndexFromInfo64(x) ((x)>>32) -#define ELF_RelTypeFromInfo64(x) ((x)&0xFFFFFFFFL) -#define ELF_RelInfoFromSymIndexType64(n,t) (((n)<<8)|((t)&0xFFFFFFFFL)) - - - -// program header - -typedef struct ELF_Phdr32{ - U32 p_type; - U32 p_offset; - U32 p_vaddr; - U32 p_paddr; - U32 p_filesz; - U32 p_memsz; - U32 p_flags; - U32 p_align; -} ELF_Phdr32; - -typedef struct ELF_Phdr64{ - U32 p_type; - U32 p_flags; - U64 p_offset; - U64 p_vaddr; - U64 p_paddr; - U64 p_filesz; - U64 p_memsz; - U64 p_align; -} ELF_Phdr64; - -typedef enum ELF_SegmentType{ - ELF_SegmentType_NULL = 0, - ELF_SegmentType_LOAD = 1, - ELF_SegmentType_DYNAMIC = 2, - ELF_SegmentType_INTERP = 3, - ELF_SegmentType_NOTE = 4, - ELF_SegmentType_SHLIB = 5, - ELF_SegmentType_PHDR = 6, - ELF_SegmentType_TLS = 7, - ELF_SegmentType_LOOS = 0x60000000, - ELF_SegmentType_HIOS = 0x6fffffff, - ELF_SegmentType_LOPROC = 0x70000000, - ELF_SegmentType_HIPROC = 0x7fffffff, -} ELF_SegmentType; - -typedef enum ELF_SegmentFlags{ - ELF_SegmentFlag_X = 0x1, - ELF_SegmentFlag_W = 0x2, - ELF_SegmentFlag_R = 0x4, - ELF_SegmentFlag_MASKOS = 0x0FF00000, - ELF_SegmentFlag_MASKPROC = 0xF0000000, -} ELF_SegmentFlags; - -//////////////////////////////// -//~ ELF Parser Types - -// elf top level - -typedef struct ELF_SectionArray{ - ELF_Shdr64 *sections; - U64 count; -} ELF_SectionArray; - -typedef struct ELF_SegmentArray{ - ELF_Phdr64 *segments; - U64 count; -} ELF_SegmentArray; - -typedef struct ELF_Parsed{ - String8 data; - ELF_Class elf_class; - Arch arch; - - ELF_Shdr64 *sections; - String8 *section_names; - U64 section_foff; - U64 section_count; - - ELF_Phdr64 *segments; - U64 segment_foff; - U64 segment_count; - - U64 vbase; - U64 entry_vaddr; - U64 section_name_table_foff; - U64 section_name_table_opl; - - U64 strtab_idx; - U64 symtab_idx; - U64 dynsym_idx; -} ELF_Parsed; - -// elf symtab - -typedef struct ELF_SymArray{ - ELF_Sym64 *symbols; - U64 count; -} ELF_SymArray; - -//////////////////////////////// -//~ ELF Parser Functions - -static ELF_Parsed* elf_parsed_from_data(Arena *arena, String8 elf_data); - -static ELF_SectionArray elf_section_array_from_elf(ELF_Parsed *elf); -static String8Array elf_section_name_array_from_elf(ELF_Parsed *elf); -static ELF_SegmentArray elf_segment_array_from_elf(ELF_Parsed *elf); - -static String8 elf_section_name_from_name_offset(ELF_Parsed *elf, U64 offset); -static String8 elf_section_name_from_idx(ELF_Parsed *elf, U32 idx); -static U32 elf_section_idx_from_name(ELF_Parsed *elf, String8 name); - -static String8 elf_section_data_from_idx(ELF_Parsed *elf, U32 idx); - -static ELF_SymArray elf_sym_array_from_data(Arena *arena, ELF_Class elf_class, String8 data); - -// string functions - -static String8 elf_string_from_section_type(ELF_SectionType section_type); -static String8 elf_string_from_symbol_binding(ELF_SymbolBinding binding); -static String8 elf_string_from_symbol_type(ELF_SymbolType type); -static String8 elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility); - -#endif //RDI_ELF_H diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c index bfb70be2..8d600762 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1,894 +1,1981 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -//////////////////////////////// -//~ rjf: Build Options - -#define BUILD_TITLE "rdi_from_dwarf" -#define BUILD_CONSOLE_INTERFACE 1 - -//////////////////////////////// -//~ rjf: Includes - -//- rjf: [lib] -#include "lib_rdi_format/rdi_format.h" -#include "lib_rdi_format/rdi_format.c" -#include "third_party/rad_lzb_simple/rad_lzb_simple.h" -#include "third_party/rad_lzb_simple/rad_lzb_simple.c" - -//- rjf: [h] -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "rdi_make/rdi_make_local.h" -#include "rdi_elf.h" -#include "rdi_dwarf.h" -#include "rdi_dwarf_stringize.h" -#include "rdi_from_dwarf.h" - -//- rjf: [c] -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "rdi_make/rdi_make_local.c" -#include "rdi_elf.c" -#include "rdi_dwarf.c" -#include "rdi_dwarf_stringize.c" - -// TODO(allen): -// [ ] need sample data for .debug_names - -//////////////////////////////// -//~ Program Parameters Parser - -static DWARFCONV_Params* -dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ - DWARFCONV_Params *result = push_array(arena, DWARFCONV_Params, 1); - result->unit_idx_max = ~0ull; - - // get input pdb - { - String8 input_name = cmd_line_string(cmdline, str8_lit("elf")); - if (input_name.size == 0){ - str8_list_push(arena, &result->errors, - str8_lit("missing required parameter '--elf:'")); - } - - if (input_name.size > 0){ - String8 input_data = os_data_from_file_path(arena, input_name); - - if (input_data.size == 0){ - str8_list_pushf(arena, &result->errors, - "could not load input file '%.*s'", str8_varg(input_name)); - } - - if (input_data.size != 0){ - result->input_elf_name = input_name; - result->input_elf_data = input_data; - } - } - } - - // get output name - { - result->output_name = cmd_line_string(cmdline, str8_lit("out")); - } - - // error options - if (cmd_line_has_flag(cmdline, str8_lit("hide_errors"))){ - String8List vals = cmd_line_strings(cmdline, str8_lit("hide_errors")); - - // if no values - set all to hidden - if (vals.node_count == 0){ - B8 *ptr = (B8*)&result->hide_errors; - B8 *opl = ptr + sizeof(result->hide_errors); - for (;ptr < opl; ptr += 1){ - *ptr = 1; - } - } - - // for each explicit value set the corresponding flag to hidden - for (String8Node *node = vals.first; - node != 0; - node = node->next){ - if (str8_match(node->string, str8_lit("input"), 0)){ - result->hide_errors.input = 1; - } - } - - } - - // unit idx selector - if (cmd_line_has_flag(cmdline, str8_lit("unit_idx"))){ - String8List vals = cmd_line_strings(cmdline, str8_lit("unit_idx")); - - // single value unit index - if (vals.node_count == 1){ - U64 idx = u64_from_str8(vals.first->string, 10); - result->unit_idx_min = idx; - result->unit_idx_max = idx; - } - - // range value unit index - else if (vals.node_count >= 2){ - U64 idx_a = u64_from_str8(vals.first->string, 10); - U64 idx_b = u64_from_str8(vals.first->next->string, 10); - result->unit_idx_min = Min(idx_a, idx_b); - result->unit_idx_max = Max(idx_a, idx_b); - } - } - - // dump options - if (cmd_line_has_flag(cmdline, str8_lit("dump"))){ - result->dump = 1; - - String8List vals = cmd_line_strings(cmdline, str8_lit("dump")); - if (vals.first == 0){ - B8 *ptr = &result->dump__first; - for (; ptr < &result->dump__last; ptr += 1){ - *ptr = 1; - } - } - else{ - for (String8Node *node = vals.first; - node != 0; - node = node->next){ - if (str8_match(node->string, str8_lit("header"), 0)){ - result->dump_header = 1; - } - else if (str8_match(node->string, str8_lit("sections"), 0)){ - result->dump_sections = 1; - } - else if (str8_match(node->string, str8_lit("segments"), 0)){ - result->dump_segments = 1; - } - else if (str8_match(node->string, str8_lit("symtab"), 0)){ - result->dump_symtab = 1; - } - else if (str8_match(node->string, str8_lit("dynsym"), 0)){ - result->dump_dynsym = 1; - } - else if (str8_match(node->string, str8_lit("debug_sections"), 0)){ - result->dump_debug_sections = 1; - } - else if (str8_match(node->string, str8_lit("debug_info"), 0)){ - result->dump_debug_info = 1; - } - else if (str8_match(node->string, str8_lit("debug_abbrev"), 0)){ - result->dump_debug_abbrev = 1; - } - else if (str8_match(node->string, str8_lit("debug_pubnames"), 0)){ - result->dump_debug_pubnames = 1; - } - else if (str8_match(node->string, str8_lit("debug_pubtypes"), 0)){ - result->dump_debug_pubtypes = 1; - } - else if (str8_match(node->string, str8_lit("debug_names"), 0)){ - result->dump_debug_names = 1; - } - else if (str8_match(node->string, str8_lit("debug_aranges"), 0)){ - result->dump_debug_aranges = 1; - } - else if (str8_match(node->string, str8_lit("debug_addr"), 0)){ - result->dump_debug_addr = 1; - } - } - } - } - - return(result); -} - -//////////////////////////////// -//~ Entry Point - -static void -dump_symtab(Arena *arena, String8List *out, ELF_SymArray *symbols, String8 strtab, - U32 indent){ - static char spaces[] = " "; - - U8 *str_first = strtab.str; - U8 *str_opl = strtab.str + strtab.size; - - ELF_Sym64 *symbol = symbols->symbols; - U64 count = symbols->count; - for (U64 i = 0; i < count; i += 1, symbol += 1){ - U8 *name_first = str_first + symbol->st_name; - U8 *name_opl = name_first; - for (;name_opl < str_opl && *name_opl != 0;) name_opl += 1; - String8 name = str8_range(name_first, name_opl); - - ELF_SymbolBinding binding = ELF_SymBindingFromInfo(symbol->st_info); - String8 binding_string = elf_string_from_symbol_binding(binding); - - ELF_SymbolType type = ELF_SymTypeFromInfo(symbol->st_info); - String8 type_string = elf_string_from_symbol_type(type); - - ELF_SymbolVisibility vis = ELF_SymVisibilityFromOther(symbol->st_other); - String8 vis_string = elf_string_from_symbol_visibility(vis); - - str8_list_pushf(arena, out, - "%.*ssymbol[%5llu] %6.*s %7.*s %9.*s 0x%08llx size=%-5llu sec=%-5u " - "%.*s\n", - indent, spaces, i, - str8_varg(binding_string), str8_varg(type_string), - str8_varg(vis_string), - symbol->st_value, symbol->st_size, - symbol->st_shndx, str8_varg(name)); - } -} - -#if 0 -static void -dump_entry_tree(Arena *arena, String8List *out, - DWARF_Parsed *dwarf, DWARF_InfoUnit *unit, - DWARF_InfoEntry *entry, U32 indent){ - static char spaces[] = " "; - - DWARF_AbbrevDecl *abbrev_decl = entry->abbrev_decl; - - // tag - DWARF_Tag tag = abbrev_decl->tag; - String8 tag_string = dwarf_string_from_tag(tag); - str8_list_pushf(arena, out, "%.*sentry(@%llx) TAG %.*s\n", - indent, spaces, entry->info_offset, str8_varg(tag_string)); - - // attributes - U32 attrib_count = abbrev_decl->attrib_count; - DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; - DWARF_InfoAttribVal *attrib_val = entry->attrib_vals; - for (U32 i = 0; i < attrib_count; i += 1, attrib_spec += 1, attrib_val += 1){ - // attribute name - DWARF_AttributeName name = attrib_spec->name; - String8 name_string = dwarf_string_from_attribute_name(name); - str8_list_pushf(arena, out, "%.*sATTR %.*s ", indent + 4, spaces, str8_varg(name_string)); - - // attribute value - switch (attrib_spec->form){ - default: - { - String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form); - str8_list_pushf(arena, out, " {%llu, 0x%p}\n", - str8_varg(form_string), attrib_val->val, attrib_val->dataptr); - }break; - - case DWARF_AttributeForm_strp: - { - String8 str = {0}; - - String8 data = dwarf->debug_data[DWARF_SectionCode_Str]; - U64 off = attrib_val->val; - if (off < data.size){ - U8 *start = data.str + off; - U8 *opl = data.str + data.size; - U8 *ptr = start; - for (;ptr < opl && *ptr != 0;) ptr += 1; - str = str8_range(start, ptr); - } - - str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str)); - }break; - - case DWARF_AttributeForm_sec_offset: - { - DWARF_AttributeClassFlags attr_classes1 = dwarf_attribute_class_from_name(name); - DWARF_AttributeClassFlags attr_classes2 = DWARF_AttributeClassFlag_sec_offset_classes; - DWARF_AttributeClassFlags attr_classes = attr_classes1&attr_classes2; - - DWARF_SectionCode sec_code = DWARF_SectionCode_Null; - if (unit->dwarf_version == 5){ - switch (attr_classes){ - case DWARF_AttributeClassFlag_addrptr: sec_code = DWARF_SectionCode_Addr; break; - case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break; - case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_LocLists; break; - case DWARF_AttributeClassFlag_loclistsptr: sec_code = DWARF_SectionCode_LocLists; break; - case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_Macro; break; - case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_RngLists; break; - case DWARF_AttributeClassFlag_rnglistsptr: sec_code = DWARF_SectionCode_RngLists; break; - case DWARF_AttributeClassFlag_stroffsetsptr: sec_code = DWARF_SectionCode_StrOffsets; break; - } - } - else if (unit->dwarf_version == 4){ - switch (attr_classes){ - case DWARF_AttributeClassFlag_lineptr: sec_code = DWARF_SectionCode_Line; break; - case DWARF_AttributeClassFlag_loclist: sec_code = DWARF_SectionCode_Loc; break; - case DWARF_AttributeClassFlag_macptr: sec_code = DWARF_SectionCode_MacInfo; break; - case DWARF_AttributeClassFlag_rnglist: sec_code = DWARF_SectionCode_Ranges; break; - } - } - - String8 sec_name = dwarf_name_from_debug_section(dwarf, sec_code); - str8_list_pushf(arena, out, "sec(%.*s) + %llu\n", str8_varg(sec_name), attrib_val->val); - }break; - - case DWARF_AttributeForm_ref1: - case DWARF_AttributeForm_ref2: - case DWARF_AttributeForm_ref4: - case DWARF_AttributeForm_ref8: - case DWARF_AttributeForm_ref_udata: - { - str8_list_pushf(arena, out, "entry(@%llx)\n", attrib_val->val); - }break; - - case DWARF_AttributeForm_addr: - { - str8_list_pushf(arena, out, "0x%llx\n", attrib_val->val); - }break; - - case DWARF_AttributeForm_exprloc: - { - str8_list_pushf(arena, out, "expression\n"); - // TODO(allen): dwarf expression dumping - }break; - - case DWARF_AttributeForm_strx1: - case DWARF_AttributeForm_strx2: - case DWARF_AttributeForm_strx3: - case DWARF_AttributeForm_strx4: - { - String8 str = {0}; - - U32 idx = attrib_val->val; - U64 str_offsets_off = unit->str_offsets_base + idx*unit->offset_size; - - String8 str_offsets = dwarf->debug_data[DWARF_SectionCode_StrOffsets]; - if (str_offsets_off + unit->offset_size < str_offsets.size){ - U64 off = 0; - MemoryCopy(&off, str_offsets.str + str_offsets_off, unit->offset_size); - - String8 data = dwarf->debug_data[DWARF_SectionCode_Str]; - if (off < data.size){ - U8 *start = data.str + off; - U8 *opl = data.str + data.size; - U8 *ptr = start; - for (;ptr < opl && *ptr != 0;) ptr += 1; - str = str8_range(start, ptr); - } - } - - str8_list_pushf(arena, out, "'%.*s'\n", str8_varg(str)); - }break; - - case DWARF_AttributeForm_addrx: - case DWARF_AttributeForm_addrx1: - case DWARF_AttributeForm_addrx2: - case DWARF_AttributeForm_addrx3: - case DWARF_AttributeForm_addrx4: - { - U64 address = 0; - - U32 idx = attrib_val->val; - U64 address_off = unit->addr_base + idx*unit->address_size; - - String8 data = dwarf->debug_data[DWARF_SectionCode_Addr]; - if (address_off + unit->address_size < data.size){ - MemoryCopy(&address, data.str + address_off, unit->address_size); - } - - str8_list_pushf(arena, out, "0x%x\n", address); - }break; - - case DWARF_AttributeForm_rnglistx: - { - U64 rnglist_off = unit->rnglists_base + attrib_val->val; - int x = 0; - }break; - - case DWARF_AttributeForm_data1: - case DWARF_AttributeForm_data2: - case DWARF_AttributeForm_data4: - case DWARF_AttributeForm_data8: - case DWARF_AttributeForm_data16: - case DWARF_AttributeForm_udata: - case DWARF_AttributeForm_implicit_const: - case DWARF_AttributeForm_flag: - case DWARF_AttributeForm_flag_present: - { - str8_list_pushf(arena, out, "%llu\n", attrib_val->val); - }break; - - case DWARF_AttributeForm_sdata: - { - str8_list_pushf(arena, out, "%lld\n", (S64)attrib_val->val); - }break; - - case DWARF_AttributeForm_string: - { - str8_list_pushf(arena, out, "'%.*s'\n", (int)attrib_val->val, attrib_val->dataptr); - }break; - } - } - - // dump children - for (DWARF_InfoEntry *child = entry->first_child; - child != 0; - child = child->next_sibling){ - dump_entry_tree(arena, out, dwarf, unit, child, indent + 1); - } -} -#endif - -internal void -entry_point(CmdLine *cmd_line) +internal D2R_User2Convert * +d2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline) { - Arena *arena = arena_alloc(); - - // parse arguments - DWARFCONV_Params *params = dwarf_convert_params_from_cmd_line(arena, cmd_line); - - // show input errors - if (params->errors.node_count > 0 && - !params->hide_errors.input){ - for (String8Node *node = params->errors.first; - node != 0; - node = node->next){ - fprintf(stdout, "error(input): %.*s\n", str8_varg(node->string)); + D2R_User2Convert *result = push_array(arena, D2R_User2Convert, 1); + + String8 exe_name = cmd_line_string(cmdline, str8_lit("exe")); + String8 debug_name = cmd_line_string(cmdline, str8_lit("debug")); + String8 out_name = cmd_line_string(cmdline, str8_lit("out")); + + // error check params + if (exe_name.size == 0 && debug_name.size == 0) { + str8_list_pushf(arena, &result->errors, "Missing one of the required parameters: '--exe:' or '--debug:'"); + } + if (out_name.size == 0) { + str8_list_pushf(arena, &result->errors, "Missing required parameter: '--out:'"); + } + + // get input EXE or ELF + if (exe_name.size > 0) { + String8 exe_data = os_data_from_file_path(arena, exe_name); + if (exe_data.size == 0) { + str8_list_pushf(arena, &result->errors, "Could not load input EXE file from '%S'", exe_name); + } else { + result->input_exe_name = exe_name; + result->input_exe_data = exe_data; } } - - // will we try to parse an input file? - B32 try_parse_input = (params->errors.node_count == 0); - - // track parse success - B32 successful_parse = 1; - -#define PARSE_CHECK_ERROR(p, fmt, ...) do{ if ((p) == 0){ \ -successful_parse = 0; \ -fprintf(stdout, "error(parsing): " fmt "\n",##__VA_ARGS__); \ -} }while(0) - - // parse elf - ELF_Parsed *elf = 0; - if (try_parse_input) ProfScope("parse elf"){ - elf = elf_parsed_from_data(arena, params->input_elf_data); - PARSE_CHECK_ERROR(elf, "ELF"); - } - - // parse strtab - String8 strtab = {0}; - if (elf != 0) ProfScope("parse strtab"){ - strtab = elf_section_data_from_idx(elf, elf->strtab_idx); - } - - // parse symtab - ELF_SymArray symtab = {0}; - if (elf != 0) ProfScope("parse symtab"){ - String8 data = elf_section_data_from_idx(elf, elf->symtab_idx); - symtab = elf_sym_array_from_data(arena, elf->elf_class, data); - } - - // parse dynsym - ELF_SymArray dynsym = {0}; - if (elf != 0) ProfScope("parse dynsym"){ - String8 data = elf_section_data_from_idx(elf, elf->dynsym_idx); - dynsym = elf_sym_array_from_data(arena, elf->elf_class, data); - } - - // parse dwarf - DWARF_Parsed *dwarf = 0; - if (elf != 0) ProfScope("parse dwarf"){ - dwarf = dwarf_parsed_from_elf(arena, elf); - PARSE_CHECK_ERROR(dwarf, "DWARF"); - } - - // parse info - DWARF_InfoParsed *info = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Info]; - if (data.size > 0) ProfScope("parse .debug_info"){ - info = dwarf_info_from_data(arena, data); - PARSE_CHECK_ERROR(info, "DEBUG INFO"); + + // get input DEBUG + if (debug_name.size > 0) { + String8 debug_data = os_data_from_file_path(arena, debug_name); + if (debug_data.size == 0) { + str8_list_pushf(arena, &result->errors, "Could not load input DEBUG file from '%S'", debug_name); + } else { + result->input_debug_name = debug_name; + result->input_debug_data = debug_data; } } - - // parse pubnames - DWARF_PubNamesParsed *pubnames = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_PubNames]; - if (data.size) ProfScope("parse .debug_pubnames"){ - pubnames = dwarf_pubnames_from_data(arena, data); - PARSE_CHECK_ERROR(pubnames, "DEBUG PUBNAMES"); + + result->output_name = out_name; + result->flags = ~0ull; + + String8List only_names = cmd_line_strings(cmdline, str8_lit("only")); + String8List omit_names = cmd_line_strings(cmdline, str8_lit("omit")); + + if (only_names.node_count > 0) { + result->flags = 0; + for (String8Node *i = only_names.first; i != 0; i = i->next) { +#define X(t,n,k) if (str8_match_lit(Stringify(n), i->string, StringMatchFlag_CaseInsensitive)) \ + result->flags |= D2R_ConvertFlag_##t; + RDI_SectionKind_XList +#undef X } } - - // parse pubtypes - DWARF_PubNamesParsed *pubtypes = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_PubTypes]; - if (data.size) ProfScope("parse .debug_pubtypes"){ - pubtypes = dwarf_pubnames_from_data(arena, data); - PARSE_CHECK_ERROR(pubtypes, "DEBUG PUBTYPES"); + + if (omit_names.node_count > 0) { + for (String8Node *i = omit_names.first; i != 0; i = i->next) { +#define X(t,n,k) if (str8_match_lit(Stringify(n), i->string, StringMatchFlag_CaseInsensitive)) \ + result->flags &= ~D2R_ConvertFlag_##t; + RDI_SectionKind_XList +#undef X } } - - // parse names - DWARF_NamesParsed *names = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Names]; - if (data.size) ProfScope("parse .debug_names"){ - names = dwarf_names_from_data(arena, data); - PARSE_CHECK_ERROR(names, "DEBUG NAMES"); + + return result; +} + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code_x64(U64 reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX64_##reg_name_dw: return RDI_RegCodeX64_##reg_name_rdi; + DW_Regs_X64_XList(X) +#undef X + } + InvalidPath; + return 0; +} + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code_x86(U64 reg_code) +{ + switch (reg_code) { +#define X(reg_name_dw, reg_code_dw, reg_name_rdi, reg_pos, reg_size) case DW_RegX86_##reg_name_dw: return RDI_RegCodeX86_##reg_name_rdi; + DW_Regs_X86_XList(X) +#undef X + } + InvalidPath; + return 0; +} + +internal RDI_RegCode +d2r_rdi_reg_from_dw_reg_code(RDI_Arch arch, U64 reg_code) +{ + switch (arch) { + case RDI_Arch_NULL: return 0; + case RDI_Arch_X64: return d2r_rdi_reg_from_dw_reg_code_x64(reg_code); + case RDI_Arch_X86: return d2r_rdi_reg_from_dw_reg_code_x86(reg_code); + } + InvalidPath; + return 0; +} + +internal RDIM_Type * +d2r_create_type(Arena *arena, D2R_TypeTable *type_table) +{ + RDIM_Type *type = rdim_type_chunk_list_push(arena, type_table->types, type_table->type_chunk_cap); + return type; +} + +internal RDIM_Type * +d2r_find_or_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off) +{ + RDIM_Type *type = 0; + KeyValuePair *is_type_present = hash_table_search_u64(type_table->ht, info_off); + if (is_type_present) { + type = is_type_present->value_raw; + } else { + type = d2r_create_type(arena, type_table); + hash_table_push_u64_raw(arena, type_table->ht, info_off, type); + } + return type; +} + +internal RDIM_Type * +d2r_type_from_attrib(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind) +{ + RDIM_Type *type = 0; + + // find attrib + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + + // does tag have this attribute? + if (attrib->attrib_kind == kind) { + DW_AttribClass value_class = dw_value_class_from_attrib(cu, attrib); + + if (value_class == DW_AttribClass_Reference) { + // resolve reference + DW_Reference ref = dw_ref_from_attrib_ptr(input, cu, attrib); + + // TODO: support for external compile unit references + AssertAlways(ref.cu == cu); + + // find or create type + type = d2r_find_or_create_type_from_offset(arena, type_table, ref.info_off); + } else { + Assert(!"unexpected attrib class"); + } + } else if (attrib->attrib_kind == DW_Attrib_Null) { + type = type_table->void_type; + } + + return type; +} + +internal Rng1U64List +d2r_range_list_from_tag(Arena *arena, DW_Input *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag) +{ + // collect non-contiguous range + Rng1U64List ranges = dw_rnglist_from_attrib(arena, input, cu, tag, DW_Attrib_Ranges); + + // collect contiguous range + DW_Attrib *lo_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_Attrib_LowPc); + DW_Attrib *hi_pc_attrib = dw_attrib_from_tag(input, cu, tag, DW_Attrib_HighPc); + if (lo_pc_attrib->attrib_kind != DW_Attrib_Null && hi_pc_attrib->attrib_kind != DW_Attrib_Null) { + U64 lo_pc = dw_address_from_attrib_ptr(input, cu, lo_pc_attrib); + + U64 hi_pc; + DW_AttribClass hi_pc_class = dw_value_class_from_attrib(cu, hi_pc_attrib); + if (hi_pc_class == DW_AttribClass_Address) { + hi_pc = dw_address_from_attrib_ptr(input, cu, hi_pc_attrib); + } else if (hi_pc_class == DW_AttribClass_Const) { + hi_pc = dw_const_u64_from_attrib_ptr(input, cu, hi_pc_attrib); + hi_pc += lo_pc; + } else { + AssertAlways(!"undefined attrib encoding"); + } + + // TODO: error handling + AssertAlways(lo_pc >= image_base); + AssertAlways(hi_pc >= image_base); + AssertAlways(lo_pc <= hi_pc); + + U64 lo_voff = lo_pc - image_base; + U64 hi_voff = hi_pc - image_base; + rng1u64_list_push(arena, &ranges, rng_1u64(lo_voff, hi_voff)); + } + + return ranges; +} + +internal RDIM_Type ** +d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Input *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out) +{ + Temp scratch = scratch_begin(&arena, 1); + + RDIM_TypeList list = {0}; + B32 has_vargs = 0; + for (DW_TagNode *i = cur_node->first_child; i != 0; i = i->sibling) { + if (i->tag.kind == DW_Tag_FormalParameter) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = d2r_type_from_attrib(arena, type_table, input, cu, i->tag, DW_Attrib_Type); + SLLQueuePush(list.first, list.last, n); + ++list.count; + } else if (i->tag.kind == DW_Tag_UnspecifiedParameters) { + has_vargs = 1; } } - - // parse aranges - DWARF_ArangesParsed *aranges = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Aranges]; - if (data.size) ProfScope("parse .debug_aranges"){ - aranges = dwarf_aranges_from_data(arena, data); - PARSE_CHECK_ERROR(aranges, "DEBUG ARANGES"); - } + + if (has_vargs) { + RDIM_TypeNode *n = push_array(scratch.arena, RDIM_TypeNode, 1); + n->v = type_table->varg_type; + SLLQueuePush(list.first, list.last, n); + ++list.count; } - - // parse addr - DWARF_AddrParsed *addr = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Addr]; - if (data.size) ProfScope("parse .debug_addr"){ - addr = dwarf_addr_from_data(arena, data); - PARSE_CHECK_ERROR(addr, "DEBUG ADDR"); - } - } - -#if 0 - // parse abbrev - DWARF_AbbrevParsed *abbrev = 0; - if (dwarf != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Abbrev]; - if (data.size > 0) ProfScope("parse .debug_abbrev"){ - DWARF_AbbrevParams abbrev_params = {0}; - abbrev_params.unit_idx_min = params->unit_idx_min; - abbrev_params.unit_idx_max = params->unit_idx_max; - abbrev = dwarf_abbrev_from_data(arena, data, &abbrev_params); - PARSE_CHECK_ERROR(abbrev, "DEBUG ABBREV"); - } - } - - // parse info - DWARF_InfoParsed *info = 0; - if (abbrev != 0){ - String8 data = dwarf->debug_data[DWARF_SectionCode_Info]; - if (data.size > 0) ProfScope("parse .debug_info"){ - DWARF_InfoParams info_params = {0}; - info_params.unit_idx_min = params->unit_idx_min; - info_params.unit_idx_max = params->unit_idx_max; - info = dwarf_info_from_data(arena, data, &info_params, abbrev); - PARSE_CHECK_ERROR(info, "DEBUG INFO"); - } - } -#endif - - // dump - if (params->dump) ProfScope("dump"){ - String8List dump = {0}; - - // ELF - if (params->dump_header){ - if (elf != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "ELF:\n")); - - // TODO: better stringizers for fields here - str8_list_pushf(arena, &dump, " elf_class=%u\n", elf->elf_class); - str8_list_pushf(arena, &dump, " arch=%u\n", elf->arch); - str8_list_pushf(arena, &dump, " section_count=%llu\n", elf->section_count); - str8_list_pushf(arena, &dump, " segment_count=%llu\n", elf->segment_count); - str8_list_pushf(arena, &dump, " vbase=0x%llx\n", elf->vbase); - str8_list_pushf(arena, &dump, " entry_vaddr=0x%llx\n", elf->vbase); - - str8_list_push(arena, &dump, str8_lit("\n")); + + // collect params + *param_count_out = list.count; + RDIM_Type **params = rdim_array_from_type_list(arena, list); + + scratch_end(scratch); + return params; +} + + +internal RDIM_EvalBytecode +d2r_bytecode_from_expression(Arena *arena, U64 image_base, U64 address_size, RDI_Arch arch, DW_ListUnit *addr_lu, String8 expr) +{ + RDIM_EvalBytecode bc = {0}; + + for (U64 cursor = 0; cursor < expr.size; ) { + U8 op = 0; + cursor += str8_deserial_read_struct(expr, cursor, &op); + + U64 size_param; + switch (op) { + case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2: + case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5: + case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8: + case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11: + case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14: + case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17: + case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20: + case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23: + case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26: + case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29: + case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: { + U64 lit = op - DW_ExprOp_Lit0; + rdim_bytecode_push_uconst(arena, &bc, lit); + } break; + + case DW_ExprOp_Const1U: size_param = 1; goto const_unsigned; + case DW_ExprOp_Const2U: size_param = 2; goto const_unsigned; + case DW_ExprOp_Const4U: size_param = 4; goto const_unsigned; + case DW_ExprOp_Const8U: size_param = 8; goto const_unsigned; + const_unsigned: { + U64 val = 0; + cursor += str8_deserial_read(expr, cursor, &val, size_param, size_param); + rdim_bytecode_push_uconst(arena, &bc, val); + } break; + + case DW_ExprOp_Const1S:size_param = 1; goto const_signed; + case DW_ExprOp_Const2S:size_param = 2; goto const_signed; + case DW_ExprOp_Const4S:size_param = 4; goto const_signed; + case DW_ExprOp_Const8S:size_param = 8; goto const_signed; + const_signed: { + S64 val = 0; + cursor += str8_deserial_read(expr, cursor, &val, size_param, size_param); + val = extend_sign64(val, size_param); + rdim_bytecode_push_sconst(arena, &bc, val); + } break; + + case DW_ExprOp_ConstU: { + U64 val = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &val); + rdim_bytecode_push_uconst(arena, &bc, val); + } break; + + case DW_ExprOp_ConstS: { + S64 val = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, &val); + rdim_bytecode_push_sconst(arena, &bc, val); + } break; + + case DW_ExprOp_Addr: { + U64 addr = 0; + cursor += str8_deserial_read(expr, cursor, &addr, address_size, address_size); + if (addr >= image_base) { + U64 voff = addr - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + } else { + // TODO: error handling + AssertAlways(!"unable to relocate address"); } - } - - // SECTIONS - if (params->dump_sections){ - if (elf != 0){ - ELF_SectionArray section_array = elf_section_array_from_elf(elf); - String8Array section_name_array = elf_section_name_array_from_elf(elf); - - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "SECTIONS:\n")); - - ELF_Shdr64 *sec = section_array.sections; - String8 *sec_name = section_name_array.v; - U64 count = section_array.count; - for (U64 i = 0 ; i < count; i += 1, sec += 1, sec_name += 1){ - String8 type_string = elf_string_from_section_type(sec->sh_type); - - // TODO: better stringizers for fields here - str8_list_pushf(arena, &dump, " section[%llu]:\n", i); - str8_list_pushf(arena, &dump, " name='%.*s'\n", str8_varg(*sec_name)); - str8_list_pushf(arena, &dump, " type=%.*s\n", str8_varg(type_string)); - str8_list_pushf(arena, &dump, " flags=0x%llx\n", sec->sh_flags); - str8_list_pushf(arena, &dump, " addr=0x%llx\n", sec->sh_addr); - str8_list_pushf(arena, &dump, " offset=0x%llx\n", sec->sh_offset); - str8_list_pushf(arena, &dump, " size=%llu\n", sec->sh_size); - str8_list_pushf(arena, &dump, " link=%u\n", sec->sh_link); - str8_list_pushf(arena, &dump, " info=%u\n", sec->sh_info); - str8_list_pushf(arena, &dump, " addralign=0x%llx\n", sec->sh_addralign); - str8_list_pushf(arena, &dump, " entsize=%llu\n", sec->sh_entsize); - str8_list_push(arena, &dump, str8_lit("\n")); + } break; + + case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2: + case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5: + case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8: + case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11: + case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14: + case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17: + case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20: + case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23: + case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26: + case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29: + case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: { + U64 reg_code_dw = op - DW_ExprOp_Reg0; + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, 8, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + } break; + + case DW_ExprOp_RegX: { + U64 reg_code_dw = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + U32 regread_param = RDI_EncodeRegReadParam(reg_code_rdi, 8, 0); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegRead, regread_param); + } break; + + case DW_ExprOp_ImplicitValue: { + U64 value_size = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &value_size); + + String8 val = str8_substr(expr, rng_1u64(cursor, cursor + value_size)); + if (val.size <= sizeof(U64)) { + U64 val64 = 0; + MemoryCopy(&val64, val.str, val.size); + rdim_bytecode_push_uconst(arena, &bc, val64); + } else { + // TODO: currenlty no way to encode string in RDIM_EvalBytecodeOp + NotImplemented; + } + } break; + + case DW_ExprOp_Piece: { + NotImplemented; + } break; + + case DW_ExprOp_BitPiece: { + NotImplemented; + } break; + + case DW_ExprOp_Pick: { + U8 stack_idx = 0; + cursor += str8_deserial_read_struct(expr, cursor, &stack_idx); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, stack_idx); + } break; + + case DW_ExprOp_PlusUConst: { + U64 addend = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &addend); + rdim_bytecode_push_uconst(arena, &bc, addend); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, 0); + } break; + + case DW_ExprOp_Skip: { + S16 skip = 0; + cursor += str8_deserial_read_struct(expr, cursor, &skip); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Skip, skip); + } break; + + case DW_ExprOp_Bra: { + NotImplemented; + } break; + + case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2: + case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5: + case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8: + case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11: + case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14: + case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17: + case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20: + case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23: + case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26: + case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29: + case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: { + U64 reg_code_dw = op - DW_ExprOp_BReg0; + S64 reg_off = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, 0); + } break; + + case DW_ExprOp_BRegX: { + U64 reg_code_dw = 0; + S64 reg_off = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, ®_code_dw); + cursor += str8_deserial_read_sleb128(expr, cursor, ®_off); + + RDI_RegCode reg_code_rdi = d2r_rdi_reg_from_dw_reg_code(arch, reg_code_dw); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RegReadDyn, reg_code_rdi); + rdim_bytecode_push_sconst(arena, &bc, reg_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, 0); + } break; + + case DW_ExprOp_FBReg: { + S64 frame_off = 0; + cursor += str8_deserial_read_sleb128(expr, cursor, &frame_off); + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, frame_off); + } break; + + case DW_ExprOp_Deref: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, address_size); + } break; + + case DW_ExprOp_DerefSize: { + U8 deref_size_in_bytes = 0; + cursor += str8_deserial_read_struct(expr, cursor, &deref_size_in_bytes); + if (0 < deref_size_in_bytes && deref_size_in_bytes <= address_size) { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_MemRead, deref_size_in_bytes); + } else { + // TODO: error handling + AssertAlways(!"ill formed expression"); + } + } break; + + case DW_ExprOp_XDerefSize: { + // TODO: error handling + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Call2: + case DW_ExprOp_Call4: + case DW_ExprOp_CallRef: { + // TODO: error handling + AssertAlways(!"calls are not supported"); + } break; + + case DW_ExprOp_ImplicitPointer: + case DW_ExprOp_GNU_ImplicitPointer: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Convert: + case DW_ExprOp_GNU_Convert: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_GNU_ParameterRef: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_DerefType: + case DW_ExprOp_GNU_DerefType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_ConstType: + case DW_ExprOp_GNU_ConstType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_RegvalType: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_EntryValue: + case DW_ExprOp_GNU_EntryValue: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Addrx: { + U64 addr_idx = 0; + cursor += str8_deserial_read_uleb128(expr, cursor, &addr_idx); + U64 addr = dw_addr_from_list_unit(addr_lu, addr_idx); + if (addr != max_U64) { + if (addr >= image_base) { + U64 voff = addr - image_base; + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_ModuleOff, voff); + } else { + // TODO: error handling + AssertAlways(!"unable to relocate address"); } + } else { + // TODO: error handling + AssertAlways(!"out of bounds index"); } + } break; + + case DW_ExprOp_CallFrameCfa: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_FrameOff, 0); + } break; + + case DW_ExprOp_FormTlsAddress: { + // TODO: + AssertAlways(!"RDI_EvalOp_TLSOff accepts immediate"); + } break; + + case DW_ExprOp_PushObjectAddress: { + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Nop: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Noop, 0); + } break; + + case DW_ExprOp_Eq: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_EqEq, 0); + } break; + + case DW_ExprOp_Ge: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_GrEq, 0); + } break; + + case DW_ExprOp_Gt: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Grtr, 0); + } break; + + case DW_ExprOp_Le: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LsEq, 0); + } break; + + case DW_ExprOp_Lt: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Less, 0); + } break; + + case DW_ExprOp_Ne: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_NtEq, 0); + } break; + + case DW_ExprOp_Shl: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_LShift, 0); + } break; + + case DW_ExprOp_Shr: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_RShift, 0); + } break; + + case DW_ExprOp_Shra: { + // TODO: + AssertAlways(!"sample"); + } break; + + case DW_ExprOp_Xor: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitXor, 0); + } break; + + case DW_ExprOp_XDeref: { + // TODO: error handling + Assert(!"multiple address spaces are not supported"); + } break; + + case DW_ExprOp_Abs: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Abs, 0); + } break; + + case DW_ExprOp_And: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitAnd, 0); + } break; + + case DW_ExprOp_Div: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Div, 0); + } break; + + case DW_ExprOp_Minus: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Sub, 0); + } break; + + case DW_ExprOp_Mod: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mod, 0); + } break; + + case DW_ExprOp_Mul: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Mul, 0); + } break; + + case DW_ExprOp_Neg: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Neg, 0); + } break; + + case DW_ExprOp_Not: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitNot, 0); + } break; + + case DW_ExprOp_Or: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_BitOr, 0); + } break; + + case DW_ExprOp_Plus: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Add, 0); + } break; + + case DW_ExprOp_Rot: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Swap: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Dup: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Drop: { + AssertAlways(!"no suitable conversion"); + } break; + + case DW_ExprOp_Over: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Pick, 1); + } break; + + case DW_ExprOp_StackValue: { + rdim_bytecode_push_op(arena, &bc, RDI_EvalOp_Stop, 0); + } break; + + default: InvalidPath; break; } - - // SYMTAB - if (symtab.count > 0 && params->dump_symtab){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "SYMTAB:\n")); - str8_list_pushf(arena, &dump, " section: %llu\n", elf->symtab_idx); - dump_symtab(arena, &dump, &symtab, strtab, 1); - str8_list_push(arena, &dump, str8_lit("\n")); + } + + return bc; +} + +internal RDIM_Location * +d2r_transpile_expression(Arena *arena, U64 image_base, U64 address_size, RDI_Arch arch, DW_ListUnit *addr_lu, String8 expr) +{ + RDIM_Location *loc = 0; + if (expr.size) { + loc = push_array(arena, RDIM_Location, 1); + loc->kind = RDI_LocationKind_AddrBytecodeStream; + loc->bytecode = d2r_bytecode_from_expression(arena, image_base, address_size, arch, addr_lu, expr); + } + return loc; +} + +internal RDIM_LocationSet +d2r_convert_loclist(Arena *arena, RDIM_ScopeChunkList *scopes, U64 image_base, U64 address_size, RDI_Arch arch, DW_ListUnit *addr_lu, DW_LocList loclist) +{ + RDIM_LocationSet locset = {0}; + for (DW_LocNode *loc_n = loclist.first; loc_n != 0; loc_n = loc_n->next) { + RDIM_Location *location = d2r_transpile_expression(arena, image_base, address_size, arch, addr_lu, loc_n->v.expr); + RDIM_Rng1U64 voff_range = { .min = loc_n->v.range.min - image_base, .min = loc_n->v.range.max - image_base }; + rdim_location_set_push_case(arena, scopes, &locset, voff_range, location); + } + return locset; +} + +internal RDIM_LocationSet +d2r_locset_from_attrib(Arena *arena, + DW_Input *input, + DW_CompUnit *cu, + RDIM_ScopeChunkList *scopes, + RDIM_Scope *curr_scope, + U64 image_base, + U64 address_size, + RDI_Arch arch, + DW_ListUnit *addr_lu, + DW_Tag tag, + DW_AttribKind kind) +{ + RDIM_LocationSet result = {0}; + + DW_Attrib *attrib = dw_attrib_from_tag(input, cu, tag, kind); + DW_AttribClass attrib_class = dw_value_class_from_attrib(cu, attrib); + + if (attrib_class == DW_AttribClass_LocList || attrib_class == DW_AttribClass_LocListPtr) { + Temp scratch = scratch_begin(&arena, 1); + DW_LocList loclist = dw_loclist_from_attrib_ptr(scratch.arena, input, cu, attrib); + result = d2r_convert_loclist(arena, scopes, image_base, address_size, arch, addr_lu, loclist); + } else if (attrib_class == DW_AttribClass_ExprLoc) { + String8 expr = dw_exprloc_from_attrib_ptr(input, cu, attrib); + RDIM_Location *location = d2r_transpile_expression(arena, image_base, address_size, arch, addr_lu, expr); + for (RDIM_Rng1U64Node *range_n = curr_scope->voff_ranges.first; range_n != 0; range_n = range_n->next) { + rdim_location_set_push_case(arena, scopes, &result, range_n->v, location); } - - // DYNSYM - if (dynsym.count > 0 && params->dump_dynsym){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DYNSYM:\n")); - str8_list_pushf(arena, &dump, " section: %llu\n", elf->dynsym_idx); - dump_symtab(arena, &dump, &dynsym, strtab, 1); - str8_list_push(arena, &dump, str8_lit("\n")); + } else if (attrib_class != DW_AttribClass_Null) { + AssertAlways(!"unexpected attrib class"); + } + + return result; +} + +internal D2R_CompUnitContribMap +d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Input *input, U64 image_base) +{ + Temp scratch = scratch_begin(&arena, 1); + + String8 aranges_data = input->sec[DW_Section_ARanges].data; + Rng1U64List unit_range_list = dw_unit_ranges_from_data(scratch.arena, aranges_data); + + D2R_CompUnitContribMap cm = {0}; + cm.count = 0; + cm.info_off_arr = push_array(arena, U64, unit_range_list.count); + cm.voff_range_arr = push_array(arena, RDIM_Rng1U64List, unit_range_list.count); + + for (Rng1U64Node *range_n = unit_range_list.first; range_n != 0; range_n = range_n->next) { + String8 unit_data = str8_substr(aranges_data, range_n->v); + U64 unit_cursor = 0; + + U64 unit_length = 0; + U64 unit_length_size = str8_deserial_read_dwarf_packed_size(unit_data, unit_cursor, &unit_length); + if (unit_length_size == 0) { + continue; } - - // SEGMENTS - if (params->dump_segments){ - if (elf != 0){ - ELF_SegmentArray segment_array = elf_segment_array_from_elf(elf); - - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "SEGMENTS:\n")); - - ELF_Phdr64 *segments = segment_array.segments; - U64 count = segment_array.count; - for (U64 i = 0 ; i < count; i += 1){ - ELF_Phdr64 *seg = segments + i; - - // TODO: better stringizers for fields here - str8_list_pushf(arena, &dump, " segment[%llu]:\n", i); - str8_list_pushf(arena, &dump, " p_type=%u\n", seg->p_type); - str8_list_pushf(arena, &dump, " p_flags=0x%x\n", seg->p_flags); - str8_list_pushf(arena, &dump, " p_offset=0x%llx\n", seg->p_offset); - str8_list_pushf(arena, &dump, " p_vaddr=0x%llx\n", seg->p_vaddr); - str8_list_pushf(arena, &dump, " p_paddr=0x%llx\n", seg->p_paddr); - str8_list_pushf(arena, &dump, " p_filesz=%llu\n", seg->p_filesz); - str8_list_pushf(arena, &dump, " p_memsz=%llu\n", seg->p_memsz); - str8_list_pushf(arena, &dump, " p_align=%llu\n", seg->p_align); - str8_list_push(arena, &dump, str8_lit("\n")); + unit_cursor += unit_length_size; + + DW_Version version = 0; + U64 version_size = str8_deserial_read_struct(unit_data, unit_cursor, &version); + if (version_size == 0) { + continue; + } + unit_cursor += version; + + if (version != DW_Version_2) { + AssertAlways(!"unknown .debug_aranges version"); + continue; + } + + DW_Format unit_format = DW_FormatFromSize(unit_length); + U64 cu_info_off = 0; + U64 cu_info_off_size = str8_deserial_read_dwarf_uint(unit_data, unit_cursor, unit_format, &cu_info_off); + if (cu_info_off_size == 0) { + continue; + } + unit_cursor += cu_info_off_size; + + U8 address_size = 0; + U64 address_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &address_size); + if (address_size_size == 0) { + continue; + } + unit_cursor += address_size_size; + + U8 segment_selector_size = 0; + U64 segment_selector_size_size = str8_deserial_read_struct(unit_data, unit_cursor, &segment_selector_size); + if (segment_selector_size_size == 0) { + continue; + } + unit_cursor += segment_selector_size_size; + + U64 tuple_size = address_size * 2 + segment_selector_size; + U64 bytes_too_far_past_boundary = unit_cursor % tuple_size; + if (bytes_too_far_past_boundary > 0) { + unit_cursor += tuple_size - bytes_too_far_past_boundary; + } + + RDIM_Rng1U64List voff_ranges = {0}; + if (segment_selector_size == 0) { + while (unit_cursor + address_size * 2 <= unit_data.size) { + U64 address = 0; + U64 length = 0; + unit_cursor += str8_deserial_read(unit_data, unit_cursor, &address, address_size, address_size); + unit_cursor += str8_deserial_read(unit_data, unit_cursor, &length, address_size, address_size); + + if (address == 0 && length == 0) { + break; } + + // TODO: error handling + AssertAlways(address >= image_base); + + U64 min = address - image_base; + U64 max = min + length; + rdim_rng1u64_list_push(arena, &voff_ranges, (RDIM_Rng1U64){.min = min, .max = max}); } + } else { + // TODO: segment relative addressing + NotImplemented; } - - // DEBUG SECTIONS - if (params->dump_debug_sections){ - if (dwarf != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG SECTIONS:\n")); - - U32 *debug_section_idx = dwarf->debug_section_idx; - String8 *debug_data = dwarf->debug_data; - for (U32 i = 1; i < DWARF_SectionCode_COUNT; i += 1, debug_data += 1){ - U32 idx = debug_section_idx[i]; - String8 name = dwarf_string_from_section_code(i); - str8_list_pushf(arena, &dump, " %-10.*s section_idx=%u\n", str8_varg(name), idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); + + U64 map_idx = cm.count++; + cm.info_off_arr[map_idx] = cu_info_off; + cm.voff_range_arr[map_idx] = voff_ranges; + } + + scratch_end(scratch); + return cm; +} + +internal RDIM_Rng1U64List +d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off) +{ + RDIM_Rng1U64List voff_ranges = {0}; + U64 voff_list_idx = u64_array_bsearch(map.info_off_arr, map.count, info_off); + if (voff_list_idx < map.count) { + voff_ranges = map.voff_range_arr[voff_list_idx]; + } + return voff_ranges; +} + +internal RDIM_Scope * +d2r_push_scope(Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagNode *tag_stack, Rng1U64List ranges) +{ + // fill out scope + RDIM_Scope *scope = rdim_scope_chunk_list_push(arena, scopes, scope_chunk_cap); + + // push ranges + for (Rng1U64Node *i = ranges.first; i != 0; i = i->next) { + rdim_scope_push_voff_range(arena, scopes, scope, (RDIM_Rng1U64){.min = i->v.min, i->v.max}); + } + + // associate scope with tag + tag_stack->scope = scope; + + // update scope hierarchy + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || parent_tag_kind == DW_Tag_InlinedSubroutine || parent_tag_kind == DW_Tag_LexicalBlock) { + RDIM_Scope *parent = tag_stack->next->scope; + + scope->parent_scope = tag_stack->next->scope; + + if (parent->last_child) { + parent->last_child->next_sibling = scope; + } + + SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); + } + + // propagate scope symbol + if (tag_stack->cur_node->tag.kind == DW_Tag_LexicalBlock) { + scope->symbol = tag_stack->next->scope->symbol; + } + + return scope; +} + +internal RDIM_BakeParams * +d2r_convert(Arena *arena, D2R_User2Convert *in) +{ + Temp scratch = scratch_begin(&arena, 1); + + B32 is_parse_relaxed = !(in->flags & D2R_ConvertFlag_StrictParse); + + RDIM_BinarySectionList binary_sections = {0}; + Arch arch = Arch_Null; + U64 image_base = 0; + U64 voff_max = 0; + DW_Input input = {0}; + DW_ListUnitInput lui = {0}; + if (pe_check_magic(in->input_exe_data)) { + PE_BinInfo pe = pe_bin_info_from_data(scratch.arena, in->input_exe_data); + + // infer exe info + arch = pe.arch; + image_base = pe.image_base; + + // get COFF sections + String8 raw_sections = str8_substr(in->input_exe_data, rng_1u64(pe.section_array_off, pe.section_array_off+sizeof(COFF_SectionHeader)*pe.section_count)); + U64 section_count = raw_sections.size / sizeof(COFF_SectionHeader); + COFF_SectionHeader *section_array = (COFF_SectionHeader *)raw_sections.str; + + // loop over section headers and pick max virtual offset + for (U64 i = 0; i < section_count; ++i) { + U64 sec_voff_max = section_array[i].voff + section_array[i].vsize; + voff_max = Max(voff_max, sec_voff_max); + } + + ProfBegin("binary sections"); + for (U64 i = 0; i < section_count; ++i) { + COFF_SectionHeader *coff_sec = §ion_array[i]; + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + + sec->name = coff_name_from_section_header(in->input_exe_data, coff_sec, pe.string_table_off); + sec->flags = rdi_binary_section_flags_from_coff_section_flags(coff_sec->flags); + sec->voff_first = coff_sec->voff; + sec->voff_opl = coff_sec->voff + coff_sec->vsize; + sec->foff_first = coff_sec->foff; + sec->foff_opl = coff_sec->foff + coff_sec->fsize; + } + ProfEnd(); + + // find DWARF sections + input = dw_input_from_coff_section_table(scratch.arena, in->input_exe_data, pe.string_table_off, section_count, section_array); + } + + //////////////////////////////// + + RDI_Arch arch_rdi = RDI_Arch_NULL; + switch (arch) { + case Arch_Null: arch_rdi = RDI_Arch_NULL; break; + case Arch_x64: arch_rdi = RDI_Arch_X64; break; + case Arch_x86: arch_rdi = RDI_Arch_X86; break; + default: NotImplemented; break; + } + + U64 arch_addr_size = rdi_addr_size_from_arch(arch_rdi); + + //////////////////////////////// + + ProfBegin("compute exe hash"); + U64 exe_hash = rdi_hash(in->input_exe_data.str, in->input_exe_data.size); + ProfEnd(); + + //////////////////////////////// + + ProfBegin("top level info"); + RDIM_TopLevelInfo top_level_info = {0}; + top_level_info.arch = arch_rdi; + top_level_info.exe_name = str8_skip_last_slash(in->input_exe_name); + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = voff_max; + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + ProfEnd(); + + //////////////////////////////// + + static const U64 UNIT_CHUNK_CAP = 256; + static const U64 UDT_CHUNK_CAP = 256; + static const U64 TYPE_CHUNK_CAP = 256; + static const U64 GVAR_CHUNK_CAP = 256; + static const U64 TVAR_CHUNK_CAP = 256; + static const U64 PROC_CHUNK_CAP = 256; + static const U64 SCOPE_CHUNK_CAP = 256; + static const U64 INLINE_SITE_CHUNK_CAP = 256; + static const U64 SRC_FILE_CAP = 256; + static const U64 LINE_TABLE_CAP = 256; + + RDIM_UnitChunkList units = {0}; + RDIM_UDTChunkList udts = {0}; + RDIM_TypeChunkList types = {0}; + RDIM_SymbolChunkList gvars = {0}; + RDIM_SymbolChunkList tvars = {0}; + RDIM_SymbolChunkList procs = {0}; + RDIM_ScopeChunkList scopes = {0}; + RDIM_InlineSiteChunkList inline_sites = {0}; + RDIM_SrcFileChunkList src_files = {0}; + RDIM_LineTableChunkList line_tables = {0}; + + //////////////////////////////// + + ProfBegin("Make Unit Contrib Map"); + D2R_CompUnitContribMap cu_contrib_map = {0}; + if (input.sec[DW_Section_ARanges].data.size > 0) { + cu_contrib_map = d2r_cu_contrib_map_from_aranges(arena, &input, image_base); + } else { + // TODO: synthesize cu ranges from scopes + NotImplemented; + } + ProfEnd(); + + ProfBegin("Parse Comop Unit Ranges"); + DW_ListUnitInput lu_input = dw_list_unit_input_from_input(scratch.arena, &input); + Rng1U64List cu_range_list = dw_unit_ranges_from_data(scratch.arena, input.sec[DW_Section_Info].data); + Rng1U64Array cu_ranges = rng1u64_array_from_list(scratch.arena, &cu_range_list); + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Compile Unit Headers"); + DW_CompUnit *cu_arr = push_array(scratch.arena, DW_CompUnit, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_arr[cu_idx] = dw_cu_from_info_off(scratch.arena, &input, lu_input, cu_ranges.v[cu_idx].min, is_parse_relaxed); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Parse Line Tables"); + DW_LineTableParseResult *cu_line_tables = push_array(scratch.arena, DW_LineTableParseResult, cu_ranges.count); + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + DW_CompUnit *cu = &cu_arr[cu_idx]; + String8 cu_stmt_list = dw_line_ptr_from_attrib(&input, cu, cu->tag, DW_Attrib_StmtList); + String8 cu_dir = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_CompDir); + String8 cu_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Name); + cu_line_tables[cu_idx] = dw_parsed_line_table_from_data(scratch.arena, cu_stmt_list, &input, cu_dir, cu_name, cu->address_size, cu->str_offsets_lu); + } + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Convert Line Tables"); + + HashTable *source_file_ht = hash_table_init(scratch.arena, 0x4000); + RDIM_LineTable **cu_line_tables_rdi = push_array(scratch.arena, RDIM_LineTable *, cu_ranges.count); + + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + cu_line_tables_rdi[cu_idx] = rdim_line_table_chunk_list_push(arena, &line_tables, LINE_TABLE_CAP); + + DW_LineTableParseResult *line_table = &cu_line_tables[cu_idx]; + DW_LineVMFileArray *dir_table = &line_table->vm_header.dir_table; + DW_LineVMFileArray *file_table = &line_table->vm_header.file_table; + RDIM_SrcFile **src_file_map = push_array(scratch.arena, RDIM_SrcFile *, file_table->count); + for (U64 file_idx = 0; file_idx < file_table->count; ++file_idx) { + DW_LineFile *file = &file_table->v[file_idx]; + String8 file_path = dw_path_from_file_idx(scratch.arena, &line_table->vm_header, file_idx); + String8List file_path_split = str8_split_path(scratch.arena, file_path); + str8_path_list_resolve_dots_in_place(&file_path_split, PathStyle_WindowsAbsolute); + String8 file_path_resolved = str8_path_list_join_by_style(scratch.arena, &file_path_split, PathStyle_WindowsAbsolute); + String8 file_path_normalized = lower_from_str8(scratch.arena, file_path_resolved); + RDIM_SrcFile *src_file = hash_table_search_path_raw(source_file_ht, file_path_normalized); + if (src_file == 0) { + src_file = rdim_src_file_chunk_list_push(arena, &src_files, SRC_FILE_CAP); + src_file->normal_full_path = push_str8_copy(arena, file_path_normalized); + hash_table_push_path_raw(scratch.arena, source_file_ht, src_file->normal_full_path, src_file); } + src_file_map[file_idx] = src_file; } - - // DEBUG INFO - if (params->dump_debug_info){ - if (info != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG INFO:\n")); - - U32 i = 0; - for (DWARF_InfoUnit *unit = info->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_info(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - + + for (DW_LineSeqNode *line_seq = line_table->first_seq; line_seq != 0; line_seq = line_seq->next) { + if (line_seq->count == 0) { + continue; } - } - - // DEBUG PUBNAMES - if (params->dump_debug_pubnames){ - if (pubnames != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG PUBNAMES:\n")); - - U32 i = 0; - for (DWARF_PubNamesUnit *unit = pubnames->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_pubnames(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } - - // DEBUG PUBTYPES - if (params->dump_debug_pubtypes){ - if (pubtypes != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG PUBTYPES:\n")); - - U32 i = 0; - for (DWARF_PubNamesUnit *unit = pubtypes->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_pubnames(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } - - // DEBUG NAMES - if (params->dump_debug_names){ - if (names != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG NAMES:\n")); - - U32 i = 0; - for (DWARF_NamesUnit *unit = names->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_names(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } - - // DEBUG ARANGES - if (params->dump_debug_aranges){ - if (aranges != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG ARANGES:\n")); - - U32 i = 0; - for (DWARF_ArangesUnit *unit = aranges->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_aranges(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } - - // DEBUG ADDR - if (params->dump_debug_addr){ - if (addr != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG ADDR:\n")); - - U32 i = 0; - for (DWARF_AddrUnit *unit = addr->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - dwarf_stringize_addr(arena, &dump, unit, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } - -#if 0 - // DEBUG ABBREV - if (params->dump_debug_abbrev){ - if (abbrev != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG ABBREV:\n")); - - U32 i = 0; - for (DWARF_AbbrevUnit *unit = abbrev->unit_first; - unit != 0; - unit = unit->next, i += 1){ - U32 j = 0; - for (DWARF_AbbrevDecl *abbrev_decl = unit->first; - abbrev_decl != 0; - abbrev_decl = abbrev_decl->next, j += 1){ - String8 tag_string = dwarf_string_from_tag(abbrev_decl->tag); - - str8_list_pushf(arena, &dump, " unit[%u],abbrev[%u]:\n", i, j); - str8_list_pushf(arena, &dump, " code=%llu\n", abbrev_decl->abbrev_code); - str8_list_pushf(arena, &dump, " tag=%.*s\n", str8_varg(tag_string)); - str8_list_pushf(arena, &dump, " has_children=%u\n", abbrev_decl->has_children); - str8_list_pushf(arena, &dump, " attrib_count=%u\n", abbrev_decl->attrib_count); - str8_list_pushf(arena, &dump, " attribs:\n", abbrev_decl->attrib_count); - - U32 attrib_count = abbrev_decl->attrib_count; - DWARF_AbbrevAttribSpec *attrib_spec = abbrev_decl->attrib_specs; - for (U32 k = 0; k < attrib_count; k += 1, attrib_spec += 1){ - String8 name_string = dwarf_string_from_attribute_name(attrib_spec->name); - String8 form_string = dwarf_string_from_attribute_form(attrib_spec->form); - - str8_list_pushf(arena, &dump, " [%-14.*s %-10.*s]\n", - str8_varg(name_string), str8_varg(form_string)); + + U64 *voffs = push_array(arena, U64, line_seq->count); + U32 *line_nums = push_array(arena, U32, line_seq->count); + U16 *col_nums = 0; + U64 line_idx = 0; + + DW_LineNode *file_line_n = line_seq->first; + U64 file_line_count = 0; + + for (DW_LineNode *line_n = file_line_n; line_n != 0; line_n = line_n->next) { + if (file_line_n->v.file_index != line_n->v.file_index || line_n->next == 0) { + U64 file_index = file_line_n->v.file_index; + U64 *file_voffs = &voffs[line_idx]; + U32 *file_line_nums = &line_nums[line_idx]; + U16 *file_col_nums = 0; + + U64 lines_written = 0; + U64 prev_ln = max_U64; + DW_LineNode *sentinel = line_n->v.file_index != file_line_n->v.file_index ? line_n : 0; + for (; file_line_n != sentinel; file_line_n = file_line_n->next) { + if (file_line_n->v.line != prev_ln) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; + + ++lines_written; + ++line_idx; + + prev_ln = file_line_n->v.line; } + } + + RDIM_SrcFile *src_file = src_file_map[file_index]; + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, lines_written); + rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + + file_line_count = 1; + } else { + ++file_line_count; + } + } + + // handle last line + if (file_line_n) { + U64 file_index = file_line_n->v.file_index; + U64 *file_voffs = &voffs[line_idx]; + U32 *file_line_nums = &line_nums[line_idx]; + U16 *file_col_nums = 0; + + for (; file_line_n != 0; file_line_n = file_line_n->next, ++line_idx) { + // TODO: error handling + AssertAlways(file_line_n->v.address >= image_base); + voffs[line_idx] = file_line_n->v.address - image_base; + line_nums[line_idx] = file_line_n->v.line; + } + + RDIM_SrcFile *src_file = src_file_map[file_index]; + RDIM_LineSequence *line_seq = rdim_line_table_push_sequence(arena, &line_tables, cu_line_tables_rdi[cu_idx], src_file, file_voffs, file_line_nums, file_col_nums, file_line_count); + rdim_src_file_push_line_sequence(arena, &src_files, src_file, line_seq); + } + + //Assert(line_idx == line_seq->count); + } + } + + ProfEnd(); + + //////////////////////////////// + + ProfBegin("Convert Units"); + + for (U64 cu_idx = 0; cu_idx < cu_ranges.count; ++cu_idx) { + Temp comp_temp = temp_begin(scratch.arena); + + DW_CompUnit *cu = &cu_arr[cu_idx]; + + // parse and build tag tree + DW_TagTree tag_tree = dw_tag_tree_from_cu(comp_temp.arena, &input, cu); + + // build tag hash table for abstract origin resolution + cu->tag_ht = dw_make_tag_hash_table(comp_temp.arena, tag_tree); + + String8 dwo_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_DwoName); + String8 gnu_dwo_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_GNU_DwoName); + if (dwo_name.size || gnu_dwo_name.size || cu->dwo_id) { + // TODO: report that we dont support DWO + continue; + } + + // get unit's contribution ranges + RDIM_Rng1U64List cu_voff_ranges = d2r_voff_ranges_from_cu_info_off(cu_contrib_map, cu_ranges.v[cu_idx].min); + + String8 cu_name = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Name); + String8 cu_dir = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_CompDir); + String8 cu_prod = dw_string_from_attrib(&input, cu, cu->tag, DW_Attrib_Producer); + DW_Language cu_lang = dw_const_u64_from_attrib(&input, cu, cu->tag, DW_Attrib_Language); + + RDIM_Unit *unit = rdim_unit_chunk_list_push(arena, &units, UNIT_CHUNK_CAP); + unit->unit_name = cu_name; + unit->compiler_name = cu_prod; + unit->source_file = str8_zero(); + unit->object_file = str8_zero(); + unit->archive_file = str8_zero(); + unit->build_path = cu_dir; + unit->language = rdi_language_from_dw_language(cu_lang); + unit->line_table = cu_line_tables_rdi[cu_idx]; + unit->voff_ranges = cu_voff_ranges; + + D2R_TypeTable *type_table = push_array(comp_temp.arena, D2R_TypeTable, 1); + type_table->ht = hash_table_init(comp_temp.arena, 0x4000); + type_table->types = &types; + type_table->type_chunk_cap = TYPE_CHUNK_CAP; + type_table->void_type = d2r_create_type(arena, type_table); + type_table->void_type->kind = RDI_TypeKind_Void; + type_table->varg_type = d2r_create_type(arena, type_table); + type_table->varg_type->kind = RDI_TypeKind_Variadic; + + D2R_TagNode *free_tags = push_array(comp_temp.arena, D2R_TagNode, 1); + D2R_TagNode *tag_stack = push_array(comp_temp.arena, D2R_TagNode, 1); + tag_stack->cur_node = tag_tree.root; + + while (tag_stack) { + while (tag_stack->cur_node) { + DW_TagNode *cur_node = tag_stack->cur_node; + DW_Tag tag = cur_node->tag; + B32 visit_children = 1; + + switch (tag.kind) { + case DW_Tag_Null: { + InvalidPath; + } break; + case DW_Tag_ClassType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteClass; + + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Class; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + tag_stack->type = type; + } + } break; + case DW_Tag_StructureType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteStruct; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Struct; + type->udt = udt; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); - str8_list_push(arena, &dump, str8_lit("\n")); + tag_stack->type = type; + } + } break; + case DW_Tag_UnionType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteUnion; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Union; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + + tag_stack->type = type; + } + } break; + case DW_Tag_EnumerationType: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + + B32 is_decl = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_Declaration); + if (is_decl) { + type->kind = RDI_TypeKind_IncompleteEnum; + + // TODO: error handling + Assert(!cur_node->first_child); + visit_children = 0; + } else { + RDIM_UDT *udt = rdim_udt_chunk_list_push(arena, &udts, UDT_CHUNK_CAP); + udt->self_type = type; + + type->kind = RDI_TypeKind_Enum; + type->byte_size = dw_byte_size_32_from_tag(&input, cu, tag); + type->udt = udt; + + tag_stack->type = type; + } + } break; + case DW_Tag_SubroutineType: { + // collect parameters + RDIM_TypeList param_list = {0}; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind == DW_Tag_FormalParameter) { + RDIM_Type *param_type = d2r_type_from_attrib(arena, type_table, &input, cu, n->tag, DW_Attrib_Type); + rdim_type_list_push(comp_temp.arena, ¶m_list, param_type); + } else if (n->tag.kind == DW_Tag_UnspecifiedParameters) { + rdim_type_list_push(comp_temp.arena, ¶m_list, type_table->varg_type); + } else { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } + } + + // init proceudre type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Function; + type->byte_size = arch_addr_size; + type->direct_type = ret_type; + type->count = param_list.count; + type->param_types = rdim_array_from_type_list(arena, param_list); + + visit_children = 0; + } break; + case DW_Tag_Typedef: { + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_BaseType: { + DW_ATE encoding = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_Encoding); + U64 byte_size = dw_byte_size_from_tag(&input, cu, tag); + + // convert base type encoding to RDI version + RDI_TypeKind kind = RDI_TypeKind_NULL; + switch (encoding) { + case DW_ATE_Null: kind = RDI_TypeKind_NULL; break; + case DW_ATE_Address: kind = RDI_TypeKind_Void; break; + case DW_ATE_Boolean: kind = RDI_TypeKind_Bool; break; + case DW_ATE_ComplexFloat: { + switch (byte_size) { + case 4: kind = RDI_TypeKind_ComplexF32; break; + case 8: kind = RDI_TypeKind_ComplexF64; break; + case 10: kind = RDI_TypeKind_ComplexF80; break; + case 16: kind = RDI_TypeKind_ComplexF128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Float: { + switch (byte_size) { + case 2: kind = RDI_TypeKind_F16; break; + case 4: kind = RDI_TypeKind_F32; break; + case 6: kind = RDI_TypeKind_F48; break; + case 8: kind = RDI_TypeKind_F64; break; + case 16: kind = RDI_TypeKind_F128; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Signed: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_S8; break; + case 2: kind = RDI_TypeKind_S16; break; + case 4: kind = RDI_TypeKind_S32; break; + case 8: kind = RDI_TypeKind_S64; break; + case 16: kind = RDI_TypeKind_S128; break; + case 32: kind = RDI_TypeKind_S256; break; + case 64: kind = RDI_TypeKind_S512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_SignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_Char8; break; + case 2: kind = RDI_TypeKind_Char16; break; + case 4: kind = RDI_TypeKind_Char32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_Unsigned: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_U8; break; + case 2: kind = RDI_TypeKind_U16; break; + case 4: kind = RDI_TypeKind_U32; break; + case 8: kind = RDI_TypeKind_U64; break; + case 16: kind = RDI_TypeKind_U128; break; + case 32: kind = RDI_TypeKind_U256; break; + case 64: kind = RDI_TypeKind_U512; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_UnsignedChar: { + switch (byte_size) { + case 1: kind = RDI_TypeKind_UChar8; break; + case 2: kind = RDI_TypeKind_UChar16; break; + case 4: kind = RDI_TypeKind_UChar32; break; + default: AssertAlways(!"unexpected size"); break; // TODO: error handling + } + } break; + case DW_ATE_ImaginaryFloat: { + NotImplemented; + } break; + case DW_ATE_PackedDecimal: { + NotImplemented; + } break; + case DW_ATE_NumericString: { + NotImplemented; + } break; + case DW_ATE_Edited: { + NotImplemented; + } break; + case DW_ATE_SignedFixed: { + NotImplemented; + } break; + case DW_ATE_UnsignedFixed: { + NotImplemented; + } break; + case DW_ATE_DecimalFloat: { + NotImplemented; + } break; + case DW_ATE_Utf: { + NotImplemented; + } break; + case DW_ATE_Ucs: { + NotImplemented; + } break; + case DW_ATE_Ascii: { + NotImplemented; + } break; + default: AssertAlways(!"unexpected base type encoding"); break; // TODO: error handling + } + + RDIM_Type *base_type = d2r_create_type(arena, type_table); + base_type->kind = kind; + base_type->byte_size = byte_size; + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Alias; + type->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + type->direct_type = base_type; + } break; + case DW_Tag_PointerType: { + RDIM_Type *direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Allocated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Associated)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_AddressClass)); + + U64 byte_size = arch_addr_size; + if (cu->version == DW_Version_5 || cu->relaxed) { + dw_try_byte_size_from_tag(&input, cu, tag, &byte_size); + } + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Ptr; + type->byte_size = byte_size; + type->direct_type = direct_type; + } break; + case DW_Tag_RestrictType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Restrict; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_VolatileType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Volatile; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_ConstType: { + // TODO: + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Name)); + Assert(!dw_tag_has_attrib(&input, cu, tag, DW_Attrib_Alignment)); + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Modifier; + type->byte_size = arch_addr_size; + type->flags = RDI_TypeModifierFlag_Const; + type->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + } break; + case DW_Tag_ArrayType: { + // * DWARF vs RDI Array Type Graph * + // + // For example lets take following decl: + // + // int (*foo[2])[3][4]; + // + // This compiles to in DWARF: + // + // foo -> DW_TAG_ArrayType -> (A0) DW_TAG_Subrange [2] + // \ + // -> (B0) DW_TAG_PointerType -> (A1) DW_TAG_ArrayType -> DW_TAG_Subrange [3] -> DW_Tag_Subrange [4] + // \ + // -> (B1) DW_TAG_BaseType (int) + // + // RDI expects: + // + // foo -> Array (2) -> Pointer -> Array (3) -> Array (4) -> int + // + // Note that DWARF forks the graph on DW_TAG_ArrayType to describe array ranges in branch A and + // in branch B describes array type which might be a struct, pointer, base type, or any other type tag. + // However, in RDI we have a simple list of type nodes and to convert we need to append type nodes from + // B to A. + + RDIM_Type *type = d2r_find_or_create_type_from_offset(arena, type_table, tag.info_off); + type->kind = RDI_TypeKind_Array; + type->direct_type = 0; + + U64 subrange_count = 0; + RDIM_Type *t = type; + for (DW_TagNode *n = cur_node->first_child; n != 0; n = n->sibling) { + if (n->tag.kind != DW_Tag_SubrangeType) { + // TODO: error handling + AssertAlways(!"unexpected tag"); + continue; + } + + if (subrange_count > 0) { + // init array type node + RDIM_Type *s = d2r_create_type(arena, type_table); + s->kind = RDI_TypeKind_Array; + s->direct_type = 0; + + // append new array type node + t->direct_type = s; + t = s; + } + + // resolve array lower bound + U64 lower_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_LowerBound)) { + lower_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_LowerBound); + } else { + lower_bound = dw_pick_default_lower_bound(cu_lang); + } + + // resolve array upper bound + U64 upper_bound = 0; + if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_Count)) { + U64 count = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_Count); + upper_bound = lower_bound + count; + } else if (dw_tag_has_attrib(&input, cu, n->tag, DW_Attrib_UpperBound)) { + upper_bound = dw_u64_from_attrib(&input, cu, n->tag, DW_Attrib_UpperBound); + // turn upper bound into exclusive range + upper_bound += 1; + } else { + // zero size array + } + + t->count = upper_bound - lower_bound; + ++subrange_count; + } + + Assert(t->direct_type == 0); + t->direct_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + visit_children = 0; + } break; + case DW_Tag_SubrangeType: { + // TODO: error handling + AssertAlways(!"unexpected tag"); + } break; + case DW_Tag_Inheritance: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_StructureType && + parent_node->tag.kind != DW_Tag_ClassType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *parent = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, parent->udt); + member->kind = RDI_MemberKind_Base; + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + member->off = safe_cast_u32(dw_const_u32_from_attrib(&input, cu, tag, DW_Attrib_DataMemberLocation)); + } break; + case DW_Tag_Enumerator: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTEnumVal *member = rdim_udt_push_enum_val(arena, &udts, type->udt); + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + member->val = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_ConstValue); + } break; + case DW_Tag_Member: { + DW_TagNode *parent_node = tag_stack->next->cur_node; + if (parent_node->tag.kind != DW_Tag_StructureType && + parent_node->tag.kind != DW_Tag_ClassType && + parent_node->tag.kind != DW_Tag_UnionType && + parent_node->tag.kind != DW_Tag_EnumerationType) { + // TODO: error handling + AssertAlways(!"unexpected parent tag"); + } + + DW_Attrib *data_member_location = dw_attrib_from_tag(&input, cu, tag, DW_Attrib_DataMemberLocation); + DW_AttribClass data_member_location_class = dw_value_class_from_attrib(cu, data_member_location); + if (data_member_location_class == DW_AttribClass_LocList) { + AssertAlways(!"UDT member with multiple locations are not supported"); + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = RDI_MemberKind_DataField; + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + member->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + member->off = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_DataMemberLocation); + } break; + case DW_Tag_SubProgram: { + DW_InlKind inl = dw_u64_from_attrib(&input, cu, tag, DW_Attrib_Inline); + switch (inl) { + case DW_Inl_NotInlined: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *container_type = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_Attrib_ContainingType)) { + container_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_ContainingType); + } + + // get frame base expression + String8 frame_base_expr = dw_exprloc_from_attrib(&input, cu, tag, DW_Attrib_FrameBase); + + // get proc container symbol + RDIM_Symbol *proc = rdim_symbol_chunk_list_push(arena, &procs, PROC_CHUNK_CAP ); + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->symbol = proc; + + // fill out proc + proc->is_extern = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_External); + proc->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + proc->link_name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_LinkageName); + proc->type = proc_type; + proc->container_symbol = 0; + proc->container_type = container_type; + proc->root_scope = root_scope; + proc->frame_base = d2r_locset_from_attrib(arena, &input, cu, &scopes, root_scope, image_base, cu->address_size, arch_rdi, cu->addr_lu, tag, DW_Attrib_FrameBase); + + // sub program with user-defined parent tag is a method + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_ClassType || parent_tag_kind == DW_Tag_StructureType) { + RDI_MemberKind member_kind = RDI_MemberKind_NULL; + DW_VirtualityKind virtuality = dw_const_u64_from_attrib(&input, cu, tag, DW_Attrib_Virtuality); + switch (virtuality) { + case DW_VirtualityKind_None: member_kind = RDI_MemberKind_Method; break; + case DW_VirtualityKind_Virtual: member_kind = RDI_MemberKind_VirtualMethod; break; + case DW_VirtualityKind_PureVirtual: member_kind = RDI_MemberKind_VirtualMethod; break; // TODO: create kind for pure virutal + default: InvalidPath; break; + } + + RDIM_Type *type = tag_stack->next->type; + RDIM_UDTMember *member = rdim_udt_push_member(arena, &udts, type->udt); + member->kind = member_kind; + member->type = type; + member->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + } else if (parent_tag_kind != DW_Tag_CompileUnit) { + AssertAlways(!"unexpected tag"); + } + + tag_stack->scope = root_scope; + } break; + case DW_Inl_DeclaredNotInlined: + case DW_Inl_DeclaredInlined: + case DW_Inl_Inlined: { + visit_children = 0; + } break; + default: InvalidPath; break; + } + } break; + case DW_Tag_InlinedSubroutine: { + U64 param_count = 0; + RDIM_Type **params = d2r_collect_proc_params(arena, type_table, &input, cu, tag_stack->cur_node, ¶m_count); + + // get return type + RDIM_Type *ret_type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + // fill out proc type + RDIM_Type *proc_type = d2r_create_type(arena, type_table); + proc_type->kind = RDI_TypeKind_Function; + proc_type->byte_size = arch_addr_size; + proc_type->direct_type = ret_type; + proc_type->count = param_count; + proc_type->param_types = params; + + // get container type + RDIM_Type *owner = 0; + if (dw_tag_has_attrib(&input, cu, tag, DW_Attrib_ContainingType)) { + owner = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_ContainingType); + } + + // fill out inline site + RDIM_InlineSite *inline_site = rdim_inline_site_chunk_list_push(arena, &inline_sites, INLINE_SITE_CHUNK_CAP); + inline_site->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + inline_site->type = proc_type; + inline_site->owner = owner; + inline_site->line_table = 0; + + // make scope + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + RDIM_Scope *root_scope = d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + root_scope->inline_site = inline_site; + } break; + case DW_Tag_Variable: { + String8 name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + RDIM_Type *type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || + parent_tag_kind == DW_Tag_InlinedSubroutine || + parent_tag_kind == DW_Tag_LexicalBlock) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *local = rdim_scope_push_local(arena, &scopes, tag_stack->next->scope); + local->kind = RDI_LocalKind_Variable; + local->name = name; + local->type = type; + local->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, scope, image_base, cu->address_size, arch_rdi, cu->addr_lu, tag, DW_Attrib_Location); + } else { + + // NOTE: due to a bug in clang in stb_sprint.h local variables + // are declared in global scope without a name + if (name.size == 0) { + break; + } + + RDIM_Symbol *gvar = rdim_symbol_chunk_list_push(arena, &gvars, GVAR_CHUNK_CAP); + gvar->is_extern = dw_flag_from_attrib(&input, cu, tag, DW_Attrib_External); + gvar->name = name; + gvar->link_name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_LinkageName); + gvar->type = type; + gvar->offset = 0; // TODO: NotImplemented; + gvar->container_symbol = 0; + gvar->container_type = 0; // TODO: NotImplemented; + } + } break; + case DW_Tag_FormalParameter: { + DW_TagKind parent_tag_kind = tag_stack->next->cur_node->tag.kind; + if (parent_tag_kind == DW_Tag_SubProgram || parent_tag_kind == DW_Tag_InlinedSubroutine) { + RDIM_Scope *scope = tag_stack->next->scope; + RDIM_Local *param = rdim_scope_push_local(arena, &scopes, scope); + param->kind = RDI_LocalKind_Parameter; + param->name = dw_string_from_attrib(&input, cu, tag, DW_Attrib_Name); + param->type = d2r_type_from_attrib(arena, type_table, &input, cu, tag, DW_Attrib_Type); + param->locset = d2r_locset_from_attrib(arena, &input, cu, &scopes, scope, image_base, cu->address_size, arch_rdi, cu->addr_lu, tag, DW_Attrib_Location); + } else { + // TODO: error handling + AssertAlways(!"this is a local variable"); + } + } break; + case DW_Tag_LexicalBlock: { + if (tag_stack->next->cur_node->tag.kind == DW_Tag_SubProgram || + tag_stack->next->cur_node->tag.kind == DW_Tag_InlinedSubroutine || + tag_stack->next->cur_node->tag.kind == DW_Tag_LexicalBlock) { + Rng1U64List ranges = d2r_range_list_from_tag(comp_temp.arena, &input, cu, image_base, tag); + d2r_push_scope(arena, &scopes, SCOPE_CHUNK_CAP, tag_stack, ranges); + } + } break; + case DW_Tag_Label: + case DW_Tag_CompileUnit: + case DW_Tag_UnspecifiedParameters: + break; + default: NotImplemented; break; + } + + if (tag_stack->cur_node->first_child && visit_children) { + D2R_TagNode *frame = free_tags; + if (frame) { + SLLStackPop(free_tags); + MemoryZeroStruct(frame); + } else { + frame = push_array(scratch.arena, D2R_TagNode, 1); + } + frame->cur_node = tag_stack->cur_node->first_child; + SLLStackPush(tag_stack, frame); + } else { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } + + // recycle free frame + D2R_TagNode *frame = tag_stack; + SLLStackPop(tag_stack); + SLLStackPush(free_tags, frame); + + if (tag_stack) { + tag_stack->cur_node = tag_stack->cur_node->sibling; + } + } + + temp_end(comp_temp); + } + + ProfEnd(); + + { + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Alias) { + for (RDIM_Type *t = type->direct_type; t != 0; t = t->direct_type) { + if (t->byte_size != 0) { + type->byte_size = t->byte_size; + break; + } } } - } } -#endif - -#if 0 - // DEBUG INFO - if (params->dump_debug_info){ - if (info != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DEBUG INFO:\n")); - - U32 i = 0; - for (DWARF_InfoUnit *unit = info->unit_first; - unit != 0; - unit = unit->next, i += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - str8_list_pushf(arena, &dump, " [header]\n"); - str8_list_pushf(arena, &dump, " version=%u\n", unit->dwarf_version); - str8_list_pushf(arena, &dump, " offset_size=%u\n", unit->offset_size); - str8_list_pushf(arena, &dump, " address_size=%u\n", unit->address_size); - str8_list_pushf(arena, &dump, " [extracted attributes]\n"); - str8_list_pushf(arena, &dump, " langauge=%u\n", (U32)unit->language); - str8_list_pushf(arena, &dump, " line_info_offset=%llu\n", unit->line_info_offset); - str8_list_pushf(arena, &dump, " vbase=0x%llx\n", unit->vbase); - str8_list_pushf(arena, &dump, " str_offsets_base=%llu\n", unit->str_offsets_base); - str8_list_pushf(arena, &dump, " addr_base=%llu\n", unit->addr_base); - str8_list_pushf(arena, &dump, " rnglists_base=%llu\n", unit->rnglists_base); - str8_list_pushf(arena, &dump, " loclists_base=%llu\n", unit->loclists_base); - dump_entry_tree(arena, &dump, dwarf, unit, unit->entry_root, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - } - } -#endif - - // print dump - for (String8Node *node = dump.first; - node != 0; - node = node->next){ - fwrite(node->string.str, 1, node->string.size, stdout); - } } + + { + RDIM_TypeNode *type_stack = 0; + RDIM_TypeNode *free_types = 0; + + for (RDIM_TypeChunkNode *chunk_n = types.first; chunk_n != 0; chunk_n = chunk_n->next) { + for (U64 i = 0; i < chunk_n->count; ++i) { + RDIM_Type *type = &chunk_n->v[i]; + if (type->kind == RDI_TypeKind_Array) { + if (type->byte_size != 0) + continue; + + RDIM_Type *t; + for (t = type; t != 0 && t->kind == RDI_TypeKind_Array; t = t->direct_type) { + RDIM_TypeNode *f = free_types; + if (f == 0) { + f = push_array(scratch.arena, RDIM_TypeNode, 1); + } else { + SLLStackPop(free_types); + } + f->v = t; + SLLStackPush(type_stack, f); + } + + U64 base_type_size = 0; + if (t) { + base_type_size = t->byte_size; + } + + U64 array_size = base_type_size; + while (type_stack) { + if (type_stack->v->count) { + array_size *= type_stack->v->count; + } else { + array_size += type_stack->v->byte_size; + } + SLLStackPop(type_stack); + } + + type->count = 0; + type->byte_size = array_size; + + // recycle frames + free_types = type_stack; + type_stack = 0; + } + } + } + } + + //////////////////////////////// + + RDIM_BakeParams *bake_params = push_array(arena, RDIM_BakeParams, 1); + bake_params->top_level_info = top_level_info; + bake_params->binary_sections = binary_sections; + bake_params->units = units; + bake_params->types = types; + bake_params->udts = udts; + bake_params->src_files = src_files; + bake_params->line_tables = line_tables; + bake_params->global_variables = gvars; + bake_params->thread_variables = tvars; + bake_params->procedures = procs; + bake_params->scopes = scopes; + bake_params->inline_sites = inline_sites; + + scratch_end(scratch); + return bake_params; } + +RDI_PROC void +rdim_assign_type_index(RDIM_Type *type, U64 *type_indices, U64 *curr_type_idx) +{ + RDI_U64 type_pos = rdim_idx_from_type(type); + + if(type->kind == RDI_TypeKind_NULL) + { + type_indices[type_pos] = 0; + return; + } + + if(type_indices[type_pos] == 0) + { + if(type->param_types) + { + for(RDI_U64 param_idx = 0; param_idx < type->count; param_idx += 1) + { + rdim_assign_type_index(type->param_types[param_idx], type_indices, curr_type_idx); + } + } + + if(type->direct_type) + { + rdim_assign_type_index(type->direct_type, type_indices, curr_type_idx); + } + + type_indices[type_pos] = *curr_type_idx; + *curr_type_idx += 1; + } +} + +RDI_PROC RDI_U64 * +rdim_make_type_indices(RDIM_Arena *arena, RDIM_TypeChunkList *types) +{ + ProfBeginFunction(); + + RDI_U64 *type_indices = rdim_push_array(arena, RDI_U64, types->total_count + 1); + RDI_U64 type_indices_count = 1; + + for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) + { + for(RDI_U64 i = 0; i < chunk->count; i += 1) + { + rdim_assign_type_index(&chunk->v[i], type_indices, &type_indices_count); + } + } + + ProfEnd(); + return type_indices; +} + +internal RDIM_BakeResults +d2r_bake(RDIM_LocalState *state, RDIM_BakeParams *in_params) +{ + //////////////////////////////// + // resolve incomplete types + + rdim_local_resolve_incomplete_types(&in_params->types, &in_params->udts); + + //////////////////////////////// + // compute type indices + + RDI_U64 *type_indices = rdim_make_type_indices(scratch.arena, &in_params->types); + + // using type indices create a correct type array layout + NotImplemented; + + return rdim_bake(state, in_params); +} + +internal RDIM_SerializedSectionBundle +d2r_compress(Arena *arena, RDIM_SerializedSectionBundle in) +{ + RDIM_SerializedSectionBundle result = {0}; + return result; +} + +internal RDI_Language +rdi_language_from_dw_language(DW_Language v) +{ + RDI_Language result = RDI_Language_NULL; + switch (v) { + case DW_Language_Null: result = RDI_Language_NULL; break; + + case DW_Language_C89: + case DW_Language_C99: + case DW_Language_C11: + case DW_Language_C: + result = RDI_Language_C; + break; + + case DW_Language_CPlusPlus03: + case DW_Language_CPlusPlus11: + case DW_Language_CPlusPlus14: + case DW_Language_CPlusPlus: + result = RDI_Language_CPlusPlus; + break; + + default: NotImplemented; break; + } + return result; +} + +internal RDI_RegCodeX86 +rdi_reg_from_dw_reg_x86(DW_RegX86 v) +{ + RDI_RegCodeX86 result = RDI_RegCode_nil; + switch (v) { +#define X(reg_dw, val_dw, reg_rdi, ...) case DW_RegX86_##reg_dw: result = RDI_RegCodeX86_##reg_rdi; break; + DW_Regs_X86_XList(X) +#undef X + default: NotImplemented; break; + } + return result; +} + +internal B32 +rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out) +{ + RDI_RegCodeX64 result = RDI_RegCode_nil; + switch (v) { +#define X(reg_dw, val_dw, reg_rdi, off, size) case DW_RegX64_##reg_dw: result = RDI_RegCodeX64_##reg_rdi; *off_out = off; *size_out = size; break; + DW_Regs_X64_XList(X) +#undef X + default: NotImplemented; break; + } + return result; +} + +internal B32 +rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out) +{ + RDI_RegCode result = RDI_RegCode_nil; + switch (arch) { + case Arch_Null: break; + case Arch_x86: ; break; + case Arch_x64: return rdi_reg_from_dw_reg_x64(v, code_out, off_out, size_out); + default: NotImplemented; break; + } + return 0; +} + diff --git a/src/rdi_from_dwarf/rdi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h index c5ea8251..4f59fb27 100644 --- a/src/rdi_from_dwarf/rdi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -1,50 +1,69 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RDI_FROM_DWARF_H -#define RDI_FROM_DWARF_H +#pragma once + +typedef U64 D2R_ConvertFlags; +enum +{ +#define X(t,n,k) D2R_ConvertFlag_##t = (1ull << RDI_SectionKind_##t), + RDI_SectionKind_XList +#undef X + D2R_ConvertFlag_StrictParse, +}; + +typedef struct D2R_User2Convert +{ + String8 input_exe_name; + String8 input_exe_data; + String8 input_debug_name; + String8 input_debug_data; + String8 output_name; + D2R_ConvertFlags flags; + String8List errors; +} D2R_User2Convert; + +typedef struct D2R_TypeTable +{ + HashTable *ht; + RDIM_TypeChunkList *types; + U64 type_chunk_cap; + RDIM_Type *void_type; + RDIM_Type *varg_type; +} D2R_TypeTable; + +typedef struct D2R_TagNode +{ + struct D2R_TagNode *next; + DW_TagNode *cur_node; + RDIM_Type *type; + RDIM_Scope *scope; +} D2R_TagNode; + +typedef struct D2R_CompUnitContribMap +{ + U64 count; + U64 *info_off_arr; + RDIM_Rng1U64List *voff_range_arr; +} D2R_CompUnitContribMap; //////////////////////////////// -//~ Program Parameters Type +// Command Line -> Conversion Inputs -typedef struct DWARFCONV_Params{ - String8 input_elf_name; - String8 input_elf_data; - - String8 output_name; - - U64 unit_idx_min; - U64 unit_idx_max; - - struct{ - B8 input; - } hide_errors; - - B8 dump; - B8 dump__first; - B8 dump_header; - B8 dump_sections; - B8 dump_segments; - B8 dump_symtab; - B8 dump_dynsym; - B8 dump_debug_sections; - B8 dump_debug_info; - B8 dump_debug_abbrev; - B8 dump_debug_pubnames; - B8 dump_debug_pubtypes; - B8 dump_debug_names; - B8 dump_debug_aranges; - B8 dump_debug_addr; - B8 dump__last; - - String8List errors; -} DWARFCONV_Params; +internal D2R_User2Convert * d2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline); //////////////////////////////// -//~ Program Parameters Parser +// Top-Level Conversion Entry Point -static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline); +internal RDIM_BakeParams * d2r_convert (Arena *arena, D2R_User2Convert *in); +internal RDIM_BakeResults d2r_bake (RDIM_LocalState *state, RDIM_BakeParams *in); +internal RDIM_SerializedSectionBundle d2r_compress(Arena *arena, RDIM_SerializedSectionBundle in); +//////////////////////////////// +// Enum Conversion +internal RDI_Language rdi_language_from_dw_language(DW_Language v); +internal RDI_RegCodeX86 rdi_reg_from_dw_reg_x86(DW_RegX86 v); +internal B32 rdi_reg_from_dw_reg_x64(DW_RegX64 v, RDI_RegCodeX64 *code_out, U64 *off_out, U64 *size_out); +internal B32 rdi_reg_from_dw_reg(Arch arch, DW_Reg v, RDI_RegCode *code_out, U64 *off_out, U64 *size_out); -#endif //RDI_FROM_DWARF_H diff --git a/src/rdi_from_dwarf/rdi_from_dwarf_main.c b/src/rdi_from_dwarf/rdi_from_dwarf_main.c new file mode 100644 index 00000000..a74e3b15 --- /dev/null +++ b/src/rdi_from_dwarf/rdi_from_dwarf_main.c @@ -0,0 +1,121 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define BUILD_TITLE "Epic Games Tools (R) DWARF Converter" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// + +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" +#include "third_party/xxHash/xxhash.c" +#include "third_party/xxHash/xxhash.h" +#include "third_party/radsort/radsort.h" + +//////////////////////////////// + +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format_parse.c" + +//////////////////////////////// + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "async/async.h" +#include "rdi_make/rdi_make_local.h" +#include "linker/path_ext/path.h" +#include "linker/hash_table.h" +#include "coff/coff.h" +#include "coff/coff_parse.h" +#include "dwarf/dwarf.h" +#include "dwarf/dwarf_parse.h" +#include "dwarf/dwarf_coff.h" +#include "pe/pe.h" +#include "linker/rdi/rdi_coff.h" +#include "rdi_from_dwarf/rdi_from_dwarf.h" + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "async/async.c" +#include "coff/coff.c" +#include "coff/coff_parse.c" +#include "pe/pe.c" +#include "rdi_make/rdi_make_local.c" +#include "linker/rdi/rdi_coff.c" +#include "linker/path_ext/path.c" +#include "linker/hash_table.c" +#include "dwarf/dwarf.c" +#include "dwarf/dwarf_parse.c" +#include "dwarf/dwarf_coff.c" +#include "rdi_from_dwarf/rdi_from_dwarf.c" + +//////////////////////////////// +// Entry Point + +internal void +entry_point(CmdLine *cmdline) +{ + // initialize state and unpack command line + Arena *arena = arena_alloc(); + B32 do_help = (cmd_line_has_flag(cmdline, str8_lit("help")) || + cmd_line_has_flag(cmdline, str8_lit("h")) || + cmd_line_has_flag(cmdline, str8_lit("?"))); + + D2R_User2Convert *user2convert = d2r_user2convert_from_cmdln(arena, cmdline); + + // display help + if (do_help) { + fprintf(stderr, "--- rdi_from_dwarf ------------------------------------------------------------\n\n"); + + fprintf(stderr, "This utility converts debug information from DWARF into the RAD Debug Info\n"); + fprintf(stderr, "format. The following arguments are accepted:\n\n"); + + fprintf(stderr, "--exe: [optional] Specifies the path of the executable filefor which the\n"); + fprintf(stderr, " debug info was generated.\n"); + fprintf(stderr, "--debug: Specifies the path of the .DEBUG debug info file to\n"); + fprintf(stderr, " convert.\n"); + fprintf(stderr, "--out: Specifies the path at which the output will be written.\n\n"); + + if (!do_help) { + for (String8Node *n = user2convert->errors.first; n != 0; n = n->next) { + fprintf(stderr, "error(input): %.*s\n", str8_varg(n->string)); + } + } + + os_abort(0); + } + + RDIM_LocalState *rdim_local_state = rdim_local_init(); + + ProfBegin("convert"); + RDIM_BakeParams *convert2bake = d2r_convert(arena, user2convert); + ProfEnd(); + + ProfBegin("bake"); + RDIM_BakeResults bake2srlz = d2r_bake(rdim_local_state, convert2bake); + ProfEnd(); + + ProfBegin("serialize bake"); + RDIM_SerializedSectionBundle srlz2file = rdim_serialized_section_bundle_from_bake_results(&bake2srlz); + ProfEnd(); + + RDIM_SerializedSectionBundle srlz2file_compressed = srlz2file; + if (cmd_line_has_flag(cmdline, str8_lit("compress"))) { + ProfBegin("compress"); + srlz2file_compressed = d2r_compress(arena, srlz2file); + ProfEnd(); + } + + ProfBegin("serialize blobs"); + String8List blobs = rdim_file_blobs_from_section_bundle(arena, &srlz2file_compressed); + ProfEnd(); + + ProfBegin("write"); + if (!os_write_data_list_to_file_path(user2convert->output_name, blobs)) { + fprintf(stderr, "error(ouptut): unable to write to %.*s\n", str8_varg(user2convert->output_name)); + } + ProfEnd(); +} + diff --git a/src/rdi_from_pdb/rdi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c index 943dcca1..a15b21cb 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -616,13 +616,14 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } } - //- rjf: produce obj name + //- rjf: produce obj name/path String8 obj_name = pdb_unit->obj_name; if(str8_match(obj_name, str8_lit("* Linker *"), 0) || str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) { MemoryZeroStruct(&obj_name); } + String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); //- rjf: build this unit's line table, fill out primary line info (inline info added after) RDIM_LineTable *line_table = 0; @@ -641,12 +642,18 @@ ASYNC_WORK_DEF(p2r_units_convert_work) // rjf: file name -> normalized file path String8 file_path = lines->file_name; String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); - for(U64 idx = 0; idx < file_path_normalized.size; idx += 1) { - if(file_path_normalized.str[idx] == '\\') + PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + if(file_path_normalized_style == PathStyle_Relative) { - file_path_normalized.str[idx] = '/'; + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); + file_path_normalized_parts = obj_folder_path_parts; + file_path_normalized_style = path_style_from_str8(obj_folder_path); } + str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); } // rjf: normalized file path -> source file node @@ -716,10 +723,23 @@ ASYNC_WORK_DEF(p2r_units_convert_work) ProfScope("pass 3: parse all inlinee line tables") for(U64 comp_unit_idx = 0; comp_unit_idx < in->comp_units->count; comp_unit_idx += 1) { + //- rjf: unpack unit + PDB_CompUnit *pdb_unit = in->comp_units->units[comp_unit_idx]; CV_SymParsed *unit_sym = in->comp_unit_syms[comp_unit_idx]; CV_C13Parsed *unit_c13 = in->comp_unit_c13s[comp_unit_idx]; CV_RecRange *rec_ranges_first = unit_sym->sym_ranges.ranges; CV_RecRange *rec_ranges_opl = rec_ranges_first+unit_sym->sym_ranges.count; + + //- rjf: produce obj name/path + String8 obj_name = pdb_unit->obj_name; + if(str8_match(obj_name, str8_lit("* Linker *"), 0) || + str8_match(obj_name, str8_lit("Import:"), StringMatchFlag_RightSideSloppy)) + { + MemoryZeroStruct(&obj_name); + } + String8 obj_folder_path = lower_from_str8(scratch.arena, str8_chop_last_slash(obj_name)); + + //- rjf: parse inlinee line tables U64 base_voff = 0; for(CV_RecRange *rec_range = rec_ranges_first; rec_range < rec_ranges_opl; @@ -787,12 +807,12 @@ ASYNC_WORK_DEF(p2r_units_convert_work) } // rjf: build line table, fill with parsed binary annotations - + if(inlinee_lines_parsed != 0) { // rjf: grab checksums sub-section CV_C13SubSectionNode *file_chksms = unit_c13->file_chksms_sub_section; - + // rjf: gathered lines typedef struct LineChunk LineChunk; struct LineChunk @@ -810,12 +830,12 @@ ASYNC_WORK_DEF(p2r_units_convert_work) U32 last_file_off = max_U32; U32 curr_file_off = max_U32; RDIM_LineTable* line_table = 0; - + CV_C13InlineSiteDecoder decoder = cv_c13_inline_site_decoder_init(inlinee_lines_parsed->file_off, inlinee_lines_parsed->first_source_ln, base_voff); for(;;) { CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitFile) { last_file_off = curr_file_off; @@ -829,7 +849,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) if((last_file_off != max_U32 && last_file_off != curr_file_off)) { String8 seq_file_name = {0}; - + if(last_file_off + sizeof(CV_C13Checksum) <= file_chksms->size) { CV_C13Checksum *checksum = (CV_C13Checksum*)(unit_c13->data.str + file_chksms->off + last_file_off); @@ -840,12 +860,18 @@ ASYNC_WORK_DEF(p2r_units_convert_work) // rjf: file name -> normalized file path String8 file_path = seq_file_name; String8 file_path_normalized = lower_from_str8(scratch.arena, str8_skip_chop_whitespace(file_path)); - for(U64 idx = 0; idx < file_path_normalized.size; idx += 1) { - if(file_path_normalized.str[idx] == '\\') + PathStyle file_path_normalized_style = path_style_from_str8(file_path_normalized); + String8List file_path_normalized_parts = str8_split_path(scratch.arena, file_path_normalized); + if(file_path_normalized_style == PathStyle_Relative) { - file_path_normalized.str[idx] = '/'; + String8List obj_folder_path_parts = str8_split_path(scratch.arena, obj_folder_path); + str8_list_concat_in_place(&obj_folder_path_parts, &file_path_normalized_parts); + file_path_normalized_parts = obj_folder_path_parts; + file_path_normalized_style = path_style_from_str8(obj_folder_path); } + str8_path_list_resolve_dots_in_place(&file_path_normalized_parts, file_path_normalized_style); + file_path_normalized = str8_path_list_join_by_style(scratch.arena, &file_path_normalized_parts, file_path_normalized_style); } // rjf: normalized file path -> source file node @@ -901,7 +927,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) first_line_chunk = last_line_chunk = 0; total_line_chunk_line_count = 0; } - + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitLine) { LineChunk *chunk = last_line_chunk; @@ -919,7 +945,7 @@ ASYNC_WORK_DEF(p2r_units_convert_work) chunk->count += 1; total_line_chunk_line_count += 1; } - + if(step.flags == 0) { break; @@ -2088,6 +2114,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) RDIM_SymbolChunkList sym_thread_variables = {0}; RDIM_ScopeChunkList sym_scopes = {0}; RDIM_InlineSiteChunkList sym_inline_sites = {0}; + RDIM_TypeChunkList typedefs = {0}; ////////////////////////// //- rjf: symbols pass 1: produce procedure frame info map (procedure -> frame info) @@ -2311,6 +2338,24 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) } }break; + case CV_SymKind_UDT: + { + if(in->parsing_global_stream && top_scope_node == 0) + { + CV_SymUDT *udt = (CV_SymUDT *)sym_header_struct_base; + String8 name = str8_cstring_capped(udt+1, sym_data_opl); + + RDIM_Type *type = rdim_type_chunk_list_push(arena, &typedefs, 4096); + type->kind = RDI_TypeKind_Alias; + type->name = name; + type->direct_type = p2r_type_ptr_from_itype(udt->itype); + if(type->direct_type != 0) + { + type->byte_size = type->direct_type->byte_size; + } + } + }break; + //- rjf: LPROC32/GPROC32 case CV_SymKind_LPROC32: case CV_SymKind_GPROC32: @@ -2437,7 +2482,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) if(is_stack_reg) { U32 frame_size = 0xFFFFFFFF; - if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num < procedure_frameprocs_count) + if(procedure_num != 0 && procedure_frameprocs[procedure_num-1] != 0 && procedure_num <= procedure_frameprocs_count) { CV_SymFrameproc *frameproc = procedure_frameprocs[procedure_num-1]; frame_size = frameproc->frame_size; @@ -2869,14 +2914,14 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) for(;;) { CV_C13InlineSiteDecoderStep step = cv_c13_inline_site_decoder_step(&decoder, binary_annots); - + if(step.flags & CV_C13InlineSiteDecoderStepFlag_EmitRange) { // rjf: build new range & add to scope RDIM_Rng1U64 voff_range = { step.range.min, step.range.max }; rdim_scope_push_voff_range(arena, &sym_scopes, scope, voff_range); } - + if(step.flags & CV_C13InlineSiteDecoderStepFlag_ExtendLastRange) { if(scope->voff_ranges.last != 0) @@ -2884,7 +2929,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) scope->voff_ranges.last->v.max = step.range.max; } } - + if(step.flags == 0) { break; @@ -2919,6 +2964,7 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work) out->thread_variables = sym_thread_variables; out->scopes = sym_scopes; out->inline_sites = sym_inline_sites; + out->typedefs = typedefs; } #undef p2r_type_ptr_from_itype @@ -2957,6 +3003,11 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) named_streams = pdb_named_stream_table_from_info(arena, info); MemoryCopyStruct(&auth_guid, &info->auth_guid); scratch_end(scratch); + + if (info->features & PDB_FeatureFlag_MINIMAL_DBG_INFO) { + fprintf(stderr, "ERROR: PDB was linked with /DEBUG:FASTLINK (partial debug info is not supported). Please relink using /DEBUG:FULL."); + os_abort(1); + } } ////////////////////////////////////////////////////////////// @@ -3392,11 +3443,90 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // from regular type info. // RDIM_Type **itype_type_ptrs = 0; - RDIM_TypeChunkList all_types = {0}; + RDIM_TypeChunkList all_types = rdim_init_type_chunk_list(arena, top_level_info.arch); #define p2r_type_ptr_from_itype(itype) ((itype_type_ptrs && (itype) < itype_opl) ? (itype_type_ptrs[(itype_fwd_map[(itype)] ? itype_fwd_map[(itype)] : (itype))]) : 0) if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 3: construct all root/stub types from TPI") { itype_type_ptrs = push_array(arena, RDIM_Type *, (U64)(itype_opl)); + + ////////////////////////// + //- basic type aliases + // + { + RDIM_DataModel data_model = rdim_infer_data_model(OperatingSystem_Windows, top_level_info.arch); + RDI_TypeKind short_type = rdim_short_type_from_data_model(data_model); + RDI_TypeKind ushort_type = rdim_unsigned_short_type_from_data_model(data_model); + RDI_TypeKind long_type = rdim_long_type_from_data_model(data_model); + RDI_TypeKind ulong_type = rdim_unsigned_long_type_from_data_model(data_model); + RDI_TypeKind long_long_type = rdim_long_long_type_from_data_model(data_model); + RDI_TypeKind ulong_long_type = rdim_unsigned_long_long_type_from_data_model(data_model); + RDI_TypeKind ptr_type = rdim_pointer_size_t_type_from_data_model(data_model); + + struct + { + char * name; + RDI_TypeKind kind_rdi; + CV_LeafKind kind_cv; + } + table[] = + { + { "signed char" , RDI_TypeKind_Char8 , CV_BasicType_CHAR }, + { "short" , short_type , CV_BasicType_SHORT }, + { "long" , long_type , CV_BasicType_LONG }, + { "long long" , long_long_type , CV_BasicType_QUAD }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_OCT }, // Clang type + { "unsigned char" , RDI_TypeKind_UChar8 , CV_BasicType_UCHAR }, + { "unsigned short" , ushort_type , CV_BasicType_USHORT }, + { "unsigned long" , ulong_type , CV_BasicType_ULONG }, + { "unsigned long long" , ulong_long_type , CV_BasicType_UQUAD }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UOCT }, // Clang type + { "bool" , RDI_TypeKind_S8 , CV_BasicType_BOOL8 }, + { "__bool16" , RDI_TypeKind_S16 , CV_BasicType_BOOL16 }, // not real C type + { "__bool32" , RDI_TypeKind_S32 , CV_BasicType_BOOL32 }, // not real C type + { "float" , RDI_TypeKind_F32 , CV_BasicType_FLOAT32 }, + { "double" , RDI_TypeKind_F64 , CV_BasicType_FLOAT64 }, + { "long double" , RDI_TypeKind_F80 , CV_BasicType_FLOAT80 }, + { "__float128" , RDI_TypeKind_F128 , CV_BasicType_FLOAT128 }, // Clang type + { "__float48" , RDI_TypeKind_F48 , CV_BasicType_FLOAT48 }, // not real C type + { "__float32pp" , RDI_TypeKind_F32PP , CV_BasicType_FLOAT32PP }, // not real C type + { "__float16" , RDI_TypeKind_F16 , CV_BasicType_FLOAT16 }, + { "_Complex float" , RDI_TypeKind_ComplexF32 , CV_BasicType_COMPLEX32 }, + { "_Complex double" , RDI_TypeKind_ComplexF64 , CV_BasicType_COMPLEX64 }, + { "_Complex long double" , RDI_TypeKind_ComplexF80 , CV_BasicType_COMPLEX80 }, + { "_Complex __float128" , RDI_TypeKind_ComplexF128, CV_BasicType_COMPLEX128 }, + { "__int8" , RDI_TypeKind_S8 , CV_BasicType_INT8 }, + { "__uint8" , RDI_TypeKind_U8 , CV_BasicType_UINT8 }, + { "__int16" , RDI_TypeKind_S16 , CV_BasicType_INT16 }, + { "__uint16" , RDI_TypeKind_U16 , CV_BasicType_UINT16 }, + { "int32" , RDI_TypeKind_S32 , CV_BasicType_INT32 }, + { "uint32" , RDI_TypeKind_U32 , CV_BasicType_UINT32 }, + { "__int64" , RDI_TypeKind_S64 , CV_BasicType_INT64 }, + { "__uint64" , RDI_TypeKind_U64 , CV_BasicType_UINT64 }, + { "__int128" , RDI_TypeKind_S128 , CV_BasicType_INT128 }, + { "__uint128" , RDI_TypeKind_U128 , CV_BasicType_UINT128 }, + { "char" , RDI_TypeKind_Char8 , CV_BasicType_RCHAR }, // always ASCII + { "wchar_t" , RDI_TypeKind_UChar16 , CV_BasicType_WCHAR }, // on windows always UTF-16 + { "char8_t" , RDI_TypeKind_Char8 , CV_BasicType_CHAR8 }, // always UTF-8 + { "char16_t" , RDI_TypeKind_Char16 , CV_BasicType_CHAR16 }, // always UTF-16 + { "char32_t" , RDI_TypeKind_Char32 , CV_BasicType_CHAR32 }, // always UTF-32 + { "__pointer" , ptr_type , CV_BasicType_PTR } + }; + + itype_type_ptrs[CV_BasicType_NOTYPE] = rdim_builtin_type_from_kind(all_types, RDI_TypeKind_NULL); + itype_type_ptrs[CV_BasicType_HRESULT] = rdim_builtin_type_from_kind(all_types, RDI_TypeKind_HResult); + itype_type_ptrs[CV_BasicType_VOID] = rdim_builtin_type_from_kind(all_types, RDI_TypeKind_Void); + + for(U64 i = 0; i < ArrayCount(table); i += 1) + { + RDIM_Type *builtin_alias = rdim_type_chunk_list_push(arena, &all_types, tpi_leaf->itype_opl); + builtin_alias->kind = RDI_TypeKind_Alias; + builtin_alias->name = str8_cstring(table[i].name); + builtin_alias->direct_type = rdim_builtin_type_from_kind(all_types, table[i].kind_rdi); + builtin_alias->byte_size = rdi_size_from_basic_type_kind(table[i].kind_rdi); + itype_type_ptrs[table[i].kind_cv] = builtin_alias; + } + } + for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) { for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; @@ -3404,7 +3534,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) itype_chain = itype_chain->next) { CV_TypeId itype = (root_itype != itype_chain->itype && itype_chain->itype < itype_opl && itype_fwd_map[itype_chain->itype]) ? itype_fwd_map[itype_chain->itype] : itype_chain->itype; - B32 itype_is_basic = (itype < 0x1000); + B32 itype_is_basic = (itype < tpi->itype_first); ////////////////////////// //- rjf: skip forward-reference itypes - all future resolutions will @@ -3521,8 +3651,9 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) // rjf: cv -> rdi modifier flags RDI_TypeModifierFlags modifier_flags = 0; - if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} - if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} + if(lf->attribs & CV_PointerAttrib_Const) {modifier_flags |= RDI_TypeModifierFlag_Const;} + if(lf->attribs & CV_PointerAttrib_Volatile) {modifier_flags |= RDI_TypeModifierFlag_Volatile;} + if(lf->attribs & CV_PointerAttrib_Restricted) {modifier_flags |= RDI_TypeModifierFlag_Restrict;} // rjf: cv info -> rdi pointer type kind RDI_TypeKind type_kind = RDI_TypeKind_Ptr; @@ -3906,10 +4037,11 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) tasks_inputs[idx].link_name_map = link_name_map; if(idx < global_stream_subdivision_tasks_count) { - tasks_inputs[idx].sym = sym; - tasks_inputs[idx].sym_ranges_first= idx*global_stream_syms_per_task; - tasks_inputs[idx].sym_ranges_opl = tasks_inputs[idx].sym_ranges_first + global_stream_syms_per_task; - tasks_inputs[idx].sym_ranges_opl = ClampTop(tasks_inputs[idx].sym_ranges_opl, sym->sym_ranges.count); + tasks_inputs[idx].parsing_global_stream = 1; + tasks_inputs[idx].sym = sym; + tasks_inputs[idx].sym_ranges_first = idx*global_stream_syms_per_task; + tasks_inputs[idx].sym_ranges_opl = tasks_inputs[idx].sym_ranges_first + global_stream_syms_per_task; + tasks_inputs[idx].sym_ranges_opl = ClampTop(tasks_inputs[idx].sym_ranges_opl, sym->sym_ranges.count); } else { @@ -3935,6 +4067,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) rdim_symbol_chunk_list_concat_in_place(&all_thread_variables, &out->thread_variables); rdim_scope_chunk_list_concat_in_place(&all_scopes, &out->scopes); rdim_inline_site_chunk_list_concat_in_place(&all_inline_sites,&out->inline_sites); + rdim_type_chunk_list_concat_in_place(&all_types, &out->typedefs); } } } @@ -3972,387 +4105,6 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) return out; } -//////////////////////////////// -//~ rjf: Baking Stage Tasks - -//- rjf: bake string map building - -#define p2r_make_string_map_if_needed() do {if(in->maps[thread_idx] == 0) ProfScope("make map") {in->maps[thread_idx] = rdim_bake_string_map_loose_make(arena, in->top);}} while(0) - -ASYNC_WORK_DEF(p2r_bake_src_files_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeSrcFilesStringsIn *in = (P2R_BakeSrcFilesStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake src file strings") rdim_bake_string_map_loose_push_src_files(arena, in->top, in->maps[thread_idx], in->list); - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_units_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeUnitsStringsIn *in = (P2R_BakeUnitsStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake unit strings") rdim_bake_string_map_loose_push_units(arena, in->top, in->maps[thread_idx], in->list); - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_types_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeTypesStringsIn *in = (P2R_BakeTypesStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake type strings") - { - for(P2R_BakeTypesStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_type_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_udts_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeUDTsStringsIn *in = (P2R_BakeUDTsStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake udt strings") - { - for(P2R_BakeUDTsStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_udt_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_symbols_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeSymbolsStringsIn *in = (P2R_BakeSymbolsStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake symbol strings") - { - for(P2R_BakeSymbolsStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_symbol_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_inline_site_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeInlineSiteStringsIn *in = input; - p2r_make_string_map_if_needed(); - ProfScope("bake inline site strings") - { - for(P2R_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_scopes_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeScopesStringsIn *in = (P2R_BakeScopesStringsIn *)input; - p2r_make_string_map_if_needed(); - ProfScope("bake scope strings") - { - for(P2R_BakeScopesStringsInNode *n = in->first; n != 0; n = n->next) - { - rdim_bake_string_map_loose_push_scope_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); - } - } - ProfEnd(); - return 0; -} - -ASYNC_WORK_DEF(p2r_bake_line_tables_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeLineTablesIn *in = (P2R_BakeLineTablesIn *)input; - RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); - ProfScope("bake line tables") *out = rdim_bake_line_tables(arena, in->line_tables); - ProfEnd(); - return out; -} - -#undef p2r_make_string_map_if_needed - -//- rjf: bake string map joining - -ASYNC_WORK_DEF(p2r_bake_string_map_join_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_JoinBakeStringMapSlotsIn *in = (P2R_JoinBakeStringMapSlotsIn *)input; - ProfScope("join bake string maps") - { - for(U64 src_map_idx = 0; src_map_idx < in->src_maps_count; src_map_idx += 1) - { - for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1) - { - B32 src_slots_good = (in->src_maps[src_map_idx] != 0 && in->src_maps[src_map_idx]->slots != 0); - B32 dst_slot_is_zero = (in->dst_map->slots[slot_idx] == 0); - if(src_slots_good && dst_slot_is_zero) - { - in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx]; - } - else if(src_slots_good && in->src_maps[src_map_idx]->slots[slot_idx] != 0) - { - rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]); - } - } - } - } - ProfEnd(); - return 0; -} - -//- rjf: bake string map sorting - -ASYNC_WORK_DEF(p2r_bake_string_map_sort_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_SortBakeStringMapSlotsIn *in = (P2R_SortBakeStringMapSlotsIn *)input; - ProfScope("sort bake string chunk list map range") - { - for(U64 slot_idx = in->slot_idx; - slot_idx < in->slot_idx+in->slot_count; - slot_idx += 1) - { - if(in->src_map->slots[slot_idx] != 0) - { - if(in->src_map->slots[slot_idx]->total_count > 1) - { - in->dst_map->slots[slot_idx] = push_array(arena, RDIM_BakeStringChunkList, 1); - *in->dst_map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, in->src_map->slots[slot_idx]); - } - else - { - in->dst_map->slots[slot_idx] = in->src_map->slots[slot_idx]; - } - } - } - } - ProfEnd(); - return 0; -} - -//- rjf: pass 1: interner/deduper map builds - -ASYNC_WORK_DEF(p2r_build_bake_name_map_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BuildBakeNameMapIn *in = (P2R_BuildBakeNameMapIn *)input; - RDIM_BakeNameMap *name_map = 0; - ProfScope("build name map %i", in->k) name_map = rdim_bake_name_map_from_kind_params(arena, in->k, in->params); - ProfEnd(); - return name_map; -} - -//- rjf: pass 2: string-map-dependent debug info stream builds - -ASYNC_WORK_DEF(p2r_bake_units_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeUnitsIn *in = (P2R_BakeUnitsIn *)input; - RDIM_UnitBakeResult *out = push_array(arena, RDIM_UnitBakeResult, 1); - ProfScope("bake units") *out = rdim_bake_units(arena, in->strings, in->path_tree, in->units); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_unit_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeUnitVMapIn *in = (P2R_BakeUnitVMapIn *)input; - RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); - ProfScope("bake unit vmap") *out = rdim_bake_unit_vmap(arena, in->units); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_src_files_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeSrcFilesIn *in = (P2R_BakeSrcFilesIn *)input; - RDIM_SrcFileBakeResult *out = push_array(arena, RDIM_SrcFileBakeResult, 1); - ProfScope("bake src files") *out = rdim_bake_src_files(arena, in->strings, in->path_tree, in->src_files); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_udts_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeUDTsIn *in = (P2R_BakeUDTsIn *)input; - RDIM_UDTBakeResult *out = push_array(arena, RDIM_UDTBakeResult, 1); - ProfScope("bake udts") *out = rdim_bake_udts(arena, in->strings, in->udts); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_global_variables_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeGlobalVariablesIn *in = (P2R_BakeGlobalVariablesIn *)input; - RDIM_GlobalVariableBakeResult *out = push_array(arena, RDIM_GlobalVariableBakeResult, 1); - ProfScope("bake global variables") *out = rdim_bake_global_variables(arena, in->strings, in->global_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_global_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeGlobalVMapIn *in = (P2R_BakeGlobalVMapIn *)input; - RDIM_GlobalVMapBakeResult *out = push_array(arena, RDIM_GlobalVMapBakeResult, 1); - ProfScope("bake global vmap") *out = rdim_bake_global_vmap(arena, in->global_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_thread_variables_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeThreadVariablesIn *in = (P2R_BakeThreadVariablesIn *)input; - RDIM_ThreadVariableBakeResult *out = push_array(arena, RDIM_ThreadVariableBakeResult, 1); - ProfScope("bake thread variables") *out = rdim_bake_thread_variables(arena, in->strings, in->thread_variables); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_procedures_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeProceduresIn *in = (P2R_BakeProceduresIn *)input; - RDIM_ProcedureBakeResult *out = push_array(arena, RDIM_ProcedureBakeResult, 1); - ProfScope("bake procedures") *out = rdim_bake_procedures(arena, in->strings, in->procedures); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_scopes_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeScopesIn *in = (P2R_BakeScopesIn *)input; - RDIM_ScopeBakeResult *out = push_array(arena, RDIM_ScopeBakeResult, 1); - ProfScope("bake scopes") *out = rdim_bake_scopes(arena, in->strings, in->scopes); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_scope_vmap_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeScopeVMapIn *in = (P2R_BakeScopeVMapIn *)input; - RDIM_ScopeVMapBakeResult *out = push_array(arena, RDIM_ScopeVMapBakeResult, 1); - ProfScope("bake scope vmap") *out = rdim_bake_scope_vmap(arena, in->scopes); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_inline_sites_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeInlineSitesIn *in = (P2R_BakeInlineSitesIn *)input; - RDIM_InlineSiteBakeResult *out = push_array(arena, RDIM_InlineSiteBakeResult, 1); - ProfScope("bake inline sites") *out = rdim_bake_inline_sites(arena, in->strings, in->inline_sites); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_file_paths_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeFilePathsIn *in = (P2R_BakeFilePathsIn *)input; - RDIM_FilePathBakeResult *out = push_array(arena, RDIM_FilePathBakeResult, 1); - ProfScope("bake file paths") *out = rdim_bake_file_paths(arena, in->strings, in->path_tree); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_strings_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeStringsIn *in = (P2R_BakeStringsIn *)input; - RDIM_StringBakeResult *out = push_array(arena, RDIM_StringBakeResult, 1); - ProfScope("bake strings") *out = rdim_bake_strings(arena, in->strings); - ProfEnd(); - return out; -} - -//- rjf: pass 3: idx-run-map-dependent debug info stream builds - -ASYNC_WORK_DEF(p2r_bake_type_nodes_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeTypeNodesIn *in = (P2R_BakeTypeNodesIn *)input; - RDIM_TypeNodeBakeResult *out = push_array(arena, RDIM_TypeNodeBakeResult, 1); - ProfScope("bake type nodes") *out = rdim_bake_types(arena, in->strings, in->idx_runs, in->types); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_name_map_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeNameMapIn *in = (P2R_BakeNameMapIn *)input; - RDIM_NameMapBakeResult *out = push_array(arena, RDIM_NameMapBakeResult, 1); - ProfScope("bake name map %i", in->kind) *out = rdim_bake_name_map(arena, in->strings, in->idx_runs, in->map); - ProfEnd(); - return out; -} - -ASYNC_WORK_DEF(p2r_bake_idx_runs_work) -{ - ProfBeginFunction(); - Arena *arena = p2r_state->work_thread_arenas[thread_idx]; - P2R_BakeIdxRunsIn *in = (P2R_BakeIdxRunsIn *)input; - RDIM_IndexRunBakeResult *out = push_array(arena, RDIM_IndexRunBakeResult, 1); - ProfScope("bake idx runs") *out = rdim_bake_index_runs(arena, in->idx_runs); - ProfEnd(); - return out; -} - //////////////////////////////// //~ rjf: Top-Level Initialization @@ -4376,468 +4128,14 @@ p2r_init(void) internal P2R_Bake2Serialize * p2r_bake(Arena *arena, P2R_Convert2Bake *in) { - Temp scratch = scratch_begin(&arena, 1); - RDIM_BakeParams *in_params = &in->bake_params; - P2R_Bake2Serialize *out = push_array(arena, P2R_Bake2Serialize, 1); - RDIM_BakeResults *out_results = &out->bake_results; + RDIM_LocalState local_state = {0}; + local_state.arena = p2r_state->arena; + local_state.work_thread_arenas_count = p2r_state->work_thread_arenas_count; + local_state.work_thread_arenas = p2r_state->work_thread_arenas; - ////////////////////////////// - //- rjf: kick off line tables baking - // - ASYNC_Task *bake_line_tables_task = 0; - { - P2R_BakeLineTablesIn *in = push_array(scratch.arena, P2R_BakeLineTablesIn, 1); - in->line_tables = &in_params->line_tables; - bake_line_tables_task = async_task_launch(scratch.arena, p2r_bake_line_tables_work, .input = in); - } - - ////////////////////////////// - //- rjf: build interned path tree - // - RDIM_BakePathTree *path_tree = 0; - ProfScope("build interned path tree") - { - path_tree = rdim_bake_path_tree_from_params(arena, in_params); - } - - ////////////////////////////// - //- rjf: kick off string map building tasks - // - RDIM_BakeStringMapTopology bake_string_map_topology = {(64 + - in_params->procedures.total_count*1 + - in_params->global_variables.total_count*1 + - in_params->thread_variables.total_count*1 + - in_params->types.total_count/2)}; - RDIM_BakeStringMapLoose **bake_string_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringMapLoose *, async_thread_count()); - ASYNC_TaskList bake_string_map_build_tasks = {0}; - { - // rjf: src files - ProfScope("kick off src files string map build task") - { - P2R_BakeSrcFilesStringsIn *in = push_array(scratch.arena, P2R_BakeSrcFilesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - in->list = &in_params->src_files; - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_src_files_strings_work, .input = in)); - } - - // rjf: units - ProfScope("kick off units string map build task") - { - P2R_BakeUnitsStringsIn *in = push_array(scratch.arena, P2R_BakeUnitsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - in->list = &in_params->units; - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_units_strings_work, .input = in)); - } - - // rjf: types - ProfScope("kick off types string map build tasks") - { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->types.total_count+items_per_task-1)/items_per_task; - RDIM_TypeChunkNode *chunk = in_params->types.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_BakeTypesStringsIn *in = push_array(scratch.arena, P2R_BakeTypesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) - { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - P2R_BakeTypesStringsInNode *n = push_array(scratch.arena, P2R_BakeTypesStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) - { - chunk = chunk->next; - chunk_off = 0; - } - } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_types_strings_work, .input = in)); - } - } - - // rjf: UDTs - ProfScope("kick off udts string map build tasks") - { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->udts.total_count+items_per_task-1)/items_per_task; - RDIM_UDTChunkNode *chunk = in_params->udts.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_BakeUDTsStringsIn *in = push_array(scratch.arena, P2R_BakeUDTsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) - { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - P2R_BakeUDTsStringsInNode *n = push_array(scratch.arena, P2R_BakeUDTsStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) - { - chunk = chunk->next; - chunk_off = 0; - } - } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_udts_strings_work, .input = in)); - } - } - - // rjf: symbols - ProfScope("kick off symbols string map build tasks") - { - RDIM_SymbolChunkList *symbol_lists[] = - { - &in_params->global_variables, - &in_params->thread_variables, - &in_params->procedures, - }; - for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1) - { - U64 items_per_task = 4096; - U64 num_tasks = (symbol_lists[list_idx]->total_count+items_per_task-1)/items_per_task; - RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_BakeSymbolsStringsIn *in = push_array(scratch.arena, P2R_BakeSymbolsStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) - { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - P2R_BakeSymbolsStringsInNode *n = push_array(scratch.arena, P2R_BakeSymbolsStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) - { - chunk = chunk->next; - chunk_off = 0; - } - } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_symbols_strings_work, .input = in)); - } - } - } - - ProfScope("kick off inline site string map build task") - { - U64 items_per_task = 4096; - U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task); - RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_BakeInlineSiteStringsIn *in = push_array(scratch.arena, P2R_BakeInlineSiteStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) - { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - P2R_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, P2R_BakeInlineSiteStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) - { - chunk = chunk->next; - chunk_off = 0; - } - } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_inline_site_strings_work, .input = in)); - } - } - - // rjf: scope chunks - ProfScope("kick off scope chunks string map build tasks") - { - U64 items_per_task = 4096; - U64 num_tasks = (in_params->scopes.total_count+items_per_task-1)/items_per_task; - RDIM_ScopeChunkNode *chunk = in_params->scopes.first; - U64 chunk_off = 0; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_BakeScopesStringsIn *in = push_array(scratch.arena, P2R_BakeScopesStringsIn, 1); - in->top = &bake_string_map_topology; - in->maps = bake_string_maps__in_progress; - U64 items_left = items_per_task; - for(;chunk != 0 && items_left > 0;) - { - U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); - P2R_BakeScopesStringsInNode *n = push_array(scratch.arena, P2R_BakeScopesStringsInNode, 1); - SLLQueuePush(in->first, in->last, n); - n->v = chunk->v + chunk_off; - n->count = items_in_this_chunk; - chunk_off += items_in_this_chunk; - items_left -= items_in_this_chunk; - if(chunk_off >= chunk->count) - { - chunk = chunk->next; - chunk_off = 0; - } - } - async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, p2r_bake_scopes_strings_work, .input = in)); - } - } - } - - ////////////////////////////// - //- rjf: kick off name map building tasks - // - P2R_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0}; - ASYNC_Task *build_bake_name_map_task[RDI_NameMapKind_COUNT] = {0}; - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - build_bake_name_map_in[k].k = k; - build_bake_name_map_in[k].params = in_params; - build_bake_name_map_task[k] = async_task_launch(scratch.arena, p2r_build_bake_name_map_work, .input = &build_bake_name_map_in[k]); - } - - ////////////////////////////// - //- rjf: join string map building tasks - // - ProfScope("join string map building tasks") - { - for(ASYNC_TaskNode *n = bake_string_map_build_tasks.first; n != 0; n = n->next) - { - async_task_join(n->v); - } - } - - ////////////////////////////// - //- rjf: produce joined string map - // - RDIM_BakeStringMapLoose *unsorted_bake_string_map = rdim_bake_string_map_loose_make(arena, &bake_string_map_topology); - ProfScope("produce joined string map") - { - U64 slots_per_task = 16384; - U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; - ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, num_tasks); - - // rjf: kickoff tasks - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_JoinBakeStringMapSlotsIn *in = push_array(scratch.arena, P2R_JoinBakeStringMapSlotsIn, 1); - in->top = &bake_string_map_topology; - in->src_maps = bake_string_maps__in_progress; - in->src_maps_count = async_thread_count(); - in->dst_map = unsorted_bake_string_map; - in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task); - in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count); - tasks[task_idx] = async_task_launch(scratch.arena, p2r_bake_string_map_join_work, .input = in); - } - - // rjf: join tasks - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - async_task_join(tasks[task_idx]); - } - - // rjf: insert small top-level stuff - rdim_bake_string_map_loose_push_top_level_info(arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->top_level_info); - rdim_bake_string_map_loose_push_binary_sections(arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->binary_sections); - rdim_bake_string_map_loose_push_path_tree(arena, &bake_string_map_topology, unsorted_bake_string_map, path_tree); - } - - ////////////////////////////// - //- rjf: kick off string map sorting tasks - // - ASYNC_TaskList sort_bake_string_map_tasks = {0}; - RDIM_BakeStringMapLoose *sorted_bake_string_map__in_progress = rdim_bake_string_map_loose_make(arena, &bake_string_map_topology); - { - U64 slots_per_task = 4096; - U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; - for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) - { - P2R_SortBakeStringMapSlotsIn *in = push_array(scratch.arena, P2R_SortBakeStringMapSlotsIn, 1); - { - in->top = &bake_string_map_topology; - in->src_map = unsorted_bake_string_map; - in->dst_map = sorted_bake_string_map__in_progress; - in->slot_idx = task_idx*slots_per_task; - in->slot_count = slots_per_task; - if(in->slot_idx+in->slot_count > bake_string_map_topology.slots_count) - { - in->slot_count = bake_string_map_topology.slots_count - in->slot_idx; - } - } - async_task_list_push(scratch.arena, &sort_bake_string_map_tasks, async_task_launch(scratch.arena, p2r_bake_string_map_sort_work, .input = in)); - } - } - - ////////////////////////////// - //- rjf: join string map sorting tasks - // - ProfScope("join string map sorting tasks") - { - for(ASYNC_TaskNode *n = sort_bake_string_map_tasks.first; n != 0; n = n->next) - { - async_task_join(n->v); - } - } - RDIM_BakeStringMapLoose *sorted_bake_string_map = sorted_bake_string_map__in_progress; - - ////////////////////////////// - //- rjf: build finalized string map - // - ProfBegin("build finalized string map base indices"); - RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(arena, &bake_string_map_topology, sorted_bake_string_map); - ProfEnd(); - ProfBegin("build finalized string map"); - RDIM_BakeStringMapTight bake_strings = rdim_bake_string_map_tight_from_loose(arena, &bake_string_map_topology, &bake_string_map_base_idxes, sorted_bake_string_map); - ProfEnd(); - - ////////////////////////////// - //- rjf: kick off pass 2 tasks - // - P2R_BakeUnitsIn bake_units_top_level_in = {&bake_strings, path_tree, &in_params->units}; - ASYNC_Task *bake_units_task = async_task_launch(scratch.arena, p2r_bake_units_work, .input = &bake_units_top_level_in); - P2R_BakeUnitVMapIn bake_unit_vmap_in = {&in_params->units}; - ASYNC_Task *bake_unit_vmap_task = async_task_launch(scratch.arena, p2r_bake_unit_vmap_work, .input = &bake_unit_vmap_in); - P2R_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, &in_params->src_files}; - ASYNC_Task *bake_src_files_task = async_task_launch(scratch.arena, p2r_bake_src_files_work, .input = &bake_src_files_in); - P2R_BakeUDTsIn bake_udts_in = {&bake_strings, &in_params->udts}; - ASYNC_Task *bake_udts_task = async_task_launch(scratch.arena, p2r_bake_udts_work, .input = &bake_udts_in); - P2R_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, &in_params->global_variables}; - ASYNC_Task *bake_global_variables_task = async_task_launch(scratch.arena, p2r_bake_global_variables_work, .input = &bake_global_variables_in); - P2R_BakeGlobalVMapIn bake_global_vmap_in = {&in_params->global_variables}; - ASYNC_Task *bake_global_vmap_task = async_task_launch(scratch.arena, p2r_bake_global_vmap_work, .input = &bake_global_vmap_in); - P2R_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, &in_params->thread_variables}; - ASYNC_Task *bake_thread_variables_task = async_task_launch(scratch.arena, p2r_bake_thread_variables_work, .input = &bake_thread_variables_in); - P2R_BakeProceduresIn bake_procedures_in = {&bake_strings, &in_params->procedures}; - ASYNC_Task *bake_procedures_task = async_task_launch(scratch.arena, p2r_bake_procedures_work, .input = &bake_procedures_in); - P2R_BakeScopesIn bake_scopes_in = {&bake_strings, &in_params->scopes}; - ASYNC_Task *bake_scopes_task = async_task_launch(scratch.arena, p2r_bake_scopes_work, .input = &bake_scopes_in); - P2R_BakeScopeVMapIn bake_scope_vmap_in = {&in_params->scopes}; - ASYNC_Task *bake_scope_vmap_task = async_task_launch(scratch.arena, p2r_bake_scope_vmap_work, .input = &bake_scope_vmap_in); - P2R_BakeInlineSitesIn bake_inline_sites_in = {&bake_strings, &in_params->inline_sites}; - ASYNC_Task *bake_inline_sites_task = async_task_launch(scratch.arena, p2r_bake_inline_sites_work, .input = &bake_inline_sites_in); - P2R_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; - ASYNC_Task *bake_file_paths_task = async_task_launch(scratch.arena, p2r_bake_file_paths_work, .input = &bake_file_paths_in); - P2R_BakeStringsIn bake_strings_in = {&bake_strings}; - ASYNC_Task *bake_strings_task = async_task_launch(scratch.arena, p2r_bake_strings_work, .input = &bake_strings_in); - - ////////////////////////////// - //- rjf: join name map building tasks - // - RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT] = {0}; - ProfScope("join name map building tasks") - { - for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); - k < RDI_NameMapKind_COUNT; - k = (RDI_NameMapKind)(k+1)) - { - name_maps[k] = async_task_join_struct(build_bake_name_map_task[k], RDIM_BakeNameMap); - } - } - - ////////////////////////////// - //- rjf: build interned idx run map - // - RDIM_BakeIdxRunMap *idx_runs = 0; - ProfScope("build interned idx run map") - { - idx_runs = rdim_bake_idx_run_map_from_params(arena, name_maps, in_params); - } - - ////////////////////////////// - //- rjf: do small top-level bakes - // - ProfScope("top level info") out_results->top_level_info = rdim_bake_top_level_info(arena, &bake_strings, &in_params->top_level_info); - ProfScope("binary sections") out_results->binary_sections = rdim_bake_binary_sections(arena, &bake_strings, &in_params->binary_sections); - ProfScope("top level name maps section") out_results->top_level_name_maps = rdim_bake_name_maps_top_level(arena, &bake_strings, idx_runs, name_maps); - - ////////////////////////////// - //- rjf: kick off pass 3 tasks - // - P2R_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, &in_params->types}; - ASYNC_Task *bake_type_nodes_task = async_task_launch(scratch.arena, p2r_bake_type_nodes_work, .input = &bake_type_nodes_in); - ASYNC_Task *bake_name_maps_tasks[RDI_NameMapKind_COUNT] = {0}; - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - if(name_maps[k] == 0 || name_maps[k]->name_count == 0) - { - continue; - } - P2R_BakeNameMapIn *in = push_array(scratch.arena, P2R_BakeNameMapIn, 1); - in->strings = &bake_strings; - in->idx_runs = idx_runs; - in->map = name_maps[k]; - in->kind = k; - bake_name_maps_tasks[k] = async_task_launch(scratch.arena, p2r_bake_name_map_work, .input = in); - } - } - P2R_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; - ASYNC_Task *bake_idx_runs_task = async_task_launch(scratch.arena, p2r_bake_idx_runs_work, .input = &bake_idx_runs_in); - - ////////////////////////////// - //- rjf: join remaining completed bakes - // - ProfScope("top-level units info") out_results->units = *async_task_join_struct(bake_units_task, RDIM_UnitBakeResult); - ProfScope("unit vmap") out_results->unit_vmap = *async_task_join_struct(bake_unit_vmap_task, RDIM_UnitVMapBakeResult); - ProfScope("source files") out_results->src_files = *async_task_join_struct(bake_src_files_task, RDIM_SrcFileBakeResult); - ProfScope("UDTs") out_results->udts = *async_task_join_struct(bake_udts_task, RDIM_UDTBakeResult); - ProfScope("global variables") out_results->global_variables = *async_task_join_struct(bake_global_variables_task, RDIM_GlobalVariableBakeResult); - ProfScope("global vmap") out_results->global_vmap = *async_task_join_struct(bake_global_vmap_task, RDIM_GlobalVMapBakeResult); - ProfScope("thread variables") out_results->thread_variables = *async_task_join_struct(bake_thread_variables_task, RDIM_ThreadVariableBakeResult); - ProfScope("procedures") out_results->procedures = *async_task_join_struct(bake_procedures_task, RDIM_ProcedureBakeResult); - ProfScope("scopes") out_results->scopes = *async_task_join_struct(bake_scopes_task, RDIM_ScopeBakeResult); - ProfScope("scope vmap") out_results->scope_vmap = *async_task_join_struct(bake_scope_vmap_task, RDIM_ScopeVMapBakeResult); - ProfScope("inline sites") out_results->inline_sites = *async_task_join_struct(bake_inline_sites_task, RDIM_InlineSiteBakeResult); - ProfScope("file paths") out_results->file_paths = *async_task_join_struct(bake_file_paths_task, RDIM_FilePathBakeResult); - ProfScope("strings") out_results->strings = *async_task_join_struct(bake_strings_task, RDIM_StringBakeResult); - ProfScope("type nodes") out_results->type_nodes = *async_task_join_struct(bake_type_nodes_task, RDIM_TypeNodeBakeResult); - ProfScope("idx runs") out_results->idx_runs = *async_task_join_struct(bake_idx_runs_task, RDIM_IndexRunBakeResult); - ProfScope("line tables") out_results->line_tables = *async_task_join_struct(bake_line_tables_task, RDIM_LineTableBakeResult); - - ////////////////////////////// - //- rjf: join individual name map bakes - // - RDIM_NameMapBakeResult name_map_bakes[RDI_NameMapKind_COUNT] = {0}; - ProfScope("name maps") - { - for EachNonZeroEnumVal(RDI_NameMapKind, k) - { - RDIM_NameMapBakeResult *bake = async_task_join_struct(bake_name_maps_tasks[k], RDIM_NameMapBakeResult); - if(bake != 0) - { - name_map_bakes[k] = *bake; - } - } - } - - ////////////////////////////// - //- rjf: join all individual name map bakes - // - ProfScope("join all name map bakes into final name map bake") - { - out_results->name_maps = rdim_name_map_bake_results_combine(arena, name_map_bakes, ArrayCount(name_map_bakes)); - } - - scratch_end(scratch); - return out; + P2R_Bake2Serialize *result = push_array(arena, P2R_Bake2Serialize, 1); + result->bake_results = rdim_bake(&local_state, &in->bake_params); + return result; } //////////////////////////////// @@ -4847,33 +4145,7 @@ internal P2R_Serialize2File * p2r_compress(Arena *arena, P2R_Serialize2File *in) { P2R_Serialize2File *out = push_array(arena, P2R_Serialize2File, 1); - { - //- rjf: set up compression context - rr_lzb_simple_context ctx = {0}; - ctx.m_tableSizeBits = 14; - ctx.m_hashTable = push_array(arena, U16, 1<bundle.sections[k]; - RDIM_SerializedSection *dst = &out->bundle.sections[k]; - MemoryCopyStruct(dst, src); - - // rjf: determine if this section should be compressed - B32 should_compress = 1; - - // rjf: compress if needed - if(should_compress) - { - MemoryZero(ctx.m_hashTable, sizeof(U16)*(1<data = push_array_no_zero(arena, U8, src->encoded_size); - dst->encoded_size = rr_lzb_simple_encode_veryfast(&ctx, src->data, src->encoded_size, dst->data); - dst->unpacked_size = src->encoded_size; - dst->encoding = RDI_SectionEncoding_LZB; - } - } - } + out->bundle = rdim_compress(arena, &in->bundle); return out; } diff --git a/src/rdi_from_pdb/rdi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h index ced21a66..e8642256 100644 --- a/src/rdi_from_pdb/rdi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -249,6 +249,7 @@ struct P2R_UDTConvertIn typedef struct P2R_SymbolStreamConvertIn P2R_SymbolStreamConvertIn; struct P2R_SymbolStreamConvertIn { + B32 parsing_global_stream; RDI_Arch arch; COFF_SectionHeaderArray coff_sections; PDB_TpiHashParsed *tpi_hash; @@ -271,274 +272,7 @@ struct P2R_SymbolStreamConvertOut RDIM_SymbolChunkList thread_variables; RDIM_ScopeChunkList scopes; RDIM_InlineSiteChunkList inline_sites; -}; - -//////////////////////////////// -//~ rjf: Baking Task Types - -//- rjf: line table baking task types - -typedef struct P2R_BakeLineTablesIn P2R_BakeLineTablesIn; -struct P2R_BakeLineTablesIn -{ - RDIM_LineTableChunkList *line_tables; -}; - -//- rjf: string map baking task types - -typedef struct P2R_BakeSrcFilesStringsIn P2R_BakeSrcFilesStringsIn; -struct P2R_BakeSrcFilesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_SrcFileChunkList *list; -}; - -typedef struct P2R_BakeUnitsStringsIn P2R_BakeUnitsStringsIn; -struct P2R_BakeUnitsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - RDIM_UnitChunkList *list; -}; - -typedef struct P2R_BakeTypesStringsInNode P2R_BakeTypesStringsInNode; -struct P2R_BakeTypesStringsInNode -{ - P2R_BakeTypesStringsInNode *next; - RDIM_Type *v; - RDI_U64 count; -}; - -typedef struct P2R_BakeTypesStringsIn P2R_BakeTypesStringsIn; -struct P2R_BakeTypesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - P2R_BakeTypesStringsInNode *first; - P2R_BakeTypesStringsInNode *last; -}; - -typedef struct P2R_BakeUDTsStringsInNode P2R_BakeUDTsStringsInNode; -struct P2R_BakeUDTsStringsInNode -{ - P2R_BakeUDTsStringsInNode *next; - RDIM_UDT *v; - RDI_U64 count; -}; - -typedef struct P2R_BakeUDTsStringsIn P2R_BakeUDTsStringsIn; -struct P2R_BakeUDTsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - P2R_BakeUDTsStringsInNode *first; - P2R_BakeUDTsStringsInNode *last; -}; - -typedef struct P2R_BakeSymbolsStringsInNode P2R_BakeSymbolsStringsInNode; -struct P2R_BakeSymbolsStringsInNode -{ - P2R_BakeSymbolsStringsInNode *next; - RDIM_Symbol *v; - RDI_U64 count; -}; - -typedef struct P2R_BakeSymbolsStringsIn P2R_BakeSymbolsStringsIn; -struct P2R_BakeSymbolsStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - P2R_BakeSymbolsStringsInNode *first; - P2R_BakeSymbolsStringsInNode *last; -}; - -typedef struct P2R_BakeInlineSiteStringsInNode P2R_BakeInlineSiteStringsInNode; -struct P2R_BakeInlineSiteStringsInNode -{ - P2R_BakeInlineSiteStringsInNode *next; - RDIM_InlineSite *v; - RDI_U64 count; -}; - -typedef struct P2R_BakeInlineSiteStringsIn P2R_BakeInlineSiteStringsIn; -struct P2R_BakeInlineSiteStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - P2R_BakeInlineSiteStringsInNode *first; - P2R_BakeInlineSiteStringsInNode *last; -}; - -typedef struct P2R_BakeScopesStringsInNode P2R_BakeScopesStringsInNode; -struct P2R_BakeScopesStringsInNode -{ - P2R_BakeScopesStringsInNode *next; - RDIM_Scope *v; - RDI_U64 count; -}; - -typedef struct P2R_BakeScopesStringsIn P2R_BakeScopesStringsIn; -struct P2R_BakeScopesStringsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **maps; - P2R_BakeScopesStringsInNode *first; - P2R_BakeScopesStringsInNode *last; -}; - -//- rjf: string map joining task types - -typedef struct P2R_JoinBakeStringMapSlotsIn P2R_JoinBakeStringMapSlotsIn; -struct P2R_JoinBakeStringMapSlotsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose **src_maps; - U64 src_maps_count; - RDIM_BakeStringMapLoose *dst_map; - Rng1U64 slot_idx_range; -}; - -//- rjf: string map sorting task types - -typedef struct P2R_SortBakeStringMapSlotsIn P2R_SortBakeStringMapSlotsIn; -struct P2R_SortBakeStringMapSlotsIn -{ - RDIM_BakeStringMapTopology *top; - RDIM_BakeStringMapLoose *src_map; - RDIM_BakeStringMapLoose *dst_map; - U64 slot_idx; - U64 slot_count; -}; - -//- rjf: OLD string map baking types - -typedef struct P2R_BuildBakeStringMapIn P2R_BuildBakeStringMapIn; -struct P2R_BuildBakeStringMapIn -{ - RDIM_BakePathTree *path_tree; - RDIM_BakeParams *params; -}; - -typedef struct P2R_BuildBakeNameMapIn P2R_BuildBakeNameMapIn; -struct P2R_BuildBakeNameMapIn -{ - RDI_NameMapKind k; - RDIM_BakeParams *params; -}; - -//- rjf: debug info baking task types - -typedef struct P2R_BakeUnitsIn P2R_BakeUnitsIn; -struct P2R_BakeUnitsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; - RDIM_UnitChunkList *units; -}; - -typedef struct P2R_BakeUnitVMapIn P2R_BakeUnitVMapIn; -struct P2R_BakeUnitVMapIn -{ - RDIM_UnitChunkList *units; -}; - -typedef struct P2R_BakeSrcFilesIn P2R_BakeSrcFilesIn; -struct P2R_BakeSrcFilesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; - RDIM_SrcFileChunkList *src_files; -}; - -typedef struct P2R_BakeUDTsIn P2R_BakeUDTsIn; -struct P2R_BakeUDTsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_UDTChunkList *udts; -}; - -typedef struct P2R_BakeGlobalVariablesIn P2R_BakeGlobalVariablesIn; -struct P2R_BakeGlobalVariablesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *global_variables; -}; - -typedef struct P2R_BakeGlobalVMapIn P2R_BakeGlobalVMapIn; -struct P2R_BakeGlobalVMapIn -{ - RDIM_SymbolChunkList *global_variables; -}; - -typedef struct P2R_BakeThreadVariablesIn P2R_BakeThreadVariablesIn; -struct P2R_BakeThreadVariablesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *thread_variables; -}; - -typedef struct P2R_BakeProceduresIn P2R_BakeProceduresIn; -struct P2R_BakeProceduresIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_SymbolChunkList *procedures; -}; - -typedef struct P2R_BakeScopesIn P2R_BakeScopesIn; -struct P2R_BakeScopesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_ScopeChunkList *scopes; -}; - -typedef struct P2R_BakeScopeVMapIn P2R_BakeScopeVMapIn; -struct P2R_BakeScopeVMapIn -{ - RDIM_ScopeChunkList *scopes; -}; - -typedef struct P2R_BakeInlineSitesIn P2R_BakeInlineSitesIn; -struct P2R_BakeInlineSitesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_InlineSiteChunkList *inline_sites; -}; - -typedef struct P2R_BakeFilePathsIn P2R_BakeFilePathsIn; -struct P2R_BakeFilePathsIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakePathTree *path_tree; -}; - -typedef struct P2R_BakeStringsIn P2R_BakeStringsIn; -struct P2R_BakeStringsIn -{ - RDIM_BakeStringMapTight *strings; -}; - -typedef struct P2R_BakeTypeNodesIn P2R_BakeTypeNodesIn; -struct P2R_BakeTypeNodesIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakeIdxRunMap *idx_runs; - RDIM_TypeChunkList *types; -}; - -typedef struct P2R_BakeNameMapIn P2R_BakeNameMapIn; -struct P2R_BakeNameMapIn -{ - RDIM_BakeStringMapTight *strings; - RDIM_BakeIdxRunMap *idx_runs; - RDIM_BakeNameMap *map; - RDI_NameMapKind kind; -}; - -typedef struct P2R_BakeIdxRunsIn P2R_BakeIdxRunsIn; -struct P2R_BakeIdxRunsIn -{ - RDIM_BakeIdxRunMap *idx_runs; + RDIM_TypeChunkList typedefs; }; //////////////////////////////// @@ -630,46 +364,6 @@ ASYNC_WORK_DEF(p2r_symbol_stream_convert_work); internal P2R_Convert2Bake *p2r_convert(Arena *arena, P2R_User2Convert *in); -//////////////////////////////// -//~ rjf: Baking Stage Tasks - -//- rjf: unsorted bake string map building -ASYNC_WORK_DEF(p2r_bake_src_files_strings_work); -ASYNC_WORK_DEF(p2r_bake_units_strings_work); -ASYNC_WORK_DEF(p2r_bake_types_strings_work); -ASYNC_WORK_DEF(p2r_bake_udts_strings_work); -ASYNC_WORK_DEF(p2r_bake_symbols_strings_work); -ASYNC_WORK_DEF(p2r_bake_scopes_strings_work); -ASYNC_WORK_DEF(p2r_bake_line_tables_work); - -//- rjf: bake string map joining -ASYNC_WORK_DEF(p2r_bake_string_map_join_work); - -//- rjf: bake string map sorting -ASYNC_WORK_DEF(p2r_bake_string_map_sort_work); - -//- rjf: pass 1: interner/deduper map builds -ASYNC_WORK_DEF(p2r_build_bake_name_map_work); - -//- rjf: pass 2: string-map-dependent debug info stream builds -ASYNC_WORK_DEF(p2r_bake_units_work); -ASYNC_WORK_DEF(p2r_bake_unit_vmap_work); -ASYNC_WORK_DEF(p2r_bake_src_files_work); -ASYNC_WORK_DEF(p2r_bake_udts_work); -ASYNC_WORK_DEF(p2r_bake_global_variables_work); -ASYNC_WORK_DEF(p2r_bake_global_vmap_work); -ASYNC_WORK_DEF(p2r_bake_thread_variables_work); -ASYNC_WORK_DEF(p2r_bake_procedures_work); -ASYNC_WORK_DEF(p2r_bake_scopes_work); -ASYNC_WORK_DEF(p2r_bake_scope_vmap_work); -ASYNC_WORK_DEF(p2r_bake_file_paths_work); -ASYNC_WORK_DEF(p2r_bake_strings_work); - -//- rjf: pass 3: idx-run-map-dependent debug info stream builds -ASYNC_WORK_DEF(p2r_bake_type_nodes_work); -ASYNC_WORK_DEF(p2r_bake_name_map_work); -ASYNC_WORK_DEF(p2r_bake_idx_runs_work); - //////////////////////////////// //~ rjf: Top-Level Initialization diff --git a/src/rdi_from_pdb/rdi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c index 9b2e49b5..a0d02a7d 100644 --- a/src/rdi_from_pdb/rdi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -19,6 +19,7 @@ //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" +#include "path/path.h" #include "async/async.h" #include "rdi_make/rdi_make_local.h" #include "coff/coff.h" @@ -35,6 +36,7 @@ //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" +#include "path/path.c" #include "async/async.c" #include "rdi_make/rdi_make_local.c" #include "coff/coff.c" diff --git a/src/rdi_make/rdi_make_help.c b/src/rdi_make/rdi_make_help.c new file mode 100644 index 00000000..35ff0d9b --- /dev/null +++ b/src/rdi_make/rdi_make_help.c @@ -0,0 +1,925 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Baking Stage Tasks + +//- rjf: bake string map building + +#define rdim_make_string_map_if_needed() do {if(in->maps[thread_idx] == 0) ProfScope("make map") {in->maps[thread_idx] = rdim_bake_string_map_loose_make(arena, in->top);}} while(0) + +ASYNC_WORK_DEF(rdim_bake_src_files_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeSrcFilesStringsIn *in = (RDIM_BakeSrcFilesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake src file strings") rdim_bake_string_map_loose_push_src_files(arena, in->top, in->maps[thread_idx], in->list); + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_units_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitsStringsIn *in = (RDIM_BakeUnitsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake unit strings") rdim_bake_string_map_loose_push_units(arena, in->top, in->maps[thread_idx], in->list); + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_types_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeTypesStringsIn *in = (RDIM_BakeTypesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake type strings") + { + for(RDIM_BakeTypesStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_type_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_udts_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeUDTsStringsIn *in = (RDIM_BakeUDTsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake udt strings") + { + for(RDIM_BakeUDTsStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_udt_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_symbols_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeSymbolsStringsIn *in = (RDIM_BakeSymbolsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake symbol strings") + { + for(RDIM_BakeSymbolsStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_symbol_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_inline_site_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeInlineSiteStringsIn *in = input; + rdim_make_string_map_if_needed(); + ProfScope("bake inline site strings") + { + for(RDIM_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_scopes_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopesStringsIn *in = (RDIM_BakeScopesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake scope strings") + { + for(RDIM_BakeScopesStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_scope_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_line_tables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeLineTablesIn *in = (RDIM_BakeLineTablesIn *)input; + RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); + ProfScope("bake line tables") *out = rdim_bake_line_tables(arena, in->line_tables); + ProfEnd(); + return out; +} + +#undef rdim_make_string_map_if_needed + +//- rjf: bake string map joining + +ASYNC_WORK_DEF(rdim_bake_string_map_join_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_JoinBakeStringMapSlotsIn *in = (RDIM_JoinBakeStringMapSlotsIn *)input; + ProfScope("join bake string maps") + { + for(U64 src_map_idx = 0; src_map_idx < in->src_maps_count; src_map_idx += 1) + { + for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1) + { + B32 src_slots_good = (in->src_maps[src_map_idx] != 0 && in->src_maps[src_map_idx]->slots != 0); + B32 dst_slot_is_zero = (in->dst_map->slots[slot_idx] == 0); + if(src_slots_good && dst_slot_is_zero) + { + in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx]; + } + else if(src_slots_good && in->src_maps[src_map_idx]->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]); + } + } + } + } + ProfEnd(); + return 0; +} + +//- rjf: bake string map sorting + +ASYNC_WORK_DEF(rdim_bake_string_map_sort_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_SortBakeStringMapSlotsIn *in = (RDIM_SortBakeStringMapSlotsIn *)input; + ProfScope("sort bake string chunk list map range") + { + for(U64 slot_idx = in->slot_idx; + slot_idx < in->slot_idx+in->slot_count; + slot_idx += 1) + { + if(in->src_map->slots[slot_idx] != 0) + { + if(in->src_map->slots[slot_idx]->total_count > 1) + { + in->dst_map->slots[slot_idx] = push_array(arena, RDIM_BakeStringChunkList, 1); + *in->dst_map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, in->src_map->slots[slot_idx]); + } + else + { + in->dst_map->slots[slot_idx] = in->src_map->slots[slot_idx]; + } + } + } + } + ProfEnd(); + return 0; +} + +//- rjf: pass 1: interner/deduper map builds + +ASYNC_WORK_DEF(rdim_build_bake_name_map_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BuildBakeNameMapIn *in = (RDIM_BuildBakeNameMapIn *)input; + RDIM_BakeNameMap *name_map = 0; + ProfScope("build name map %i", in->k) name_map = rdim_bake_name_map_from_kind_params(arena, in->k, in->type_indices, in->params); + ProfEnd(); + return name_map; +} + +//- rjf: pass 2: string-map-dependent debug info stream builds + +ASYNC_WORK_DEF(rdim_bake_units_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitsIn *in = (RDIM_BakeUnitsIn *)input; + RDIM_UnitBakeResult *out = push_array(arena, RDIM_UnitBakeResult, 1); + ProfScope("bake units") *out = rdim_bake_units(arena, in->strings, in->path_tree, in->units); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_unit_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitVMapIn *in = (RDIM_BakeUnitVMapIn *)input; + RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); + ProfScope("bake unit vmap") *out = rdim_bake_unit_vmap(arena, in->units); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_src_files_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeSrcFilesIn *in = (RDIM_BakeSrcFilesIn *)input; + RDIM_SrcFileBakeResult *out = push_array(arena, RDIM_SrcFileBakeResult, 1); + ProfScope("bake src files") *out = rdim_bake_src_files(arena, in->strings, in->path_tree, in->src_files); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_udts_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeUDTsIn *in = (RDIM_BakeUDTsIn *)input; + RDIM_UDTBakeResult *out = push_array(arena, RDIM_UDTBakeResult, 1); + ProfScope("bake udts") *out = rdim_bake_udts(arena, in->strings, in->type_indices, in->udts); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_global_variables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeGlobalVariablesIn *in = (RDIM_BakeGlobalVariablesIn *)input; + RDIM_GlobalVariableBakeResult *out = push_array(arena, RDIM_GlobalVariableBakeResult, 1); + ProfScope("bake global variables") *out = rdim_bake_global_variables(arena, in->strings, in->type_indices, in->global_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_global_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeGlobalVMapIn *in = (RDIM_BakeGlobalVMapIn *)input; + RDIM_GlobalVMapBakeResult *out = push_array(arena, RDIM_GlobalVMapBakeResult, 1); + ProfScope("bake global vmap") *out = rdim_bake_global_vmap(arena, in->global_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_thread_variables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeThreadVariablesIn *in = (RDIM_BakeThreadVariablesIn *)input; + RDIM_ThreadVariableBakeResult *out = push_array(arena, RDIM_ThreadVariableBakeResult, 1); + ProfScope("bake thread variables") *out = rdim_bake_thread_variables(arena, in->strings, in->type_indices, in->thread_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_procedures_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeProceduresIn *in = (RDIM_BakeProceduresIn *)input; + RDIM_ProcedureBakeResult *out = push_array(arena, RDIM_ProcedureBakeResult, 1); + ProfScope("bake procedures") *out = rdim_bake_procedures(arena, in->strings, in->type_indices, in->location_blocks, in->location_data_blobs, in->procedures); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_scopes_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopesIn *in = (RDIM_BakeScopesIn *)input; + RDIM_ScopeBakeResult *out = push_array(arena, RDIM_ScopeBakeResult, 1); + ProfScope("bake scopes") *out = rdim_bake_scopes(arena, in->strings, in->type_indices, in->location_blocks, in->location_data_blobs, in->scopes); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_scope_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopeVMapIn *in = (RDIM_BakeScopeVMapIn *)input; + RDIM_ScopeVMapBakeResult *out = push_array(arena, RDIM_ScopeVMapBakeResult, 1); + ProfScope("bake scope vmap") *out = rdim_bake_scope_vmap(arena, in->scopes); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_inline_sites_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeInlineSitesIn *in = (RDIM_BakeInlineSitesIn *)input; + RDIM_InlineSiteBakeResult *out = push_array(arena, RDIM_InlineSiteBakeResult, 1); + ProfScope("bake inline sites") *out = rdim_bake_inline_sites(arena, in->strings, in->type_indices, in->inline_sites); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_file_paths_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeFilePathsIn *in = (RDIM_BakeFilePathsIn *)input; + RDIM_FilePathBakeResult *out = push_array(arena, RDIM_FilePathBakeResult, 1); + ProfScope("bake file paths") *out = rdim_bake_file_paths(arena, in->strings, in->path_tree); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeStringsIn *in = (RDIM_BakeStringsIn *)input; + RDIM_StringBakeResult *out = push_array(arena, RDIM_StringBakeResult, 1); + ProfScope("bake strings") *out = rdim_bake_strings(arena, in->strings); + ProfEnd(); + return out; +} + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds + +ASYNC_WORK_DEF(rdim_bake_type_nodes_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeTypeNodesIn *in = (RDIM_BakeTypeNodesIn *)input; + RDIM_TypeNodeBakeResult *out = push_array(arena, RDIM_TypeNodeBakeResult, 1); + ProfScope("bake type nodes") *out = rdim_bake_types(arena, in->strings, in->idx_runs, in->type_indices, in->types); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_name_map_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeNameMapIn *in = (RDIM_BakeNameMapIn *)input; + RDIM_NameMapBakeResult *out = push_array(arena, RDIM_NameMapBakeResult, 1); + ProfScope("bake name map %i", in->kind) *out = rdim_bake_name_map(arena, in->strings, in->idx_runs, in->map); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_idx_runs_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_help_state->work_thread_arenas[thread_idx]; + RDIM_BakeIdxRunsIn *in = (RDIM_BakeIdxRunsIn *)input; + RDIM_IndexRunBakeResult *out = push_array(arena, RDIM_IndexRunBakeResult, 1); + ProfScope("bake idx runs") *out = rdim_bake_index_runs(arena, in->idx_runs); + ProfEnd(); + return out; +} + +internal RDIM_HelpState * +rdim_help_init(void) +{ + Arena *arena = arena_alloc(); + RDIM_HelpState *state = push_array(arena, RDIM_HelpState, 1); + state->arena = arena; + state->work_thread_arenas_count = async_thread_count(); + state->work_thread_arenas = push_array(arena, Arena *, state->work_thread_arenas_count); + for EachIndex(idx, state->work_thread_arenas_count) + { + state->work_thread_arenas[idx] = arena_alloc(); + } + return state; +} + +internal RDIM_BakeResults +rdim_bake(RDIM_HelpState *state, RDIM_BakeParams *in_params) +{ + Temp scratch = scratch_begin(0,0); + RDIM_BakeResults out = {0}; + + rdim_help_state = state; + + //////////////////////////////// + // compute type indices + + RDI_U64 *type_indices = rdim_make_type_indices(scratch.arena, &in_params->types); + + ////////////////////////////// + //- rjf: kick off line tables baking + // + ASYNC_Task *bake_line_tables_task = 0; + { + RDIM_BakeLineTablesIn *in = push_array(scratch.arena, RDIM_BakeLineTablesIn, 1); + in->line_tables = &in_params->line_tables; + bake_line_tables_task = async_task_launch(scratch.arena, rdim_bake_line_tables_work, .input = in); + } + + ////////////////////////////// + //- rjf: build interned path tree + // + RDIM_BakePathTree *path_tree = 0; + ProfScope("build interned path tree") + { + path_tree = rdim_bake_path_tree_from_params(state->arena, in_params); + } + + ////////////////////////////// + //- rjf: kick off string map building tasks + // + RDIM_BakeStringMapTopology bake_string_map_topology = {(64 + + in_params->procedures.total_count*1 + + in_params->global_variables.total_count*1 + + in_params->thread_variables.total_count*1 + + in_params->types.total_count/2)}; + RDIM_BakeStringMapLoose **bake_string_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringMapLoose *, async_thread_count()); + ASYNC_TaskList bake_string_map_build_tasks = {0}; + { + // rjf: src files + ProfScope("kick off src files string map build task") + { + RDIM_BakeSrcFilesStringsIn *in = push_array(scratch.arena, RDIM_BakeSrcFilesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + in->list = &in_params->src_files; + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_src_files_strings_work, .input = in)); + } + + // rjf: units + ProfScope("kick off units string map build task") + { + RDIM_BakeUnitsStringsIn *in = push_array(scratch.arena, RDIM_BakeUnitsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + in->list = &in_params->units; + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_units_strings_work, .input = in)); + } + + // rjf: types + ProfScope("kick off types string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->types.total_count+items_per_task-1)/items_per_task; + RDIM_TypeChunkNode *chunk = in_params->types.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeTypesStringsIn *in = push_array(scratch.arena, RDIM_BakeTypesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeTypesStringsInNode *n = push_array(scratch.arena, RDIM_BakeTypesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_types_strings_work, .input = in)); + } + } + + // rjf: UDTs + ProfScope("kick off udts string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->udts.total_count+items_per_task-1)/items_per_task; + RDIM_UDTChunkNode *chunk = in_params->udts.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeUDTsStringsIn *in = push_array(scratch.arena, RDIM_BakeUDTsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeUDTsStringsInNode *n = push_array(scratch.arena, RDIM_BakeUDTsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_udts_strings_work, .input = in)); + } + } + + // rjf: symbols + ProfScope("kick off symbols string map build tasks") + { + RDIM_SymbolChunkList *symbol_lists[] = + { + &in_params->global_variables, + &in_params->thread_variables, + &in_params->procedures, + }; + for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1) + { + U64 items_per_task = 4096; + U64 num_tasks = (symbol_lists[list_idx]->total_count+items_per_task-1)/items_per_task; + RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeSymbolsStringsIn *in = push_array(scratch.arena, RDIM_BakeSymbolsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeSymbolsStringsInNode *n = push_array(scratch.arena, RDIM_BakeSymbolsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_symbols_strings_work, .input = in)); + } + } + } + + ProfScope("kick off inline site string map build task") + { + U64 items_per_task = 4096; + U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task); + RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeInlineSiteStringsIn *in = push_array(scratch.arena, RDIM_BakeInlineSiteStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, RDIM_BakeInlineSiteStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_inline_site_strings_work, .input = in)); + } + } + + // rjf: scope chunks + ProfScope("kick off scope chunks string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->scopes.total_count+items_per_task-1)/items_per_task; + RDIM_ScopeChunkNode *chunk = in_params->scopes.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeScopesStringsIn *in = push_array(scratch.arena, RDIM_BakeScopesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeScopesStringsInNode *n = push_array(scratch.arena, RDIM_BakeScopesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_scopes_strings_work, .input = in)); + } + } + } + + ////////////////////////////// + //- rjf: kick off name map building tasks + // + RDIM_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0}; + ASYNC_Task *build_bake_name_map_task[RDI_NameMapKind_COUNT] = {0}; + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + build_bake_name_map_in[k].k = k; + build_bake_name_map_in[k].type_indices = type_indices; + build_bake_name_map_in[k].params = in_params; + build_bake_name_map_task[k] = async_task_launch(scratch.arena, rdim_build_bake_name_map_work, .input = &build_bake_name_map_in[k]); + } + + ////////////////////////////// + //- rjf: join string map building tasks + // + ProfScope("join string map building tasks") + { + for(ASYNC_TaskNode *n = bake_string_map_build_tasks.first; n != 0; n = n->next) + { + async_task_join(n->v); + } + } + + ////////////////////////////// + //- rjf: produce joined string map + // + RDIM_BakeStringMapLoose *unsorted_bake_string_map = rdim_bake_string_map_loose_make(state->arena, &bake_string_map_topology); + ProfScope("produce joined string map") + { + U64 slots_per_task = 16384; + U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; + ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, num_tasks); + + // rjf: kickoff tasks + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_JoinBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_JoinBakeStringMapSlotsIn, 1); + in->top = &bake_string_map_topology; + in->src_maps = bake_string_maps__in_progress; + in->src_maps_count = async_thread_count(); + in->dst_map = unsorted_bake_string_map; + in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task); + in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count); + tasks[task_idx] = async_task_launch(scratch.arena, rdim_bake_string_map_join_work, .input = in); + } + + // rjf: join tasks + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + async_task_join(tasks[task_idx]); + } + + // rjf: insert small top-level stuff + rdim_bake_string_map_loose_push_top_level_info(state->arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(state->arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->binary_sections); + rdim_bake_string_map_loose_push_path_tree(state->arena, &bake_string_map_topology, unsorted_bake_string_map, path_tree); + } + + ////////////////////////////// + //- rjf: kick off string map sorting tasks + // + ASYNC_TaskList sort_bake_string_map_tasks = {0}; + RDIM_BakeStringMapLoose *sorted_bake_string_map__in_progress = rdim_bake_string_map_loose_make(state->arena, &bake_string_map_topology); + { + U64 slots_per_task = 4096; + U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_SortBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_SortBakeStringMapSlotsIn, 1); + { + in->top = &bake_string_map_topology; + in->src_map = unsorted_bake_string_map; + in->dst_map = sorted_bake_string_map__in_progress; + in->slot_idx = task_idx*slots_per_task; + in->slot_count = slots_per_task; + if(in->slot_idx+in->slot_count > bake_string_map_topology.slots_count) + { + in->slot_count = bake_string_map_topology.slots_count - in->slot_idx; + } + } + async_task_list_push(scratch.arena, &sort_bake_string_map_tasks, async_task_launch(scratch.arena, rdim_bake_string_map_sort_work, .input = in)); + } + } + + ////////////////////////////// + //- rjf: join string map sorting tasks + // + ProfScope("join string map sorting tasks") + { + for(ASYNC_TaskNode *n = sort_bake_string_map_tasks.first; n != 0; n = n->next) + { + async_task_join(n->v); + } + } + RDIM_BakeStringMapLoose *sorted_bake_string_map = sorted_bake_string_map__in_progress; + + ////////////////////////////// + //- rjf: build finalized string map + // + ProfBegin("build finalized string map base indices"); + RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(state->arena, &bake_string_map_topology, sorted_bake_string_map); + ProfEnd(); + ProfBegin("build finalized string map"); + RDIM_BakeStringMapTight bake_strings = rdim_bake_string_map_tight_from_loose(state->arena, &bake_string_map_topology, &bake_string_map_base_idxes, sorted_bake_string_map); + ProfEnd(); + + ////////////////////////////// + //- rjf: kick off pass 2 tasks + // + RDIM_BakeUnitsIn bake_units_top_level_in = {&bake_strings, path_tree, &in_params->units}; + ASYNC_Task *bake_units_task = async_task_launch(scratch.arena, rdim_bake_units_work, .input = &bake_units_top_level_in); + RDIM_BakeUnitVMapIn bake_unit_vmap_in = {&in_params->units}; + ASYNC_Task *bake_unit_vmap_task = async_task_launch(scratch.arena, rdim_bake_unit_vmap_work, .input = &bake_unit_vmap_in); + RDIM_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, &in_params->src_files}; + ASYNC_Task *bake_src_files_task = async_task_launch(scratch.arena, rdim_bake_src_files_work, .input = &bake_src_files_in); + RDIM_BakeUDTsIn bake_udts_in = {&bake_strings, &in_params->udts, type_indices}; + ASYNC_Task *bake_udts_task = async_task_launch(scratch.arena, rdim_bake_udts_work, .input = &bake_udts_in); + RDIM_BakeGlobalVMapIn bake_global_vmap_in = {&in_params->global_variables}; + ASYNC_Task *bake_global_vmap_task = async_task_launch(scratch.arena, rdim_bake_global_vmap_work, .input = &bake_global_vmap_in); + RDIM_BakeScopeVMapIn bake_scope_vmap_in = {&in_params->scopes}; + ASYNC_Task *bake_scope_vmap_task = async_task_launch(scratch.arena, rdim_bake_scope_vmap_work, .input = &bake_scope_vmap_in); + RDIM_BakeInlineSitesIn bake_inline_sites_in = {&bake_strings, &in_params->inline_sites, type_indices}; + ASYNC_Task *bake_inline_sites_task = async_task_launch(scratch.arena, rdim_bake_inline_sites_work, .input = &bake_inline_sites_in); + RDIM_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; + ASYNC_Task *bake_file_paths_task = async_task_launch(scratch.arena, rdim_bake_file_paths_work, .input = &bake_file_paths_in); + RDIM_BakeStringsIn bake_strings_in = {&bake_strings}; + ASYNC_Task *bake_strings_task = async_task_launch(scratch.arena, rdim_bake_strings_work, .input = &bake_strings_in); + + RDIM_String8List location_blocks = {0}; + RDIM_String8List location_data_blobs = {0}; + + // reserve null location block for opl + rdim_location_block_chunk_list_push_array(state->arena, &location_blocks, 1); + + // TODO: export location instead of VOFF + RDIM_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, &in_params->thread_variables, type_indices}; + ASYNC_Task *bake_thread_variables_task = async_task_launch(scratch.arena, rdim_bake_thread_variables_work, .input = &bake_thread_variables_in); + ProfScope("thread variables") out.thread_variables = *async_task_join_struct(bake_thread_variables_task, RDIM_ThreadVariableBakeResult); + + // TODO: export location instead of VOFF + RDIM_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, &in_params->global_variables, type_indices}; + ASYNC_Task *bake_global_variables_task = async_task_launch(scratch.arena, rdim_bake_global_variables_work, .input = &bake_global_variables_in); + ProfScope("global variables") out.global_variables = *async_task_join_struct(bake_global_variables_task, RDIM_GlobalVariableBakeResult); + + RDIM_BakeScopesIn bake_scopes_in = {&bake_strings, &in_params->scopes, type_indices, &location_blocks, &location_data_blobs}; + ASYNC_Task *bake_scopes_task = async_task_launch(scratch.arena, rdim_bake_scopes_work, .input = &bake_scopes_in); + ProfScope("scopes") out.scopes = *async_task_join_struct(bake_scopes_task, RDIM_ScopeBakeResult); + + RDIM_BakeProceduresIn bake_procedures_in = {&bake_strings, &in_params->procedures, type_indices, &location_blocks, &location_data_blobs}; + ASYNC_Task *bake_procedures_task = async_task_launch(scratch.arena, rdim_bake_procedures_work, .input = &bake_procedures_in); + ProfScope("procedures") out.procedures = *async_task_join_struct(bake_procedures_task, RDIM_ProcedureBakeResult); + + ////////////////////////////// + //- rjf: join name map building tasks + // + RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT] = {0}; + ProfScope("join name map building tasks") + { + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + name_maps[k] = async_task_join_struct(build_bake_name_map_task[k], RDIM_BakeNameMap); + } + } + + ////////////////////////////// + //- rjf: build interned idx run map + // + RDIM_BakeIdxRunMap *idx_runs = 0; + ProfScope("build interned idx run map") + { + idx_runs = rdim_bake_idx_run_map_from_params(state->arena, name_maps, type_indices, in_params); + } + + ////////////////////////////// + //- rjf: do small top-level bakes + // + ProfScope("top level info") out.top_level_info = rdim_bake_top_level_info(state->arena, &bake_strings, &in_params->top_level_info); + ProfScope("binary sections") out.binary_sections = rdim_bake_binary_sections(state->arena, &bake_strings, &in_params->binary_sections); + ProfScope("top level name maps section") out.top_level_name_maps = rdim_bake_name_maps_top_level(state->arena, &bake_strings, idx_runs, name_maps); + + ////////////////////////////// + //- rjf: kick off pass 3 tasks + // + RDIM_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, &in_params->types, type_indices}; + ASYNC_Task *bake_type_nodes_task = async_task_launch(scratch.arena, rdim_bake_type_nodes_work, .input = &bake_type_nodes_in); + ASYNC_Task *bake_name_maps_tasks[RDI_NameMapKind_COUNT] = {0}; + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + if(name_maps[k] == 0 || name_maps[k]->name_count == 0) + { + continue; + } + RDIM_BakeNameMapIn *in = push_array(scratch.arena, RDIM_BakeNameMapIn, 1); + in->strings = &bake_strings; + in->idx_runs = idx_runs; + in->map = name_maps[k]; + in->kind = k; + bake_name_maps_tasks[k] = async_task_launch(scratch.arena, rdim_bake_name_map_work, .input = in); + } + } + RDIM_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; + ASYNC_Task *bake_idx_runs_task = async_task_launch(scratch.arena, rdim_bake_idx_runs_work, .input = &bake_idx_runs_in); + + ////////////////////////////// + //- rjf: join remaining completed bakes + // + ProfScope("top-level units info") out.units = *async_task_join_struct(bake_units_task, RDIM_UnitBakeResult); + ProfScope("unit vmap") out.unit_vmap = *async_task_join_struct(bake_unit_vmap_task, RDIM_UnitVMapBakeResult); + ProfScope("source files") out.src_files = *async_task_join_struct(bake_src_files_task, RDIM_SrcFileBakeResult); + ProfScope("UDTs") out.udts = *async_task_join_struct(bake_udts_task, RDIM_UDTBakeResult); + ProfScope("global vmap") out.global_vmap = *async_task_join_struct(bake_global_vmap_task, RDIM_GlobalVMapBakeResult); + ProfScope("scope vmap") out.scope_vmap = *async_task_join_struct(bake_scope_vmap_task, RDIM_ScopeVMapBakeResult); + ProfScope("inline sites") out.inline_sites = *async_task_join_struct(bake_inline_sites_task, RDIM_InlineSiteBakeResult); + ProfScope("file paths") out.file_paths = *async_task_join_struct(bake_file_paths_task, RDIM_FilePathBakeResult); + ProfScope("strings") out.strings = *async_task_join_struct(bake_strings_task, RDIM_StringBakeResult); + ProfScope("type nodes") out.type_nodes = *async_task_join_struct(bake_type_nodes_task, RDIM_TypeNodeBakeResult); + ProfScope("idx runs") out.idx_runs = *async_task_join_struct(bake_idx_runs_task, RDIM_IndexRunBakeResult); + ProfScope("line tables") out.line_tables = *async_task_join_struct(bake_line_tables_task, RDIM_LineTableBakeResult); + + ////////////////////////////// + //- rjf: join individual name map bakes + // + RDIM_NameMapBakeResult name_map_bakes[RDI_NameMapKind_COUNT] = {0}; + ProfScope("name maps") + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDIM_NameMapBakeResult *bake = async_task_join_struct(bake_name_maps_tasks[k], RDIM_NameMapBakeResult); + if(bake != 0) + { + name_map_bakes[k] = *bake; + } + } + } + + ////////////////////////////// + //- rjf: join all individual name map bakes + // + ProfScope("join all name map bakes into final name map bake") + { + out.name_maps = rdim_name_map_bake_results_combine(state->arena, name_map_bakes, ArrayCount(name_map_bakes)); + } + + + //////////////////////////////// + + out.location_blocks = rdim_str8_list_join(state->arena, &location_blocks, rdim_str8(0,0)); + out.location_data = rdim_str8_list_join(state->arena, &location_data_blobs, rdim_str8(0,0)); + + rdim_help_state = 0; + + scratch_end(scratch); + return out; +} + +internal RDIM_SerializedSectionBundle +rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) +{ + RDIM_SerializedSectionBundle out = {0}; + + //- rjf: set up compression context + rr_lzb_simple_context ctx = {0}; + ctx.m_tableSizeBits = 14; + ctx.m_hashTable = push_array(arena, U16, 1<sections[k]; + RDIM_SerializedSection *dst = &out.sections[k]; + MemoryCopyStruct(dst, src); + + // rjf: determine if this section should be compressed + B32 should_compress = 1; + + // rjf: compress if needed + if(should_compress) + { + MemoryZero(ctx.m_hashTable, sizeof(U16)*(1<data = push_array_no_zero(arena, U8, src->encoded_size); + dst->encoded_size = rr_lzb_simple_encode_veryfast(&ctx, src->data, src->encoded_size, dst->data); + dst->unpacked_size = src->encoded_size; + dst->encoding = RDI_SectionEncoding_LZB; + } + } + + return out; +} diff --git a/src/rdi_make/rdi_make_help.h b/src/rdi_make/rdi_make_help.h new file mode 100644 index 00000000..08c64391 --- /dev/null +++ b/src/rdi_make/rdi_make_help.h @@ -0,0 +1,342 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RDIM_MAKE_HELP +#define RDIM_MAKE_HELP + +//- rjf: line table baking task types + +typedef struct RDIM_BakeLineTablesIn RDIM_BakeLineTablesIn; +struct RDIM_BakeLineTablesIn +{ + RDIM_LineTableChunkList *line_tables; +}; + +//- rjf: string map baking task types + +typedef struct RDIM_BakeSrcFilesStringsIn RDIM_BakeSrcFilesStringsIn; +struct RDIM_BakeSrcFilesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_SrcFileChunkList *list; +}; + +typedef struct RDIM_BakeUnitsStringsIn RDIM_BakeUnitsStringsIn; +struct RDIM_BakeUnitsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_UnitChunkList *list; +}; + +typedef struct RDIM_BakeUDTsStringsInNode RDIM_BakeUDTsStringsInNode; +struct RDIM_BakeUDTsStringsInNode +{ + RDIM_BakeUDTsStringsInNode *next; + RDIM_UDT *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeTypesStringsInNode RDIM_BakeTypesStringsInNode; +struct RDIM_BakeTypesStringsInNode +{ + RDIM_BakeTypesStringsInNode *next; + RDIM_Type *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeTypesStringsIn RDIM_BakeTypesStringsIn; +struct RDIM_BakeTypesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeTypesStringsInNode *first; + RDIM_BakeTypesStringsInNode *last; +}; + +typedef struct RDIM_BakeUDTsStringsIn RDIM_BakeUDTsStringsIn; +struct RDIM_BakeUDTsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeUDTsStringsInNode *first; + RDIM_BakeUDTsStringsInNode *last; +}; + +typedef struct RDIM_BakeSymbolsStringsInNode RDIM_BakeSymbolsStringsInNode; +struct RDIM_BakeSymbolsStringsInNode +{ + RDIM_BakeSymbolsStringsInNode *next; + RDIM_Symbol *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeSymbolsStringsIn RDIM_BakeSymbolsStringsIn; +struct RDIM_BakeSymbolsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeSymbolsStringsInNode *first; + RDIM_BakeSymbolsStringsInNode *last; +}; + +typedef struct RDIM_BakeInlineSiteStringsInNode RDIM_BakeInlineSiteStringsInNode; +struct RDIM_BakeInlineSiteStringsInNode +{ + RDIM_BakeInlineSiteStringsInNode *next; + RDIM_InlineSite *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeInlineSiteStringsIn RDIM_BakeInlineSiteStringsIn; +struct RDIM_BakeInlineSiteStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeInlineSiteStringsInNode *first; + RDIM_BakeInlineSiteStringsInNode *last; +}; + +typedef struct RDIM_BakeScopesStringsInNode RDIM_BakeScopesStringsInNode; +struct RDIM_BakeScopesStringsInNode +{ + RDIM_BakeScopesStringsInNode *next; + RDIM_Scope *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeScopesStringsIn RDIM_BakeScopesStringsIn; +struct RDIM_BakeScopesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeScopesStringsInNode *first; + RDIM_BakeScopesStringsInNode *last; +}; + +//- rjf: OLD string map baking types + +typedef struct RDIM_BuildBakeStringMapIn RDIM_BuildBakeStringMapIn; +struct RDIM_BuildBakeStringMapIn +{ + RDIM_BakePathTree *path_tree; + RDIM_BakeParams *params; +}; + +typedef struct RDIM_BuildBakeNameMapIn RDIM_BuildBakeNameMapIn; +struct RDIM_BuildBakeNameMapIn +{ + RDI_NameMapKind k; + RDI_U64 *type_indices; + RDIM_BakeParams *params; +}; + +//- rjf: string map joining task types + +typedef struct RDIM_JoinBakeStringMapSlotsIn RDIM_JoinBakeStringMapSlotsIn; +struct RDIM_JoinBakeStringMapSlotsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **src_maps; + U64 src_maps_count; + RDIM_BakeStringMapLoose *dst_map; + Rng1U64 slot_idx_range; +}; + +//- rjf: string map sorting task types + +typedef struct RDIM_SortBakeStringMapSlotsIn RDIM_SortBakeStringMapSlotsIn; +struct RDIM_SortBakeStringMapSlotsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose *src_map; + RDIM_BakeStringMapLoose *dst_map; + U64 slot_idx; + U64 slot_count; +}; + +//- rjf: debug info baking task types + +typedef struct RDIM_BakeUnitsIn RDIM_BakeUnitsIn; +struct RDIM_BakeUnitsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_UnitChunkList *units; +}; + +typedef struct RDIM_BakeUnitVMapIn RDIM_BakeUnitVMapIn; +struct RDIM_BakeUnitVMapIn +{ + RDIM_UnitChunkList *units; +}; + +typedef struct RDIM_BakeSrcFilesIn RDIM_BakeSrcFilesIn; +struct RDIM_BakeSrcFilesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_SrcFileChunkList *src_files; +}; + +typedef struct RDIM_BakeUDTsIn RDIM_BakeUDTsIn; +struct RDIM_BakeUDTsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_UDTChunkList *udts; + RDI_U64 *type_indices; +}; + +typedef struct RDIM_BakeGlobalVariablesIn RDIM_BakeGlobalVariablesIn; +struct RDIM_BakeGlobalVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *global_variables; + RDI_U64 *type_indices; +}; + +typedef struct RDIM_BakeGlobalVMapIn RDIM_BakeGlobalVMapIn; +struct RDIM_BakeGlobalVMapIn +{ + RDIM_SymbolChunkList *global_variables; +}; + +typedef struct RDIM_BakeThreadVariablesIn RDIM_BakeThreadVariablesIn; +struct RDIM_BakeThreadVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *thread_variables; + RDI_U64 *type_indices; +}; + +typedef struct RDIM_BakeProceduresIn RDIM_BakeProceduresIn; +struct RDIM_BakeProceduresIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *procedures; + RDI_U64 *type_indices; + RDIM_String8List *location_blocks; + RDIM_String8List *location_data_blobs; +}; + +typedef struct RDIM_BakeScopesIn RDIM_BakeScopesIn; +struct RDIM_BakeScopesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_ScopeChunkList *scopes; + RDI_U64 *type_indices; + RDIM_String8List *location_blocks; + RDIM_String8List *location_data_blobs; +}; + +typedef struct RDIM_BakeScopeVMapIn RDIM_BakeScopeVMapIn; +struct RDIM_BakeScopeVMapIn +{ + RDIM_ScopeChunkList *scopes; +}; + +typedef struct RDIM_BakeInlineSitesIn RDIM_BakeInlineSitesIn; +struct RDIM_BakeInlineSitesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_InlineSiteChunkList *inline_sites; + RDI_U64 *type_indices; +}; + +typedef struct RDIM_BakeFilePathsIn RDIM_BakeFilePathsIn; +struct RDIM_BakeFilePathsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; +}; + +typedef struct RDIM_BakeStringsIn RDIM_BakeStringsIn; +struct RDIM_BakeStringsIn +{ + RDIM_BakeStringMapTight *strings; +}; + +typedef struct RDIM_BakeTypeNodesIn RDIM_BakeTypeNodesIn; +struct RDIM_BakeTypeNodesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeIdxRunMap *idx_runs; + RDIM_TypeChunkList *types; + RDI_U64 *type_indices; +}; + +typedef struct RDIM_BakeNameMapIn RDIM_BakeNameMapIn; +struct RDIM_BakeNameMapIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeIdxRunMap *idx_runs; + RDIM_BakeNameMap *map; + RDI_NameMapKind kind; +}; + +typedef struct RDIM_BakeIdxRunsIn RDIM_BakeIdxRunsIn; +struct RDIM_BakeIdxRunsIn +{ + RDIM_BakeIdxRunMap *idx_runs; +}; + +//////////////////////////////// +//~ rjf: Baking Stage Tasks + +//- rjf: unsorted bake string map building +ASYNC_WORK_DEF(p2r_bake_src_files_strings_work); +ASYNC_WORK_DEF(p2r_bake_units_strings_work); +ASYNC_WORK_DEF(p2r_bake_types_strings_work); +ASYNC_WORK_DEF(p2r_bake_udts_strings_work); +ASYNC_WORK_DEF(p2r_bake_symbols_strings_work); +ASYNC_WORK_DEF(p2r_bake_scopes_strings_work); +ASYNC_WORK_DEF(p2r_bake_line_tables_work); + +//- rjf: bake string map joining +ASYNC_WORK_DEF(p2r_bake_string_map_join_work); + +//- rjf: bake string map sorting +ASYNC_WORK_DEF(p2r_bake_string_map_sort_work); + +//- rjf: pass 1: interner/deduper map builds +ASYNC_WORK_DEF(p2r_build_bake_name_map_work); + +//- rjf: pass 2: string-map-dependent debug info stream builds +ASYNC_WORK_DEF(p2r_bake_units_work); +ASYNC_WORK_DEF(p2r_bake_unit_vmap_work); +ASYNC_WORK_DEF(p2r_bake_src_files_work); +ASYNC_WORK_DEF(p2r_bake_udts_work); +ASYNC_WORK_DEF(p2r_bake_global_variables_work); +ASYNC_WORK_DEF(p2r_bake_global_vmap_work); +ASYNC_WORK_DEF(p2r_bake_thread_variables_work); +ASYNC_WORK_DEF(p2r_bake_procedures_work); +ASYNC_WORK_DEF(p2r_bake_scopes_work); +ASYNC_WORK_DEF(p2r_bake_scope_vmap_work); +ASYNC_WORK_DEF(p2r_bake_file_paths_work); +ASYNC_WORK_DEF(p2r_bake_strings_work); + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds +ASYNC_WORK_DEF(p2r_bake_type_nodes_work); +ASYNC_WORK_DEF(p2r_bake_name_map_work); +ASYNC_WORK_DEF(p2r_bake_idx_runs_work); + +typedef struct RDIM_HelpState RDIM_HelpState; +struct RDIM_HelpState +{ + Arena *arena; + U64 work_thread_arenas_count; + Arena **work_thread_arenas; +}; + +//////////////////////////////// + +global RDIM_HelpState *rdim_help_state = 0; + +//////////////////////////////// + +internal RDIM_HelpState * rdim_help_init(void); +internal RDIM_BakeResults rdim_bake(RDIM_HelpState *state, RDIM_BakeParams *in); +internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in); + +#endif // RDIM_MAKE_HELP diff --git a/src/rdi_make/rdi_make_local.c b/src/rdi_make/rdi_make_local.c index c1b5436c..01fa4949 100644 --- a/src/rdi_make/rdi_make_local.c +++ b/src/rdi_make/rdi_make_local.c @@ -2,3 +2,1149 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "lib_rdi_make/rdi_make.c" + +//////////////////////////////// + +internal RDIM_DataModel +rdim_infer_data_model(OperatingSystem os, RDI_Arch arch) +{ + RDIM_DataModel data_model = RDIM_DataModel_Null; +#define Case(os_name, arch_name, model_name) if(os == OperatingSystem_##os_name && arch == Arch_##arch_name) { data_model = RDIM_DataModel_##model_name; } + Case(Windows, x86, LLP64); + Case(Windows, x64, LLP64); + Case(Linux, x86, ILP32); + Case(Linux, x64, LLP64); + Case(Mac, x64, LP64); +#undef Case + return data_model; +} + +//////////////////////////////// + +internal RDIM_TopLevelInfo +rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections) +{ + // convert arch + RDI_Arch arch_rdi; + switch (arch) { + case Arch_Null: arch_rdi = RDI_Arch_NULL; break; + case Arch_x64: arch_rdi = RDI_Arch_X64; break; + case Arch_x86: arch_rdi = RDI_Arch_X86; break; + default: NotImplemented; break; + } + + + // find max VOFF + U64 exe_voff_max = 0; + for (RDIM_BinarySectionNode *sect_n = sections.first; sect_n != 0 ; sect_n = sect_n->next) { + exe_voff_max = Max(exe_voff_max, sect_n->v.voff_opl); + } + + + // fill out top level info + RDIM_TopLevelInfo top_level_info = {0}; + top_level_info.arch = arch_rdi; + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + top_level_info.producer_name = str8_lit(BUILD_TITLE_STRING_LITERAL); + + + return top_level_info; +} + +//////////////////////////////// +//~ rjf: Baking Stage Tasks + +//- rjf: bake string map building + +#define rdim_make_string_map_if_needed() do {if(in->maps[thread_idx] == 0) ProfScope("make map") {in->maps[thread_idx] = rdim_bake_string_map_loose_make(arena, in->top);}} while(0) + +ASYNC_WORK_DEF(rdim_bake_src_files_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeSrcFilesStringsIn *in = (RDIM_BakeSrcFilesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake src file strings") rdim_bake_string_map_loose_push_src_files(arena, in->top, in->maps[thread_idx], in->list); + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_units_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitsStringsIn *in = (RDIM_BakeUnitsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake unit strings") rdim_bake_string_map_loose_push_units(arena, in->top, in->maps[thread_idx], in->list); + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_types_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeTypesStringsIn *in = (RDIM_BakeTypesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake type strings") + { + for(RDIM_BakeTypesStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_type_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_udts_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeUDTsStringsIn *in = (RDIM_BakeUDTsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake udt strings") + { + for(RDIM_BakeUDTsStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_udt_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_symbols_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeSymbolsStringsIn *in = (RDIM_BakeSymbolsStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake symbol strings") + { + for(RDIM_BakeSymbolsStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_symbol_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_inline_site_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeInlineSiteStringsIn *in = input; + rdim_make_string_map_if_needed(); + ProfScope("bake inline site strings") + { + for(RDIM_BakeInlineSiteStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_inline_site_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_scopes_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopesStringsIn *in = (RDIM_BakeScopesStringsIn *)input; + rdim_make_string_map_if_needed(); + ProfScope("bake scope strings") + { + for(RDIM_BakeScopesStringsInNode *n = in->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_scope_slice(arena, in->top, in->maps[thread_idx], n->v, n->count); + } + } + ProfEnd(); + return 0; +} + +ASYNC_WORK_DEF(rdim_bake_line_tables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeLineTablesIn *in = (RDIM_BakeLineTablesIn *)input; + RDIM_LineTableBakeResult *out = push_array(arena, RDIM_LineTableBakeResult, 1); + ProfScope("bake line tables") *out = rdim_bake_line_tables(arena, in->line_tables); + ProfEnd(); + return out; +} + +#undef rdim_make_string_map_if_needed + +//- rjf: bake string map joining + +ASYNC_WORK_DEF(rdim_bake_string_map_join_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_JoinBakeStringMapSlotsIn *in = (RDIM_JoinBakeStringMapSlotsIn *)input; + ProfScope("join bake string maps") + { + for(U64 src_map_idx = 0; src_map_idx < in->src_maps_count; src_map_idx += 1) + { + for(U64 slot_idx = in->slot_idx_range.min; slot_idx < in->slot_idx_range.max; slot_idx += 1) + { + B32 src_slots_good = (in->src_maps[src_map_idx] != 0 && in->src_maps[src_map_idx]->slots != 0); + B32 dst_slot_is_zero = (in->dst_map->slots[slot_idx] == 0); + if(src_slots_good && dst_slot_is_zero) + { + in->dst_map->slots[slot_idx] = in->src_maps[src_map_idx]->slots[slot_idx]; + } + else if(src_slots_good && in->src_maps[src_map_idx]->slots[slot_idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(in->dst_map->slots[slot_idx], in->src_maps[src_map_idx]->slots[slot_idx]); + } + } + } + } + ProfEnd(); + return 0; +} + +//- rjf: bake string map sorting + +ASYNC_WORK_DEF(rdim_bake_string_map_sort_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_SortBakeStringMapSlotsIn *in = (RDIM_SortBakeStringMapSlotsIn *)input; + ProfScope("sort bake string chunk list map range") + { + for(U64 slot_idx = in->slot_idx; + slot_idx < in->slot_idx+in->slot_count; + slot_idx += 1) + { + if(in->src_map->slots[slot_idx] != 0) + { + if(in->src_map->slots[slot_idx]->total_count > 1) + { + in->dst_map->slots[slot_idx] = push_array(arena, RDIM_BakeStringChunkList, 1); + *in->dst_map->slots[slot_idx] = rdim_bake_string_chunk_list_sorted_from_unsorted(arena, in->src_map->slots[slot_idx]); + } + else + { + in->dst_map->slots[slot_idx] = in->src_map->slots[slot_idx]; + } + } + } + } + ProfEnd(); + return 0; +} + +//- rjf: pass 1: interner/deduper map builds + +ASYNC_WORK_DEF(rdim_build_bake_name_map_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BuildBakeNameMapIn *in = (RDIM_BuildBakeNameMapIn *)input; + RDIM_BakeNameMap *name_map = 0; + ProfScope("build name map %i", in->k) name_map = rdim_bake_name_map_from_kind_params(arena, in->k, in->params); + ProfEnd(); + return name_map; +} + +//- rjf: pass 2: string-map-dependent debug info stream builds + +ASYNC_WORK_DEF(rdim_bake_units_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitsIn *in = (RDIM_BakeUnitsIn *)input; + RDIM_UnitBakeResult *out = push_array(arena, RDIM_UnitBakeResult, 1); + ProfScope("bake units") *out = rdim_bake_units(arena, in->strings, in->path_tree, in->units); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_unit_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeUnitVMapIn *in = (RDIM_BakeUnitVMapIn *)input; + RDIM_UnitVMapBakeResult *out = push_array(arena, RDIM_UnitVMapBakeResult, 1); + ProfScope("bake unit vmap") *out = rdim_bake_unit_vmap(arena, in->units); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_src_files_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeSrcFilesIn *in = (RDIM_BakeSrcFilesIn *)input; + RDIM_SrcFileBakeResult *out = push_array(arena, RDIM_SrcFileBakeResult, 1); + ProfScope("bake src files") *out = rdim_bake_src_files(arena, in->strings, in->path_tree, in->src_files); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_udts_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeUDTsIn *in = (RDIM_BakeUDTsIn *)input; + RDIM_UDTBakeResult *out = push_array(arena, RDIM_UDTBakeResult, 1); + ProfScope("bake udts") *out = rdim_bake_udts(arena, in->strings, in->udts); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_global_variables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeGlobalVariablesIn *in = (RDIM_BakeGlobalVariablesIn *)input; + RDIM_GlobalVariableBakeResult *out = push_array(arena, RDIM_GlobalVariableBakeResult, 1); + ProfScope("bake global variables") *out = rdim_bake_global_variables(arena, in->strings, in->global_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_global_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeGlobalVMapIn *in = (RDIM_BakeGlobalVMapIn *)input; + RDIM_GlobalVMapBakeResult *out = push_array(arena, RDIM_GlobalVMapBakeResult, 1); + ProfScope("bake global vmap") *out = rdim_bake_global_vmap(arena, in->global_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_thread_variables_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeThreadVariablesIn *in = (RDIM_BakeThreadVariablesIn *)input; + RDIM_ThreadVariableBakeResult *out = push_array(arena, RDIM_ThreadVariableBakeResult, 1); + ProfScope("bake thread variables") *out = rdim_bake_thread_variables(arena, in->strings, in->thread_variables); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_procedures_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeProceduresIn *in = (RDIM_BakeProceduresIn *)input; + RDIM_ProcedureBakeResult *out = push_array(arena, RDIM_ProcedureBakeResult, 1); + ProfScope("bake procedures") *out = rdim_bake_procedures(arena, in->strings, in->location_blocks, in->location_data_blobs, in->procedures); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_scopes_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopesIn *in = (RDIM_BakeScopesIn *)input; + RDIM_ScopeBakeResult *out = push_array(arena, RDIM_ScopeBakeResult, 1); + ProfScope("bake scopes") *out = rdim_bake_scopes(arena, in->strings, in->location_blocks, in->location_data_blobs, in->scopes); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_scope_vmap_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeScopeVMapIn *in = (RDIM_BakeScopeVMapIn *)input; + RDIM_ScopeVMapBakeResult *out = push_array(arena, RDIM_ScopeVMapBakeResult, 1); + ProfScope("bake scope vmap") *out = rdim_bake_scope_vmap(arena, in->scopes); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_inline_sites_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeInlineSitesIn *in = (RDIM_BakeInlineSitesIn *)input; + RDIM_InlineSiteBakeResult *out = push_array(arena, RDIM_InlineSiteBakeResult, 1); + ProfScope("bake inline sites") *out = rdim_bake_inline_sites(arena, in->strings, in->inline_sites); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_file_paths_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeFilePathsIn *in = (RDIM_BakeFilePathsIn *)input; + RDIM_FilePathBakeResult *out = push_array(arena, RDIM_FilePathBakeResult, 1); + ProfScope("bake file paths") *out = rdim_bake_file_paths(arena, in->strings, in->path_tree); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_strings_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeStringsIn *in = (RDIM_BakeStringsIn *)input; + RDIM_StringBakeResult *out = push_array(arena, RDIM_StringBakeResult, 1); + ProfScope("bake strings") *out = rdim_bake_strings(arena, in->strings); + ProfEnd(); + return out; +} + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds + +ASYNC_WORK_DEF(rdim_bake_type_nodes_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeTypeNodesIn *in = (RDIM_BakeTypeNodesIn *)input; + RDIM_TypeNodeBakeResult *out = push_array(arena, RDIM_TypeNodeBakeResult, 1); + ProfScope("bake type nodes") *out = rdim_bake_types(arena, in->strings, in->idx_runs, in->types); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_name_map_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeNameMapIn *in = (RDIM_BakeNameMapIn *)input; + RDIM_NameMapBakeResult *out = push_array(arena, RDIM_NameMapBakeResult, 1); + ProfScope("bake name map %i", in->kind) *out = rdim_bake_name_map(arena, in->strings, in->idx_runs, in->map); + ProfEnd(); + return out; +} + +ASYNC_WORK_DEF(rdim_bake_idx_runs_work) +{ + ProfBeginFunction(); + Arena *arena = rdim_local_state->work_thread_arenas[thread_idx]; + RDIM_BakeIdxRunsIn *in = (RDIM_BakeIdxRunsIn *)input; + RDIM_IndexRunBakeResult *out = push_array(arena, RDIM_IndexRunBakeResult, 1); + ProfScope("bake idx runs") *out = rdim_bake_index_runs(arena, in->idx_runs); + ProfEnd(); + return out; +} + +internal U64 +rdim_local_hash(RDIM_String8 string) +{ + U64 hash = 5381; + U8 *ptr = string.str; + U8 *opl = string.str + string.size; + for (;ptr < opl; ++ptr) { + hash = ((hash << 5) + hash) + (*ptr); + } + return hash; +} + +internal void +rdim_local_resolve_incomplete_types(RDIM_TypeChunkList *types, RDIM_UDTChunkList *udts) +{ + ProfBeginFunction(); + + Temp scratch = scratch_begin(0,0); + + U64 total_type_count = types->total_count + 1; + + ProfBegin("Build Hash Table"); + RDIM_Type **name_ht = rdim_push_array(scratch.arena, RDIM_Type *, total_type_count); + for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) + { + for(RDI_U64 i = 0; i < chunk->count; i += 1) + { + RDIM_Type *type = &chunk->v[i]; + if(RDI_TypeKind_FirstUserDefined <= type->kind && type->kind <= RDI_TypeKind_LastRecord) + { + RDIM_String8 name = type->link_name.size ? type->link_name : type->name; + RDI_U64 hash = rdim_local_hash(name); + + RDI_U64 best_slot = hash % types->total_count; + RDI_U64 slot = best_slot; + do + { + RDIM_Type *s = name_ht[slot]; + if(s == 0) + { + break; + } + + if(s->link_name.size) + { + if(str8_match(s->link_name, name, 0)) + { + break; + } + } + else if(s->name.size) + { + if(str8_match(s->name, type->name, 0)) + { + break; + } + } + + slot = (slot + 1) % total_type_count; + } while (slot != best_slot); + + if(name_ht[slot] == 0) + { + name_ht[slot] = type; + } + } + } + } + ProfEnd(); + + ProfBegin("Make Fwd Map"); + RDIM_Type **fwd_map = rdim_push_array(scratch.arena, RDIM_Type *, total_type_count); + for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) + { + for(RDI_U64 i = 0; i < chunk->count; i += 1) + { + RDIM_Type *type = &chunk->v[i]; + + if(RDI_TypeKind_FirstIncomplete <= type->kind && type->kind <= RDI_TypeKind_LastIncomplete) + { + RDIM_String8 name = type->link_name.size ? type->link_name : type->name; + RDI_U64 hash = rdim_local_hash(name); + RDI_U64 best_slot = hash % types->total_count; + RDI_U64 slot = best_slot; + + RDIM_Type *match = 0; + do + { + if(name_ht[slot] == 0) + { + break; + } + RDIM_Type *s = name_ht[slot]; + if(s->link_name.size) + { + if(str8_match(s->link_name, type->link_name, 0)) + { + match = s; + break; + } + } + else + { + if(str8_match(s->name, type->name, 0)) + { + match = s; + break; + } + } + + slot = (slot + 1) % total_type_count; + } while(slot != best_slot); + + if(match) + { + type->kind = RDI_TypeKind_NULL; + + RDI_U64 type_idx = rdim_idx_from_type(type); + fwd_map[type_idx] = match; + } + } + } + } + ProfEnd(); + + ProfBegin("Resolve Types"); + for(RDIM_TypeChunkNode *chunk = types->first; chunk != 0; chunk = chunk->next) + { + for(RDI_U64 i = 0; i < chunk->count; ++i) + { + RDIM_Type *t = &chunk->v[i]; + if(t->direct_type) + { + RDI_U64 direct_idx = rdim_idx_from_type(t->direct_type); + if(fwd_map[direct_idx]) + { + t->direct_type = fwd_map[direct_idx]; + } + } + if(t->param_types) + { + for(RDI_U64 param_idx = 0; param_idx < t->count; param_idx += 1) + { + RDI_U64 type_idx = rdim_idx_from_type(t->param_types[param_idx]); + if(fwd_map[type_idx]) + { + t->param_types[param_idx] = fwd_map[type_idx]; + } + } + } + } + } + for(RDIM_UDTChunkNode *chunk = udts->first; chunk != 0; chunk = chunk->next) + { + for(RDI_U64 i = 0; i < chunk->count; ++i) + { + RDIM_UDT *udt = &chunk->v[i]; + RDI_U64 self_idx = rdim_idx_from_type(udt->self_type); + if(fwd_map[self_idx]) + { + udt->self_type = fwd_map[self_idx]; + } + + for(RDIM_UDTMember *member = udt->first_member; member != 0; member = member->next) + { + RDI_U64 member_idx = rdim_idx_from_type(member->type); + if(fwd_map[member_idx]) + { + member->type = fwd_map[member_idx]; + } + } + } + } + ProfEnd(); + + scratch_end(scratch); + ProfEnd(); +} + +internal RDIM_LocalState * +rdim_local_init(void) +{ + Arena *arena = arena_alloc(); + RDIM_LocalState *state = push_array(arena, RDIM_LocalState, 1); + state->arena = arena; + state->work_thread_arenas_count = async_thread_count(); + state->work_thread_arenas = push_array(arena, Arena *, state->work_thread_arenas_count); + for EachIndex(idx, state->work_thread_arenas_count) + { + state->work_thread_arenas[idx] = arena_alloc(); + } + return state; +} + +internal RDIM_BakeResults +rdim_bake(RDIM_LocalState *state, RDIM_BakeParams *in_params) +{ + Temp scratch = scratch_begin(0,0); + RDIM_BakeResults out = {0}; + + rdim_local_state = state; + + ////////////////////////////// + //- rjf: kick off line tables baking + // + ASYNC_Task *bake_line_tables_task = 0; + { + RDIM_BakeLineTablesIn *in = push_array(scratch.arena, RDIM_BakeLineTablesIn, 1); + in->line_tables = &in_params->line_tables; + bake_line_tables_task = async_task_launch(scratch.arena, rdim_bake_line_tables_work, .input = in); + } + + ////////////////////////////// + //- rjf: build interned path tree + // + RDIM_BakePathTree *path_tree = 0; + ProfScope("build interned path tree") + { + path_tree = rdim_bake_path_tree_from_params(state->arena, in_params); + } + + ////////////////////////////// + //- rjf: kick off string map building tasks + // + RDIM_BakeStringMapTopology bake_string_map_topology = {(64 + + in_params->procedures.total_count*1 + + in_params->global_variables.total_count*1 + + in_params->thread_variables.total_count*1 + + in_params->types.total_count/2)}; + RDIM_BakeStringMapLoose **bake_string_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringMapLoose *, async_thread_count()); + ASYNC_TaskList bake_string_map_build_tasks = {0}; + { + // rjf: src files + ProfScope("kick off src files string map build task") + { + RDIM_BakeSrcFilesStringsIn *in = push_array(scratch.arena, RDIM_BakeSrcFilesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + in->list = &in_params->src_files; + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_src_files_strings_work, .input = in)); + } + + // rjf: units + ProfScope("kick off units string map build task") + { + RDIM_BakeUnitsStringsIn *in = push_array(scratch.arena, RDIM_BakeUnitsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + in->list = &in_params->units; + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_units_strings_work, .input = in)); + } + + // rjf: types + ProfScope("kick off types string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->types.total_count+items_per_task-1)/items_per_task; + RDIM_TypeChunkNode *chunk = in_params->types.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeTypesStringsIn *in = push_array(scratch.arena, RDIM_BakeTypesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeTypesStringsInNode *n = push_array(scratch.arena, RDIM_BakeTypesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_types_strings_work, .input = in)); + } + } + + // rjf: UDTs + ProfScope("kick off udts string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->udts.total_count+items_per_task-1)/items_per_task; + RDIM_UDTChunkNode *chunk = in_params->udts.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeUDTsStringsIn *in = push_array(scratch.arena, RDIM_BakeUDTsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeUDTsStringsInNode *n = push_array(scratch.arena, RDIM_BakeUDTsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_udts_strings_work, .input = in)); + } + } + + // rjf: symbols + ProfScope("kick off symbols string map build tasks") + { + RDIM_SymbolChunkList *symbol_lists[] = + { + &in_params->global_variables, + &in_params->thread_variables, + &in_params->procedures, + }; + for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1) + { + U64 items_per_task = 4096; + U64 num_tasks = (symbol_lists[list_idx]->total_count+items_per_task-1)/items_per_task; + RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeSymbolsStringsIn *in = push_array(scratch.arena, RDIM_BakeSymbolsStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeSymbolsStringsInNode *n = push_array(scratch.arena, RDIM_BakeSymbolsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_symbols_strings_work, .input = in)); + } + } + } + + ProfScope("kick off inline site string map build task") + { + U64 items_per_task = 4096; + U64 num_tasks = CeilIntegerDiv(in_params->inline_sites.total_count, items_per_task); + RDIM_InlineSiteChunkNode *chunk = in_params->inline_sites.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeInlineSiteStringsIn *in = push_array(scratch.arena, RDIM_BakeInlineSiteStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeInlineSiteStringsInNode *n = push_array(scratch.arena, RDIM_BakeInlineSiteStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_inline_site_strings_work, .input = in)); + } + } + + // rjf: scope chunks + ProfScope("kick off scope chunks string map build tasks") + { + U64 items_per_task = 4096; + U64 num_tasks = (in_params->scopes.total_count+items_per_task-1)/items_per_task; + RDIM_ScopeChunkNode *chunk = in_params->scopes.first; + U64 chunk_off = 0; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_BakeScopesStringsIn *in = push_array(scratch.arena, RDIM_BakeScopesStringsIn, 1); + in->top = &bake_string_map_topology; + in->maps = bake_string_maps__in_progress; + U64 items_left = items_per_task; + for(;chunk != 0 && items_left > 0;) + { + U64 items_in_this_chunk = Min(items_per_task, chunk->count-chunk_off); + RDIM_BakeScopesStringsInNode *n = push_array(scratch.arena, RDIM_BakeScopesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + chunk_off; + n->count = items_in_this_chunk; + chunk_off += items_in_this_chunk; + items_left -= items_in_this_chunk; + if(chunk_off >= chunk->count) + { + chunk = chunk->next; + chunk_off = 0; + } + } + async_task_list_push(scratch.arena, &bake_string_map_build_tasks, async_task_launch(scratch.arena, rdim_bake_scopes_strings_work, .input = in)); + } + } + } + + ////////////////////////////// + //- rjf: kick off name map building tasks + // + RDIM_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0}; + ASYNC_Task *build_bake_name_map_task[RDI_NameMapKind_COUNT] = {0}; + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + build_bake_name_map_in[k].k = k; + build_bake_name_map_in[k].params = in_params; + build_bake_name_map_task[k] = async_task_launch(scratch.arena, rdim_build_bake_name_map_work, .input = &build_bake_name_map_in[k]); + } + + ////////////////////////////// + //- rjf: join string map building tasks + // + ProfScope("join string map building tasks") + { + for(ASYNC_TaskNode *n = bake_string_map_build_tasks.first; n != 0; n = n->next) + { + async_task_join(n->v); + } + } + + ////////////////////////////// + //- rjf: produce joined string map + // + RDIM_BakeStringMapLoose *unsorted_bake_string_map = rdim_bake_string_map_loose_make(state->arena, &bake_string_map_topology); + ProfScope("produce joined string map") + { + U64 slots_per_task = 16384; + U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; + ASYNC_Task **tasks = push_array(scratch.arena, ASYNC_Task *, num_tasks); + + // rjf: kickoff tasks + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_JoinBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_JoinBakeStringMapSlotsIn, 1); + in->top = &bake_string_map_topology; + in->src_maps = bake_string_maps__in_progress; + in->src_maps_count = async_thread_count(); + in->dst_map = unsorted_bake_string_map; + in->slot_idx_range = r1u64(task_idx*slots_per_task, task_idx*slots_per_task + slots_per_task); + in->slot_idx_range.max = Min(in->slot_idx_range.max, in->top->slots_count); + tasks[task_idx] = async_task_launch(scratch.arena, rdim_bake_string_map_join_work, .input = in); + } + + // rjf: join tasks + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + async_task_join(tasks[task_idx]); + } + + // rjf: insert small top-level stuff + rdim_bake_string_map_loose_push_top_level_info(state->arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(state->arena, &bake_string_map_topology, unsorted_bake_string_map, &in_params->binary_sections); + rdim_bake_string_map_loose_push_path_tree(state->arena, &bake_string_map_topology, unsorted_bake_string_map, path_tree); + } + + ////////////////////////////// + //- rjf: kick off string map sorting tasks + // + ASYNC_TaskList sort_bake_string_map_tasks = {0}; + RDIM_BakeStringMapLoose *sorted_bake_string_map__in_progress = rdim_bake_string_map_loose_make(state->arena, &bake_string_map_topology); + { + U64 slots_per_task = 4096; + U64 num_tasks = (bake_string_map_topology.slots_count+slots_per_task-1)/slots_per_task; + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + RDIM_SortBakeStringMapSlotsIn *in = push_array(scratch.arena, RDIM_SortBakeStringMapSlotsIn, 1); + { + in->top = &bake_string_map_topology; + in->src_map = unsorted_bake_string_map; + in->dst_map = sorted_bake_string_map__in_progress; + in->slot_idx = task_idx*slots_per_task; + in->slot_count = slots_per_task; + if(in->slot_idx+in->slot_count > bake_string_map_topology.slots_count) + { + in->slot_count = bake_string_map_topology.slots_count - in->slot_idx; + } + } + async_task_list_push(scratch.arena, &sort_bake_string_map_tasks, async_task_launch(scratch.arena, rdim_bake_string_map_sort_work, .input = in)); + } + } + + ////////////////////////////// + //- rjf: join string map sorting tasks + // + ProfScope("join string map sorting tasks") + { + for(ASYNC_TaskNode *n = sort_bake_string_map_tasks.first; n != 0; n = n->next) + { + async_task_join(n->v); + } + } + RDIM_BakeStringMapLoose *sorted_bake_string_map = sorted_bake_string_map__in_progress; + + ////////////////////////////// + //- rjf: build finalized string map + // + ProfBegin("build finalized string map base indices"); + RDIM_BakeStringMapBaseIndices bake_string_map_base_idxes = rdim_bake_string_map_base_indices_from_map_loose(state->arena, &bake_string_map_topology, sorted_bake_string_map); + ProfEnd(); + ProfBegin("build finalized string map"); + RDIM_BakeStringMapTight bake_strings = rdim_bake_string_map_tight_from_loose(state->arena, &bake_string_map_topology, &bake_string_map_base_idxes, sorted_bake_string_map); + ProfEnd(); + + ////////////////////////////// + //- rjf: kick off pass 2 tasks + // + RDIM_BakeUnitsIn bake_units_top_level_in = {&bake_strings, path_tree, &in_params->units}; + ASYNC_Task *bake_units_task = async_task_launch(scratch.arena, rdim_bake_units_work, .input = &bake_units_top_level_in); + RDIM_BakeUnitVMapIn bake_unit_vmap_in = {&in_params->units}; + ASYNC_Task *bake_unit_vmap_task = async_task_launch(scratch.arena, rdim_bake_unit_vmap_work, .input = &bake_unit_vmap_in); + RDIM_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, &in_params->src_files}; + ASYNC_Task *bake_src_files_task = async_task_launch(scratch.arena, rdim_bake_src_files_work, .input = &bake_src_files_in); + RDIM_BakeUDTsIn bake_udts_in = {&bake_strings, &in_params->udts}; + ASYNC_Task *bake_udts_task = async_task_launch(scratch.arena, rdim_bake_udts_work, .input = &bake_udts_in); + RDIM_BakeGlobalVMapIn bake_global_vmap_in = {&in_params->global_variables}; + ASYNC_Task *bake_global_vmap_task = async_task_launch(scratch.arena, rdim_bake_global_vmap_work, .input = &bake_global_vmap_in); + RDIM_BakeScopeVMapIn bake_scope_vmap_in = {&in_params->scopes}; + ASYNC_Task *bake_scope_vmap_task = async_task_launch(scratch.arena, rdim_bake_scope_vmap_work, .input = &bake_scope_vmap_in); + RDIM_BakeInlineSitesIn bake_inline_sites_in = {&bake_strings, &in_params->inline_sites}; + ASYNC_Task *bake_inline_sites_task = async_task_launch(scratch.arena, rdim_bake_inline_sites_work, .input = &bake_inline_sites_in); + RDIM_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; + ASYNC_Task *bake_file_paths_task = async_task_launch(scratch.arena, rdim_bake_file_paths_work, .input = &bake_file_paths_in); + RDIM_BakeStringsIn bake_strings_in = {&bake_strings}; + ASYNC_Task *bake_strings_task = async_task_launch(scratch.arena, rdim_bake_strings_work, .input = &bake_strings_in); + + RDIM_String8List location_blocks = {0}; + RDIM_String8List location_data_blobs = {0}; + + // reserve null location block for opl + rdim_location_block_chunk_list_push_array(state->arena, &location_blocks, 1); + + // TODO: export location instead of VOFF + RDIM_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, &in_params->thread_variables}; + ASYNC_Task *bake_thread_variables_task = async_task_launch(scratch.arena, rdim_bake_thread_variables_work, .input = &bake_thread_variables_in); + ProfScope("thread variables") out.thread_variables = *async_task_join_struct(bake_thread_variables_task, RDIM_ThreadVariableBakeResult); + + // TODO: export location instead of VOFF + RDIM_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, &in_params->global_variables}; + ASYNC_Task *bake_global_variables_task = async_task_launch(scratch.arena, rdim_bake_global_variables_work, .input = &bake_global_variables_in); + ProfScope("global variables") out.global_variables = *async_task_join_struct(bake_global_variables_task, RDIM_GlobalVariableBakeResult); + + RDIM_BakeScopesIn bake_scopes_in = {&bake_strings, &in_params->scopes, &location_blocks, &location_data_blobs}; + ASYNC_Task *bake_scopes_task = async_task_launch(scratch.arena, rdim_bake_scopes_work, .input = &bake_scopes_in); + ProfScope("scopes") out.scopes = *async_task_join_struct(bake_scopes_task, RDIM_ScopeBakeResult); + + RDIM_BakeProceduresIn bake_procedures_in = {&bake_strings, &in_params->procedures, &location_blocks, &location_data_blobs}; + ASYNC_Task *bake_procedures_task = async_task_launch(scratch.arena, rdim_bake_procedures_work, .input = &bake_procedures_in); + ProfScope("procedures") out.procedures = *async_task_join_struct(bake_procedures_task, RDIM_ProcedureBakeResult); + + ////////////////////////////// + //- rjf: join name map building tasks + // + RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT] = {0}; + ProfScope("join name map building tasks") + { + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + name_maps[k] = async_task_join_struct(build_bake_name_map_task[k], RDIM_BakeNameMap); + } + } + + ////////////////////////////// + //- rjf: build interned idx run map + // + RDIM_BakeIdxRunMap *idx_runs = 0; + ProfScope("build interned idx run map") + { + idx_runs = rdim_bake_idx_run_map_from_params(state->arena, name_maps, in_params); + } + + ////////////////////////////// + //- rjf: do small top-level bakes + // + ProfScope("top level info") out.top_level_info = rdim_bake_top_level_info(state->arena, &bake_strings, &in_params->top_level_info); + ProfScope("binary sections") out.binary_sections = rdim_bake_binary_sections(state->arena, &bake_strings, &in_params->binary_sections); + ProfScope("top level name maps section") out.top_level_name_maps = rdim_bake_name_maps_top_level(state->arena, &bake_strings, idx_runs, name_maps); + + ////////////////////////////// + //- rjf: kick off pass 3 tasks + // + RDIM_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, &in_params->types}; + ASYNC_Task *bake_type_nodes_task = async_task_launch(scratch.arena, rdim_bake_type_nodes_work, .input = &bake_type_nodes_in); + ASYNC_Task *bake_name_maps_tasks[RDI_NameMapKind_COUNT] = {0}; + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + if(name_maps[k] == 0 || name_maps[k]->name_count == 0) + { + continue; + } + RDIM_BakeNameMapIn *in = push_array(scratch.arena, RDIM_BakeNameMapIn, 1); + in->strings = &bake_strings; + in->idx_runs = idx_runs; + in->map = name_maps[k]; + in->kind = k; + bake_name_maps_tasks[k] = async_task_launch(scratch.arena, rdim_bake_name_map_work, .input = in); + } + } + RDIM_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; + ASYNC_Task *bake_idx_runs_task = async_task_launch(scratch.arena, rdim_bake_idx_runs_work, .input = &bake_idx_runs_in); + + ////////////////////////////// + //- rjf: join remaining completed bakes + // + ProfScope("top-level units info") out.units = *async_task_join_struct(bake_units_task, RDIM_UnitBakeResult); + ProfScope("unit vmap") out.unit_vmap = *async_task_join_struct(bake_unit_vmap_task, RDIM_UnitVMapBakeResult); + ProfScope("source files") out.src_files = *async_task_join_struct(bake_src_files_task, RDIM_SrcFileBakeResult); + ProfScope("UDTs") out.udts = *async_task_join_struct(bake_udts_task, RDIM_UDTBakeResult); + ProfScope("global vmap") out.global_vmap = *async_task_join_struct(bake_global_vmap_task, RDIM_GlobalVMapBakeResult); + ProfScope("scope vmap") out.scope_vmap = *async_task_join_struct(bake_scope_vmap_task, RDIM_ScopeVMapBakeResult); + ProfScope("inline sites") out.inline_sites = *async_task_join_struct(bake_inline_sites_task, RDIM_InlineSiteBakeResult); + ProfScope("file paths") out.file_paths = *async_task_join_struct(bake_file_paths_task, RDIM_FilePathBakeResult); + ProfScope("strings") out.strings = *async_task_join_struct(bake_strings_task, RDIM_StringBakeResult); + ProfScope("type nodes") out.type_nodes = *async_task_join_struct(bake_type_nodes_task, RDIM_TypeNodeBakeResult); + ProfScope("idx runs") out.idx_runs = *async_task_join_struct(bake_idx_runs_task, RDIM_IndexRunBakeResult); + ProfScope("line tables") out.line_tables = *async_task_join_struct(bake_line_tables_task, RDIM_LineTableBakeResult); + + ////////////////////////////// + //- rjf: join individual name map bakes + // + RDIM_NameMapBakeResult name_map_bakes[RDI_NameMapKind_COUNT] = {0}; + ProfScope("name maps") + { + for EachNonZeroEnumVal(RDI_NameMapKind, k) + { + RDIM_NameMapBakeResult *bake = async_task_join_struct(bake_name_maps_tasks[k], RDIM_NameMapBakeResult); + if(bake != 0) + { + name_map_bakes[k] = *bake; + } + } + } + + ////////////////////////////// + //- rjf: join all individual name map bakes + // + ProfScope("join all name map bakes into final name map bake") + { + out.name_maps = rdim_name_map_bake_results_combine(state->arena, name_map_bakes, ArrayCount(name_map_bakes)); + } + + + //////////////////////////////// + + out.location_blocks = rdim_str8_list_join(state->arena, &location_blocks, rdim_str8(0,0)); + out.location_data = rdim_str8_list_join(state->arena, &location_data_blobs, rdim_str8(0,0)); + + rdim_local_state = 0; + + scratch_end(scratch); + return out; +} + +internal RDIM_SerializedSectionBundle +rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in) +{ + RDIM_SerializedSectionBundle out = {0}; + + //- rjf: set up compression context + rr_lzb_simple_context ctx = {0}; + ctx.m_tableSizeBits = 14; + ctx.m_hashTable = push_array(arena, U16, 1<sections[k]; + RDIM_SerializedSection *dst = &out.sections[k]; + MemoryCopyStruct(dst, src); + + // rjf: determine if this section should be compressed + B32 should_compress = 1; + + // rjf: compress if needed + if(should_compress) + { + MemoryZero(ctx.m_hashTable, sizeof(U16)*(1<data = push_array_no_zero(arena, U8, src->encoded_size); + dst->encoded_size = rr_lzb_simple_encode_veryfast(&ctx, src->data, src->encoded_size, dst->data); + dst->unpacked_size = src->encoded_size; + dst->encoding = RDI_SectionEncoding_LZB; + } + } + + return out; +} + diff --git a/src/rdi_make/rdi_make_local.h b/src/rdi_make/rdi_make_local.h index 46a11b16..5dc7ec6b 100644 --- a/src/rdi_make/rdi_make_local.h +++ b/src/rdi_make/rdi_make_local.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RDI_CONS_LOCAL_H -#define RDI_CONS_LOCAL_H +#ifndef RDI_MAKE_LOCAL_H +#define RDI_MAKE_LOCAL_H // rjf: base layer memory ops #define RDIM_MEMSET_OVERRIDE @@ -12,16 +12,16 @@ // rjf: base layer string overrides #define RDI_STRING8_OVERRIDE -#define RDIM_String8 String8 +#define RDIM_String8 String8 #define RDIM_String8_BaseMember str #define RDIM_String8_SizeMember size #define RDI_STRING8LIST_OVERRIDE -#define RDIM_String8Node String8Node -#define RDIM_String8Node_NextPtrMember next -#define RDIM_String8Node_StringMember string -#define RDIM_String8List String8List -#define RDIM_String8List_FirstMember first -#define RDIM_String8List_LastMember last +#define RDIM_String8Node String8Node +#define RDIM_String8Node_NextPtrMember next +#define RDIM_String8Node_StringMember string +#define RDIM_String8List String8List +#define RDIM_String8List_FirstMember first +#define RDIM_String8List_LastMember last #define RDIM_String8List_NodeCountMember node_count #define RDIM_String8List_TotalSizeMember total_size @@ -47,4 +47,342 @@ #include "lib_rdi_make/rdi_make.h" -#endif // RDI_CONS_LOCAL_H +//////////////////////////////// + +//- rjf: line table baking task types + +typedef struct RDIM_BakeLineTablesIn RDIM_BakeLineTablesIn; +struct RDIM_BakeLineTablesIn +{ + RDIM_LineTableChunkList *line_tables; +}; + +//- rjf: string map baking task types + +typedef struct RDIM_BakeSrcFilesStringsIn RDIM_BakeSrcFilesStringsIn; +struct RDIM_BakeSrcFilesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_SrcFileChunkList *list; +}; + +typedef struct RDIM_BakeUnitsStringsIn RDIM_BakeUnitsStringsIn; +struct RDIM_BakeUnitsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_UnitChunkList *list; +}; + +typedef struct RDIM_BakeUDTsStringsInNode RDIM_BakeUDTsStringsInNode; +struct RDIM_BakeUDTsStringsInNode +{ + RDIM_BakeUDTsStringsInNode *next; + RDIM_UDT *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeTypesStringsInNode RDIM_BakeTypesStringsInNode; +struct RDIM_BakeTypesStringsInNode +{ + RDIM_BakeTypesStringsInNode *next; + RDIM_Type *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeTypesStringsIn RDIM_BakeTypesStringsIn; +struct RDIM_BakeTypesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeTypesStringsInNode *first; + RDIM_BakeTypesStringsInNode *last; +}; + +typedef struct RDIM_BakeUDTsStringsIn RDIM_BakeUDTsStringsIn; +struct RDIM_BakeUDTsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeUDTsStringsInNode *first; + RDIM_BakeUDTsStringsInNode *last; +}; + +typedef struct RDIM_BakeSymbolsStringsInNode RDIM_BakeSymbolsStringsInNode; +struct RDIM_BakeSymbolsStringsInNode +{ + RDIM_BakeSymbolsStringsInNode *next; + RDIM_Symbol *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeSymbolsStringsIn RDIM_BakeSymbolsStringsIn; +struct RDIM_BakeSymbolsStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeSymbolsStringsInNode *first; + RDIM_BakeSymbolsStringsInNode *last; +}; + +typedef struct RDIM_BakeInlineSiteStringsInNode RDIM_BakeInlineSiteStringsInNode; +struct RDIM_BakeInlineSiteStringsInNode +{ + RDIM_BakeInlineSiteStringsInNode *next; + RDIM_InlineSite *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeInlineSiteStringsIn RDIM_BakeInlineSiteStringsIn; +struct RDIM_BakeInlineSiteStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeInlineSiteStringsInNode *first; + RDIM_BakeInlineSiteStringsInNode *last; +}; + +typedef struct RDIM_BakeScopesStringsInNode RDIM_BakeScopesStringsInNode; +struct RDIM_BakeScopesStringsInNode +{ + RDIM_BakeScopesStringsInNode *next; + RDIM_Scope *v; + RDI_U64 count; +}; + +typedef struct RDIM_BakeScopesStringsIn RDIM_BakeScopesStringsIn; +struct RDIM_BakeScopesStringsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **maps; + RDIM_BakeScopesStringsInNode *first; + RDIM_BakeScopesStringsInNode *last; +}; + +//- rjf: OLD string map baking types + +typedef struct RDIM_BuildBakeStringMapIn RDIM_BuildBakeStringMapIn; +struct RDIM_BuildBakeStringMapIn +{ + RDIM_BakePathTree *path_tree; + RDIM_BakeParams *params; +}; + +typedef struct RDIM_BuildBakeNameMapIn RDIM_BuildBakeNameMapIn; +struct RDIM_BuildBakeNameMapIn +{ + RDI_NameMapKind k; + RDIM_BakeParams *params; +}; + +//- rjf: string map joining task types + +typedef struct RDIM_JoinBakeStringMapSlotsIn RDIM_JoinBakeStringMapSlotsIn; +struct RDIM_JoinBakeStringMapSlotsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose **src_maps; + U64 src_maps_count; + RDIM_BakeStringMapLoose *dst_map; + Rng1U64 slot_idx_range; +}; + +//- rjf: string map sorting task types + +typedef struct RDIM_SortBakeStringMapSlotsIn RDIM_SortBakeStringMapSlotsIn; +struct RDIM_SortBakeStringMapSlotsIn +{ + RDIM_BakeStringMapTopology *top; + RDIM_BakeStringMapLoose *src_map; + RDIM_BakeStringMapLoose *dst_map; + U64 slot_idx; + U64 slot_count; +}; + +//- rjf: debug info baking task types + +typedef struct RDIM_BakeUnitsIn RDIM_BakeUnitsIn; +struct RDIM_BakeUnitsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_UnitChunkList *units; +}; + +typedef struct RDIM_BakeUnitVMapIn RDIM_BakeUnitVMapIn; +struct RDIM_BakeUnitVMapIn +{ + RDIM_UnitChunkList *units; +}; + +typedef struct RDIM_BakeSrcFilesIn RDIM_BakeSrcFilesIn; +struct RDIM_BakeSrcFilesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_SrcFileChunkList *src_files; +}; + +typedef struct RDIM_BakeUDTsIn RDIM_BakeUDTsIn; +struct RDIM_BakeUDTsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_UDTChunkList *udts; +}; + +typedef struct RDIM_BakeGlobalVariablesIn RDIM_BakeGlobalVariablesIn; +struct RDIM_BakeGlobalVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *global_variables; +}; + +typedef struct RDIM_BakeGlobalVMapIn RDIM_BakeGlobalVMapIn; +struct RDIM_BakeGlobalVMapIn +{ + RDIM_SymbolChunkList *global_variables; +}; + +typedef struct RDIM_BakeThreadVariablesIn RDIM_BakeThreadVariablesIn; +struct RDIM_BakeThreadVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *thread_variables; +}; + +typedef struct RDIM_BakeProceduresIn RDIM_BakeProceduresIn; +struct RDIM_BakeProceduresIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_SymbolChunkList *procedures; + RDIM_String8List *location_blocks; + RDIM_String8List *location_data_blobs; +}; + +typedef struct RDIM_BakeScopesIn RDIM_BakeScopesIn; +struct RDIM_BakeScopesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_ScopeChunkList *scopes; + RDIM_String8List *location_blocks; + RDIM_String8List *location_data_blobs; +}; + +typedef struct RDIM_BakeScopeVMapIn RDIM_BakeScopeVMapIn; +struct RDIM_BakeScopeVMapIn +{ + RDIM_ScopeChunkList *scopes; +}; + +typedef struct RDIM_BakeInlineSitesIn RDIM_BakeInlineSitesIn; +struct RDIM_BakeInlineSitesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_InlineSiteChunkList *inline_sites; +}; + +typedef struct RDIM_BakeFilePathsIn RDIM_BakeFilePathsIn; +struct RDIM_BakeFilePathsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; +}; + +typedef struct RDIM_BakeStringsIn RDIM_BakeStringsIn; +struct RDIM_BakeStringsIn +{ + RDIM_BakeStringMapTight *strings; +}; + +typedef struct RDIM_BakeTypeNodesIn RDIM_BakeTypeNodesIn; +struct RDIM_BakeTypeNodesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeIdxRunMap *idx_runs; + RDIM_TypeChunkList *types; +}; + +typedef struct RDIM_BakeNameMapIn RDIM_BakeNameMapIn; +struct RDIM_BakeNameMapIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeIdxRunMap *idx_runs; + RDIM_BakeNameMap *map; + RDI_NameMapKind kind; +}; + +typedef struct RDIM_BakeIdxRunsIn RDIM_BakeIdxRunsIn; +struct RDIM_BakeIdxRunsIn +{ + RDIM_BakeIdxRunMap *idx_runs; +}; + +//////////////////////////////// + +internal RDIM_DataModel rdim_infer_data_model(OperatingSystem os, RDI_Arch arch); + +//////////////////////////////// +//~ rjf: Baking Stage Tasks + +//- rjf: unsorted bake string map building +ASYNC_WORK_DEF(rdim_bake_src_files_strings_work); +ASYNC_WORK_DEF(rdim_bake_units_strings_work); +ASYNC_WORK_DEF(rdim_bake_types_strings_work); +ASYNC_WORK_DEF(rdim_bake_udts_strings_work); +ASYNC_WORK_DEF(rdim_bake_symbols_strings_work); +ASYNC_WORK_DEF(rdim_bake_scopes_strings_work); +ASYNC_WORK_DEF(rdim_bake_line_tables_work); + +//- rjf: bake string map joining +ASYNC_WORK_DEF(rdim_bake_string_map_join_work); + +//- rjf: bake string map sorting +ASYNC_WORK_DEF(rdim_bake_string_map_sort_work); + +//- rjf: pass 1: interner/deduper map builds +ASYNC_WORK_DEF(rdim_build_bake_name_map_work); + +//- rjf: pass 2: string-map-dependent debug info stream builds +ASYNC_WORK_DEF(rdim_bake_units_work); +ASYNC_WORK_DEF(rdim_bake_unit_vmap_work); +ASYNC_WORK_DEF(rdim_bake_src_files_work); +ASYNC_WORK_DEF(rdim_bake_udts_work); +ASYNC_WORK_DEF(rdim_bake_global_variables_work); +ASYNC_WORK_DEF(rdim_bake_global_vmap_work); +ASYNC_WORK_DEF(rdim_bake_thread_variables_work); +ASYNC_WORK_DEF(rdim_bake_procedures_work); +ASYNC_WORK_DEF(rdim_bake_scopes_work); +ASYNC_WORK_DEF(rdim_bake_scope_vmap_work); +ASYNC_WORK_DEF(rdim_bake_file_paths_work); +ASYNC_WORK_DEF(rdim_bake_strings_work); + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds +ASYNC_WORK_DEF(rdim_bake_type_nodes_work); +ASYNC_WORK_DEF(rdim_bake_name_map_work); +ASYNC_WORK_DEF(rdim_bake_idx_runs_work); + +typedef struct RDIM_LocalState RDIM_LocalState; +struct RDIM_LocalState +{ + Arena *arena; + U64 work_thread_arenas_count; + Arena **work_thread_arenas; +}; + +//////////////////////////////// + +global RDIM_LocalState *rdim_local_state = 0; + +//////////////////////////////// + +internal RDIM_DataModel rdim_infer_data_model(OperatingSystem os, RDI_Arch arch); +internal RDIM_TopLevelInfo rdim_make_top_level_info(String8 image_name, Arch arch, U64 exe_hash, RDIM_BinarySectionList sections); + +//////////////////////////////// + +internal RDIM_LocalState * rdim_local_init(void); +internal RDIM_BakeResults rdim_bake(RDIM_LocalState *state, RDIM_BakeParams *in); +internal RDIM_SerializedSectionBundle rdim_compress(Arena *arena, RDIM_SerializedSectionBundle *in); + +#endif // RDI_MAKE_LOCAL_H diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index c7f9f538..1f9f4b10 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -536,14 +536,14 @@ REGS_Rng regs_g_reg_code_x64_rng_table[101] = {(U16)OffsetOf(REGS_RegBlockX64, gsbase), 8}, {(U16)OffsetOf(REGS_RegBlockX64, rip), 8}, {(U16)OffsetOf(REGS_RegBlockX64, rflags), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, dr0), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr1), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr2), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr3), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr4), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr5), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr6), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, dr7), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, dr0), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr1), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr2), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr3), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr4), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr5), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr6), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, dr7), 8}, {(U16)OffsetOf(REGS_RegBlockX64, fpr0), 10}, {(U16)OffsetOf(REGS_RegBlockX64, fpr1), 10}, {(U16)OffsetOf(REGS_RegBlockX64, fpr2), 10}, diff --git a/src/regs/generated/regs.meta.h b/src/regs/generated/regs.meta.h index c2abaac9..f3cdf807 100644 --- a/src/regs/generated/regs.meta.h +++ b/src/regs/generated/regs.meta.h @@ -343,14 +343,14 @@ REGS_Reg64 fsbase; REGS_Reg64 gsbase; REGS_Reg64 rip; REGS_Reg64 rflags; -REGS_Reg32 dr0; -REGS_Reg32 dr1; -REGS_Reg32 dr2; -REGS_Reg32 dr3; -REGS_Reg32 dr4; -REGS_Reg32 dr5; -REGS_Reg32 dr6; -REGS_Reg32 dr7; +REGS_Reg64 dr0; +REGS_Reg64 dr1; +REGS_Reg64 dr2; +REGS_Reg64 dr3; +REGS_Reg64 dr4; +REGS_Reg64 dr5; +REGS_Reg64 dr6; +REGS_Reg64 dr7; REGS_Reg80 fpr0; REGS_Reg80 fpr1; REGS_Reg80 fpr2; diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 2f68c43e..5e4ae872 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -27,14 +27,14 @@ REGS_RegTableX64: {gsbase 64 Normal} {rip 64 Normal} {rflags 64 Normal} - {dr0 32 Normal} - {dr1 32 Normal} - {dr2 32 Normal} - {dr3 32 Normal} - {dr4 32 Normal} - {dr5 32 Normal} - {dr6 32 Normal} - {dr7 32 Normal} + {dr0 64 Normal} + {dr1 64 Normal} + {dr2 64 Normal} + {dr3 64 Normal} + {dr4 64 Normal} + {dr5 64 Normal} + {dr6 64 Normal} + {dr7 64 Normal} {fpr0 80 Normal} {fpr1 80 Normal} {fpr2 80 Normal} diff --git a/src/render/d3d11/generated/render_d3d11.meta.h b/src/render/d3d11/generated/render_d3d11.meta.h index 1031599d..6fd7f833 100644 --- a/src/render/d3d11/generated/render_d3d11.meta.h +++ b/src/render/d3d11/generated/render_d3d11.meta.h @@ -83,6 +83,20 @@ str8_lit_comp( " return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n" "}\n" "\n" +"float linear_from_srgb_f32(float x)\n" +"{\n" +" return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4);\n" +"}\n" +"\n" +"float4 linear_from_srgba(float4 v)\n" +"{\n" +" float4 result = float4(linear_from_srgb_f32(v.x),\n" +" linear_from_srgb_f32(v.y),\n" +" linear_from_srgb_f32(v.z),\n" +" v.w);\n" +" return result;\n" +"}\n" +"\n" "//- rjf: vertex shader\n" "\n" "Vertex2Pixel\n" @@ -122,7 +136,8 @@ str8_lit_comp( " cpu2vertex.corner_radii_px.w,\n" " cpu2vertex.corner_radii_px.z,\n" " };\n" -" float4 src_color[] = {\n" +" float4 src_color[] =\n" +" {\n" " cpu2vertex.color01,\n" " cpu2vertex.color00,\n" " cpu2vertex.color11,\n" @@ -164,6 +179,7 @@ str8_lit_comp( " if(vertex2pixel.omit_texture < 1)\n" " {\n" " albedo_sample = mul(main_t2d.Sample(main_sampler, vertex2pixel.texcoord_pct), texture_sample_channel_map);\n" +" albedo_sample = linear_from_srgba(albedo_sample);\n" " }\n" " \n" " // rjf: determine SDF sample position\n" @@ -263,8 +279,7 @@ str8_lit_comp( " corner_radii_px.w,\n" " corner_radii_px.z,\n" " };\n" -" float2 cornercoords__pct = float2(\n" -" (c2v.vertex_id >> 1) ? 1.f : 0.f,\n" +" float2 cornercoords__pct = float2((c2v.vertex_id >> 1) ? 1.f : 0.f,\n" " (c2v.vertex_id & 1) ? 0.f : 1.f);\n" " \n" " float2 vertex_position__pct = vertex_positions__scrn[c2v.vertex_id] / viewport_size;\n" diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c index 84ac64a7..dca4586c 100644 --- a/src/render/d3d11/render_d3d11.c +++ b/src/render/d3d11/render_d3d11.c @@ -1,9 +1,6 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.80f, 0.60f, 0.20f - //////////////////////////////// //~ rjf: Input Layout Element Tables @@ -520,7 +517,7 @@ r_window_equip(OS_Handle handle) { swapchain_desc.Width = 0; // NOTE(rjf): use window width swapchain_desc.Height = 0; // NOTE(rjf): use window height - swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + swapchain_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; swapchain_desc.Stereo = FALSE; swapchain_desc.SampleDesc.Count = 1; swapchain_desc.SampleDesc.Quality = 0; @@ -673,7 +670,10 @@ r_tex2d_release(R_Handle handle) OS_MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); - SLLStackPush(r_d3d11_state->first_to_free_tex2d, texture); + if(texture != &r_d3d11_tex2d_nil) + { + SLLStackPush(r_d3d11_state->first_to_free_tex2d, texture); + } } ProfEnd(); } @@ -706,15 +706,18 @@ r_fill_tex2d_region(R_Handle handle, Rng2S32 subrect, void *data) OS_MutexScopeW(r_d3d11_state->device_rw_mutex) { R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(handle); - Assert(texture->kind == R_ResourceKind_Dynamic && "only dynamic texture can update region"); - U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[texture->format]; - Vec2S32 dim = v2s32(subrect.x1 - subrect.x0, subrect.y1 - subrect.y0); - D3D11_BOX dst_box = + if(texture != &r_d3d11_tex2d_nil) { - (UINT)subrect.x0, (UINT)subrect.y0, 0, - (UINT)subrect.x1, (UINT)subrect.y1, 1, - }; - r_d3d11_state->device_ctx->lpVtbl->UpdateSubresource(r_d3d11_state->device_ctx, (ID3D11Resource *)texture->texture, 0, &dst_box, data, dim.x*bytes_per_pixel, 0); + Assert(texture->kind == R_ResourceKind_Dynamic && "only dynamic texture can update region"); + U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[texture->format]; + Vec2S32 dim = v2s32(subrect.x1 - subrect.x0, subrect.y1 - subrect.y0); + D3D11_BOX dst_box = + { + (UINT)subrect.x0, (UINT)subrect.y0, 0, + (UINT)subrect.x1, (UINT)subrect.y1, 1, + }; + r_d3d11_state->device_ctx->lpVtbl->UpdateSubresource(r_d3d11_state->device_ctx, (ID3D11Resource *)texture->texture, 0, &dst_box, data, dim.x*bytes_per_pixel, 0); + } } ProfEnd(); } @@ -822,6 +825,8 @@ r_end_frame(void) next = tex->next; tex->view->lpVtbl->Release(tex->view); tex->texture->lpVtbl->Release(tex->texture); + tex->view = 0; + tex->texture = 0; tex->generation += 1; SLLStackPush(r_d3d11_state->first_free_tex2d, tex); } @@ -888,7 +893,7 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) D3D11_TEXTURE2D_DESC color_desc = zero_struct; { wnd->framebuffer->lpVtbl->GetDesc(wnd->framebuffer, &color_desc); - color_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + color_desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; color_desc.BindFlags = D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE; } D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = zero_struct; @@ -898,7 +903,7 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) } D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = zero_struct; { - srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srv_desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srv_desc.Texture2D.MipLevels = -1; } @@ -1114,29 +1119,14 @@ r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes) R_D3D11_Tex2D *texture = r_d3d11_tex2d_from_handle(texture_handle); // rjf: get texture sample map matrix, based on format - Vec4F32 texture_sample_channel_map[] = - { - {1, 0, 0, 0}, - {0, 1, 0, 0}, - {0, 0, 1, 0}, - {0, 0, 0, 1}, - }; - switch(texture->format) - { - default: break; - case R_Tex2DFormat_R8: - { - MemoryZeroArray(texture_sample_channel_map); - texture_sample_channel_map[0] = v4f32(1, 1, 1, 1); - }break; - } + Mat4x4F32 texture_sample_channel_map = r_sample_channel_map_from_tex2dformat(texture->format); // rjf: upload uniforms R_D3D11_Uniforms_Rect uniforms = {0}; { uniforms.viewport_size = v2f32(resolution.x, resolution.y); uniforms.opacity = 1-group_params->transparency; - MemoryCopyArray(uniforms.texture_sample_channel_map, texture_sample_channel_map); + uniforms.texture_sample_channel_map = texture_sample_channel_map; uniforms.texture_t2d_size = v2f32(texture->size.x, texture->size.y); uniforms.xform[0] = v4f32(group_params->xform.v[0][0], group_params->xform.v[1][0], group_params->xform.v[2][0], 0); uniforms.xform[1] = v4f32(group_params->xform.v[0][1], group_params->xform.v[1][1], group_params->xform.v[2][1], 0); diff --git a/src/render/d3d11/render_d3d11.h b/src/render/d3d11/render_d3d11.h index 5bdec2ab..b1b0d5fd 100644 --- a/src/render/d3d11/render_d3d11.h +++ b/src/render/d3d11/render_d3d11.h @@ -29,7 +29,7 @@ struct R_D3D11_Uniforms_Rect Vec2F32 viewport_size; F32 opacity; F32 _padding0_; - Vec4F32 texture_sample_channel_map[4]; + Mat4x4F32 texture_sample_channel_map; Vec2F32 texture_t2d_size; Vec2F32 translate; Vec4F32 xform[3]; @@ -171,9 +171,9 @@ struct R_D3D11_State //~ rjf: Globals global R_D3D11_State *r_d3d11_state = 0; -global R_D3D11_Window r_d3d11_window_nil = {&r_d3d11_window_nil}; -global R_D3D11_Tex2D r_d3d11_tex2d_nil = {&r_d3d11_tex2d_nil}; -global R_D3D11_Buffer r_d3d11_buffer_nil = {&r_d3d11_buffer_nil}; +global read_only R_D3D11_Window r_d3d11_window_nil = {&r_d3d11_window_nil}; +global read_only R_D3D11_Tex2D r_d3d11_tex2d_nil = {&r_d3d11_tex2d_nil}; +global read_only R_D3D11_Buffer r_d3d11_buffer_nil = {&r_d3d11_buffer_nil}; //////////////////////////////// //~ rjf: Helpers diff --git a/src/render/d3d11/render_d3d11.mdesk b/src/render/d3d11/render_d3d11.mdesk index d05aad0f..81e2084d 100644 --- a/src/render/d3d11/render_d3d11.mdesk +++ b/src/render/d3d11/render_d3d11.mdesk @@ -81,6 +81,20 @@ float rect_sdf(float2 sample_pos, float2 rect_half_size, float r) return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r; } +float linear_from_srgb_f32(float x) +{ + return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); +} + +float4 linear_from_srgba(float4 v) +{ + float4 result = float4(linear_from_srgb_f32(v.x), + linear_from_srgb_f32(v.y), + linear_from_srgb_f32(v.z), + v.w); + return result; +} + //- rjf: vertex shader Vertex2Pixel @@ -120,7 +134,8 @@ vs_main(CPU2Vertex cpu2vertex) cpu2vertex.corner_radii_px.w, cpu2vertex.corner_radii_px.z, }; - float4 src_color[] = { + float4 src_color[] = + { cpu2vertex.color01, cpu2vertex.color00, cpu2vertex.color11, @@ -162,6 +177,7 @@ ps_main(Vertex2Pixel vertex2pixel) : SV_TARGET if(vertex2pixel.omit_texture < 1) { albedo_sample = mul(main_t2d.Sample(main_sampler, vertex2pixel.texcoord_pct), texture_sample_channel_map); + albedo_sample = linear_from_srgba(albedo_sample); } // rjf: determine SDF sample position @@ -261,8 +277,7 @@ vs_main(CPU2Vertex c2v) corner_radii_px.w, corner_radii_px.z, }; - float2 cornercoords__pct = float2( - (c2v.vertex_id >> 1) ? 1.f : 0.f, + float2 cornercoords__pct = float2((c2v.vertex_id >> 1) ? 1.f : 0.f, (c2v.vertex_id & 1) ? 0.f : 1.f); float2 vertex_position__pct = vertex_positions__scrn[c2v.vertex_id] / viewport_size; diff --git a/src/render/opengl/generated/render_opengl.meta.c b/src/render/opengl/generated/render_opengl.meta.c new file mode 100644 index 00000000..7084ac1b --- /dev/null +++ b/src/render/opengl/generated/render_opengl.meta.c @@ -0,0 +1,38 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +C_LINKAGE_BEGIN +String8 r_ogl_shader_kind_name_table[2] = +{ +str8_lit_comp("rect"), +str8_lit_comp("blur"), +}; + +String8 * r_ogl_shader_kind_vshad_src_table[2] = +{ +&r_ogl_rect_vshad_src, +&r_ogl_blur_vshad_src, +}; + +String8 * r_ogl_shader_kind_pshad_src_table[2] = +{ +&r_ogl_rect_pshad_src, +&r_ogl_blur_pshad_src, +}; + +R_OGL_AttributeArray r_ogl_shader_kind_input_attributes_table[2] = +{ +{ r_ogl_rect_input_attributes, ArrayCount(r_ogl_rect_input_attributes) }, +{ 0, }, +}; + +R_OGL_AttributeArray r_ogl_shader_kind_output_attributes_table[2] = +{ +{ r_ogl_single_color_output_attributes, ArrayCount(r_ogl_single_color_output_attributes) }, +{ r_ogl_single_color_output_attributes, ArrayCount(r_ogl_single_color_output_attributes) }, +}; + +C_LINKAGE_END + diff --git a/src/render/opengl/generated/render_opengl.meta.h b/src/render/opengl/generated/render_opengl.meta.h new file mode 100644 index 00000000..9f33f24d --- /dev/null +++ b/src/render/opengl/generated/render_opengl.meta.h @@ -0,0 +1,276 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef RENDER_OPENGL_META_H +#define RENDER_OPENGL_META_H + +typedef enum R_OGL_ShaderKind +{ +R_OGL_ShaderKind_Rect, +R_OGL_ShaderKind_Blur, +R_OGL_ShaderKind_COUNT, +} R_OGL_ShaderKind; + +C_LINKAGE_BEGIN +extern String8 r_ogl_shader_kind_name_table[2]; +extern String8 * r_ogl_shader_kind_vshad_src_table[2]; +extern String8 * r_ogl_shader_kind_pshad_src_table[2]; +extern R_OGL_AttributeArray r_ogl_shader_kind_input_attributes_table[2]; +extern R_OGL_AttributeArray r_ogl_shader_kind_output_attributes_table[2]; +read_only global String8 r_ogl_rect_vshad_src = +str8_lit_comp( +"" +"\n" +"#version 330 core\n" +"\n" +"in vec4 c2v_dst_rect;\n" +"in vec4 c2v_src_rect;\n" +"in vec4 c2v_colors_0;\n" +"in vec4 c2v_colors_1;\n" +"in vec4 c2v_colors_2;\n" +"in vec4 c2v_colors_3;\n" +"in vec4 c2v_corner_radii;\n" +"in vec4 c2v_style; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused\n" +"\n" +"out vec2 v2p_sdf_sample_pos;\n" +"out vec2 v2p_texcoord_pct;\n" +"out vec2 v2p_rect_half_size_px;\n" +"out vec4 v2p_tint;\n" +"out float v2p_corner_radius;\n" +"out float v2p_border_thickness;\n" +"out float v2p_softness;\n" +"out float v2p_omit_texture;\n" +"\n" +"uniform sampler2D u_tex_color;\n" +"uniform vec2 u_viewport_size_px;\n" +"\n" +"void main(void)\n" +"{\n" +" // rjf: constants\n" +" vec2 vertices[] = vec2[](vec2(-1, -1), vec2(-1, +1), vec2(+1, -1), vec2(+1, +1));\n" +" \n" +" // rjf: find dst position\n" +" vec2 dst_half_size = (c2v_dst_rect.zw - c2v_dst_rect.xy) / 2;\n" +" vec2 dst_center = (c2v_dst_rect.zw + c2v_dst_rect.xy) / 2;\n" +" vec2 dst_position = vertices[gl_VertexID] * dst_half_size + dst_center;\n" +" \n" +" // rjf: find src position\n" +" vec2 src_half_size = (c2v_src_rect.zw - c2v_src_rect.xy) / 2;\n" +" vec2 src_center = (c2v_src_rect.zw + c2v_src_rect.xy) / 2;\n" +" vec2 src_position = vertices[gl_VertexID] * src_half_size + src_center;\n" +" \n" +" // rjf: find color\n" +" vec4 colors[] = vec4[](c2v_colors_0, c2v_colors_1, c2v_colors_2, c2v_colors_3);\n" +" vec4 color = colors[gl_VertexID];\n" +" \n" +" // rjf: find corner radius\n" +" float corner_radii[] = float[](c2v_corner_radii.x, c2v_corner_radii.y, c2v_corner_radii.z, c2v_corner_radii.w);\n" +" float corner_radius = corner_radii[gl_VertexID];\n" +" \n" +" // rjf: fill outputs\n" +" vec2 dst_verts_pct = vec2(((gl_VertexID >> 1) != 1) ? 1.f : 0.f,\n" +" ((gl_VertexID & 1) != 0) ? 0.f : 1.f);\n" +" ivec2 u_tex_color_size_i = textureSize(u_tex_color, 0);\n" +" vec2 u_tex_color_size = vec2(float(u_tex_color_size_i.x), float(u_tex_color_size_i.y));\n" +" {\n" +" gl_Position = vec4(2 * dst_position.x / u_viewport_size_px.x - 1,\n" +" 2 * (1 - dst_position.y / u_viewport_size_px.y) - 1,\n" +" 0.0, 1.0);\n" +" v2p_sdf_sample_pos = (2.f * dst_verts_pct - 1.f) * dst_half_size;\n" +" v2p_texcoord_pct = src_position / u_tex_color_size;\n" +" v2p_rect_half_size_px = dst_half_size;\n" +" v2p_tint = color;\n" +" v2p_corner_radius = corner_radius;\n" +" v2p_border_thickness = c2v_style.x;\n" +" v2p_softness = c2v_style.y;\n" +" v2p_omit_texture = c2v_style.z;\n" +" }\n" +"}\n" +"" +); + +read_only global String8 r_ogl_rect_pshad_src = +str8_lit_comp( +"" +"\n" +"#version 330 core\n" +"\n" +"in vec2 v2p_sdf_sample_pos;\n" +"in vec2 v2p_texcoord_pct;\n" +"in vec2 v2p_rect_half_size_px;\n" +"in vec4 v2p_tint;\n" +"in float v2p_corner_radius;\n" +"in float v2p_border_thickness;\n" +"in float v2p_softness;\n" +"in float v2p_omit_texture;\n" +"\n" +"out vec4 final_color;\n" +"\n" +"uniform float u_opacity;\n" +"uniform sampler2D u_tex_color;\n" +"uniform mat4 u_texture_sample_channel_map;\n" +"\n" +"float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)\n" +"{\n" +" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n" +"}\n" +"\n" +"float linear_from_srgb_f32(float x)\n" +"{\n" +" return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4);\n" +"}\n" +"\n" +"vec4 linear_from_srgba(vec4 v)\n" +"{\n" +" vec4 result = vec4(linear_from_srgb_f32(v.x),\n" +" linear_from_srgb_f32(v.y),\n" +" linear_from_srgb_f32(v.z),\n" +" v.w);\n" +" return result;\n" +"}\n" +"\n" +"void main(void)\n" +"{\n" +" // rjf: sample texture\n" +" vec4 albedo_sample = vec4(1, 1, 1, 1);\n" +" if(v2p_omit_texture < 1)\n" +" {\n" +" albedo_sample = u_texture_sample_channel_map * texture(u_tex_color, v2p_texcoord_pct);\n" +" albedo_sample = linear_from_srgba(albedo_sample);\n" +" }\n" +" \n" +" // rjf: sample for borders\n" +" float border_sdf_t = 1;\n" +" if(v2p_border_thickness > 0)\n" +" {\n" +" float border_sdf_s = rect_sdf(v2p_sdf_sample_pos,\n" +" v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f) - v2p_border_thickness,\n" +" max(v2p_corner_radius-v2p_border_thickness, 0));\n" +" border_sdf_t = smoothstep(0, 2*v2p_softness, border_sdf_s);\n" +" }\n" +" if(border_sdf_t < 0.001f)\n" +" {\n" +" discard;\n" +" }\n" +" \n" +" // rjf: sample for corners\n" +" float corner_sdf_t = 1;\n" +" if(v2p_corner_radius > 0 || v2p_softness > 0.75f)\n" +" {\n" +" float corner_sdf_s = rect_sdf(v2p_sdf_sample_pos,\n" +" v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f),\n" +" v2p_corner_radius);\n" +" corner_sdf_t = 1-smoothstep(0, 2*v2p_softness, corner_sdf_s);\n" +" }\n" +" \n" +" // rjf: form+return final color\n" +" final_color = albedo_sample;\n" +" final_color *= v2p_tint;\n" +" final_color.a *= u_opacity;\n" +" final_color.a *= corner_sdf_t;\n" +" final_color.a *= border_sdf_t;\n" +"}\n" +"" +); + +read_only global String8 r_ogl_blur_vshad_src = +str8_lit_comp( +"" +"\n" +"#version 330 core\n" +"\n" +"uniform vec4 rect;\n" +"uniform vec4 corner_radii_px;\n" +"uniform vec2 viewport_size;\n" +"uniform uint blur_count;\n" +"\n" +"out vec2 texcoord;\n" +"out vec2 sdf_sample_pos;\n" +"out vec2 rect_half_size;\n" +"out float corner_radius;\n" +"\n" +"void main(void)\n" +"{\n" +" vec2 vertex_positions_scrn[] = vec2[](rect.xw,\n" +" rect.xy,\n" +" rect.zw,\n" +" rect.zy);\n" +" float corner_radii_px[] = float[](corner_radii_px.y,\n" +" corner_radii_px.x,\n" +" corner_radii_px.w,\n" +" corner_radii_px.z);\n" +" vec2 cornercoords_pct = vec2((gl_VertexID >> 1) != 0 ? 1.f : 0.f,\n" +" (gl_VertexID & 1) != 0 ? 0.f : 1.f);\n" +" \n" +" vec2 vertex_position_pct = vertex_positions_scrn[gl_VertexID] / viewport_size;\n" +" vec2 vertex_position_scr = 2.f * vertex_position_pct - 1.f;\n" +" \n" +" vec2 rect_half_size = vec2((rect.z-rect.x)/2, (rect.w-rect.y)/2);\n" +" \n" +" gl_Position = vec4(vertex_position_scr.x, -vertex_position_scr.y, 0.f, 1.f);\n" +" texcoord = vertex_position_pct;\n" +" sdf_sample_pos = (2.f * cornercoords_pct - 1.f) * rect_half_size;\n" +" rect_half_size = rect_half_size - 2.f;\n" +" corner_radius = corner_radii_px[gl_VertexID];\n" +"}\n" +"" +); + +read_only global String8 r_ogl_blur_pshad_src = +str8_lit_comp( +"" +"\n" +"#version 330 core\n" +"\n" +"uniform sampler2D tex;\n" +"uniform vec4 kernel[32];\n" +"uniform int blur_count;\n" +"uniform vec2 direction;\n" +"\n" +"in vec2 texcoord;\n" +"in vec2 sdf_sample_pos;\n" +"in vec2 rect_half_size;\n" +"in float corner_radius;\n" +"\n" +"out vec4 final_color;\n" +"\n" +"float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r)\n" +"{\n" +" return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r;\n" +"}\n" +"\n" +"void main(void)\n" +"{\n" +" // rjf: blend weighted texture samples into color\n" +" vec3 color = kernel[0].x * texture(tex, texcoord).rgb;\n" +" \n" +" for(int i = 1; i < blur_count; i += 1)\n" +" {\n" +" float weight = kernel[i].x;\n" +" float offset = kernel[i].y;\n" +" color += weight * texture(tex, texcoord - offset * direction).rgb;\n" +" color += weight * texture(tex, texcoord + offset * direction).rgb;\n" +" }\n" +" \n" +" // rjf: sample for corners\n" +" float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size, corner_radius);\n" +" float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s);\n" +" \n" +" // rjf: weight output color by sdf\n" +" // this is doing alpha testing, leave blurring only where mostly opaque pixels are\n" +" if(corner_sdf_t < 0.9f)\n" +" {\n" +" discard;\n" +" }\n" +" \n" +" final_color = vec4(color, 1.f);\n" +"}\n" +"" +); + + +C_LINKAGE_END + +#endif // RENDER_OPENGL_META_H diff --git a/src/render/opengl/linux/egl/render_opengl_linux_egl.c b/src/render/opengl/linux/egl/render_opengl_linux_egl.c new file mode 100644 index 00000000..3d3370c6 --- /dev/null +++ b/src/render/opengl/linux/egl/render_opengl_linux_egl.c @@ -0,0 +1,189 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal VoidProc * +r_ogl_os_load_procedure(char *name) +{ + VoidProc *result = (VoidProc *)eglGetProcAddress(name); + return result; +} + +internal void +r_ogl_os_init(CmdLine *cmdln) +{ + //- rjf: set up state + { + Arena *arena = arena_alloc(); + r_ogl_lnx_state = push_array(arena, R_OGL_LNX_State, 1); + r_ogl_lnx_state->arena = arena; + } + + //- rjf: get EGL display + { + r_ogl_lnx_state->display = eglGetDisplay((EGLNativeDisplayType)os_lnx_gfx_state->display); + if(r_ogl_lnx_state->display == EGL_NO_DISPLAY) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Failed to get EGL display.")); + os_abort(1); + } + } + + //- rjf: initialize GL version + EGLint egl_version_major = 0; + EGLint egl_version_minor = 0; + if(!eglInitialize(r_ogl_lnx_state->display, &egl_version_major, &egl_version_minor)) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't initialize EGL display.")); + os_abort(1); + } + if(egl_version_major < 1 || (egl_version_major == 1 && egl_version_minor < 5)) + { + Temp scratch = scratch_begin(0, 0); + String8 message = push_str8f(scratch.arena, "Unsupported EGL version (%i.%i, need at least 1.5)", egl_version_major, egl_version_minor); + os_graphical_message(1, str8_lit("Fatal Error"), message); + os_abort(1); + scratch_end(scratch); + } + + //- rjf: pick GL API + if(!eglBindAPI(EGL_OPENGL_API)) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't initialize EGL API to OpenGL.")); + os_abort(1); + } + + //- rjf: construct context + { + B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug")); +#if BUILD_DEBUG + debug_mode = 1; +#endif + EGLint options[] = + { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_MINOR_VERSION, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + debug_mode ? EGL_CONTEXT_OPENGL_DEBUG : EGL_NONE, EGL_TRUE, + EGL_NONE, + }; + r_ogl_lnx_state->context = eglCreateContext(r_ogl_lnx_state->display, 0, EGL_NO_CONTEXT, options); + if(r_ogl_lnx_state->context == EGL_NO_CONTEXT) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't create OpenGL context with EGL.")); + os_abort(1); + } + } + + eglMakeCurrent(r_ogl_lnx_state->display, 0, 0, r_ogl_lnx_state->context); + glDrawBuffer(GL_BACK); +} + +internal R_Handle +r_ogl_os_window_equip(OS_Handle window) +{ + OS_LNX_Window *window_os = (OS_LNX_Window *)window.u64[0]; + R_OGL_LNX_Window *w = r_ogl_lnx_state->free_window; + if(w != 0) + { + SLLStackPop(r_ogl_lnx_state->free_window); + } + else + { + w = push_array(r_ogl_lnx_state->arena, R_OGL_LNX_Window, 1); + } + { + EGLint surface_options[] = + { + EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, + EGL_NONE, + }; + if(r_ogl_lnx_state->config == 0) + { + //- rjf: get all EGL configs + EGLConfig configs[256] = {0}; + EGLint configs_count = 0; + { + EGLint options[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_CONFORMANT, EGL_OPENGL_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, + + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + + EGL_NONE, + }; + if(!eglChooseConfig(r_ogl_lnx_state->display, options, configs, ArrayCount(configs), &configs_count) || configs_count == 0) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't choose EGL configuration.")); + os_abort(1); + } + } + + //- rjf: actually choose the egl config + { + EGLint config_options[] = + { + EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, + EGL_NONE, + }; + for(U32 idx = 0; idx < configs_count; idx += 1) + { + w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, configs[idx], window_os->window, config_options); + if(w->surface != EGL_NO_SURFACE) + { + r_ogl_lnx_state->config = configs[idx]; + break; + } + } + if(r_ogl_lnx_state->config == 0) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't find a suitable EGL configuration.")); + os_abort(1); + } + } + } + else + { + w->surface = eglCreateWindowSurface(r_ogl_lnx_state->display, r_ogl_lnx_state->config, window_os->window, surface_options); + } + if(w->surface == EGL_NO_SURFACE) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Couldn't create EGL surface.")); + os_abort(1); + } + } + R_Handle result = {(U64)w}; + return result; +} + +internal void +r_ogl_os_window_unequip(OS_Handle os, R_Handle r) +{ + R_OGL_LNX_Window *w = (R_OGL_LNX_Window *)r.u64[0]; + { + + } + SLLStackPush(r_ogl_lnx_state->free_window, w); +} + +internal void +r_ogl_os_select_window(OS_Handle os, R_Handle r) +{ + OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0]; + R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0]; + eglMakeCurrent(r_ogl_lnx_state->display, w_r->surface, w_r->surface, r_ogl_lnx_state->context); +} + +internal void +r_ogl_os_window_swap(OS_Handle os, R_Handle r) +{ + OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0]; + R_OGL_LNX_Window *w_r = (R_OGL_LNX_Window *)r.u64[0]; + eglSwapBuffers(r_ogl_lnx_state->display, w_r->surface); +} diff --git a/src/render/opengl/linux/egl/render_opengl_linux_egl.h b/src/render/opengl/linux/egl/render_opengl_linux_egl.h new file mode 100644 index 00000000..54a419d1 --- /dev/null +++ b/src/render/opengl/linux/egl/render_opengl_linux_egl.h @@ -0,0 +1,35 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_OPENGL_LINUX_EGL_H +#define RENDER_OPENGL_LINUX_EGL_H + +#define glTexImage3D glTexImage3D__static +#define glTexSubImage3D glTexSubImage3D__static +#define glActiveTexture glActiveTexture__static +#include +#include +#undef glTexImage3D +#undef glTexSubImage3D +#undef glActiveTexture + +typedef struct R_OGL_LNX_Window R_OGL_LNX_Window; +struct R_OGL_LNX_Window +{ + R_OGL_LNX_Window *next; + EGLSurface *surface; +}; + +typedef struct R_OGL_LNX_State R_OGL_LNX_State; +struct R_OGL_LNX_State +{ + Arena *arena; + EGLDisplay *display; + EGLConfig config; + EGLContext *context; + R_OGL_LNX_Window *free_window; +}; + +global R_OGL_LNX_State *r_ogl_lnx_state = 0; + +#endif // RENDER_OPENGL_LINUX_EGL_H diff --git a/src/render/opengl/linux/glx/render_opengl_linux_glx.c b/src/render/opengl/linux/glx/render_opengl_linux_glx.c new file mode 100644 index 00000000..f8ca0af0 --- /dev/null +++ b/src/render/opengl/linux/glx/render_opengl_linux_glx.c @@ -0,0 +1,106 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal VoidProc * +r_ogl_os_load_procedure(char *name) +{ + VoidProc *result = (VoidProc *)glXGetProcAddressARB((U8 *)name); + return result; +} + +internal void +r_ogl_os_init(CmdLine *cmdln) +{ + //- rjf: require GLX 1.3+ + int glx_version_major = 0; + int glx_version_minor = 0; + if(!glXQueryVersion(os_lnx_gfx_state->display, &glx_version_major, &glx_version_minor) || + (glx_version_major == 1 && glx_version_minor < 3) || + glx_version_major < 1) + { + Temp scratch = scratch_begin(0, 0); + String8 message = push_str8f(scratch.arena, "Unsupported GLX version (%i.%i, need at least 1.3)", glx_version_major, glx_version_minor); + os_graphical_message(1, str8_lit("Fatal Error"), message); + os_abort(1); + scratch_end(scratch); + } + + //- rjf: get frame buffer configs + local_persist int framebuffer_config_options[] = + { + GLX_X_RENDERABLE, 1, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + GLX_DOUBLEBUFFER, 1, + None + }; + int framebuffer_configs_count = 0; + GLXFBConfig *framebuffer_configs = glXChooseFBConfig(os_lnx_gfx_state->display, DefaultScreen(os_lnx_gfx_state->display), framebuffer_config_options, &framebuffer_configs_count); + if(framebuffer_configs == 0) + { + os_graphical_message(1, str8_lit("Fatal Error"), str8_lit("Could not find a suitable framebuffer configuration.")); + os_abort(1); + } + GLXFBConfig framebuffer_config = framebuffer_configs[0]; + XFree(framebuffer_configs); + + //- rjf: construct set-window-attributes + XSetWindowAttributes set_window_attributes = {0}; + set_window_attributes.background_pixmap = None; + set_window_attributes.border_pixel = 0; + set_window_attributes.event_mask = StructureNotifyMask; + + //- rjf: construct context + { + B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug")); +#if BUILD_DEBUG + debug_mode = 1; +#endif + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((U8 *)"glXCreateContextAttribsARB"); + int context_options[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_FLAGS_ARB, !!debug_mode*GLX_CONTEXT_DEBUG_BIT_ARB, + None + }; + r_ogl_lnx_ctx = glXCreateContextAttribsARB(os_lnx_gfx_state->display, framebuffer_config, 0, 1, context_options); + } + + glXMakeCurrent(os_lnx_gfx_state->display, 0, r_ogl_lnx_ctx); +} + +internal R_Handle +r_ogl_os_window_equip(OS_Handle window) +{ + R_Handle result = {0}; + return result; +} + +internal void +r_ogl_os_window_unequip(OS_Handle os, R_Handle r) +{ + +} + +internal void +r_ogl_os_select_window(OS_Handle os, R_Handle r) +{ + OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0]; + glXMakeCurrent(os_lnx_gfx_state->display, w->window, r_ogl_lnx_ctx); +} + +internal void +r_ogl_os_window_swap(OS_Handle os, R_Handle r) +{ + OS_LNX_Window *w = (OS_LNX_Window *)os.u64[0]; + glXSwapBuffers(os_lnx_gfx_state->display, w->window); +} diff --git a/src/render/opengl/linux/glx/render_opengl_linux_glx.h b/src/render/opengl/linux/glx/render_opengl_linux_glx.h new file mode 100644 index 00000000..995172b0 --- /dev/null +++ b/src/render/opengl/linux/glx/render_opengl_linux_glx.h @@ -0,0 +1,25 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_OPENGL_LINUX_GLX_H +#define RENDER_OPENGL_LINUX_GLX_H + +#define glTexImage3D glTexImage3D__static +#define glTexSubImage3D glTexSubImage3D__static +#define glActiveTexture glActiveTexture__static +#include +#include +#undef glTexImage3D +#undef glTexSubImage3D +#undef glActiveTexture + +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + +global GLXContext r_ogl_lnx_ctx = 0; + +#endif // RENDER_OPENGL_LINUX_GLX_H diff --git a/src/render/opengl/linux/render_opengl_linux.c b/src/render/opengl/linux/render_opengl_linux.c new file mode 100644 index 00000000..4e0e2964 --- /dev/null +++ b/src/render/opengl/linux/render_opengl_linux.c @@ -0,0 +1,13 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Backend Includes + +#if R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_GLX +# include "glx/render_opengl_linux_glx.c" +#elif R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_EGL +# include "egl/render_opengl_linux_egl.c" +#else +# error Linux OpenGL backend not specified. +#endif diff --git a/src/render/opengl/linux/render_opengl_linux.h b/src/render/opengl/linux/render_opengl_linux.h new file mode 100644 index 00000000..21069e8d --- /dev/null +++ b/src/render/opengl/linux/render_opengl_linux.h @@ -0,0 +1,31 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_OPENGL_LINUX_H +#define RENDER_OPENGL_LINUX_H + +//////////////////////////////// +//~ rjf: Backend Constants + +#define R_OPENGL_LINUX_BACKEND_GLX 0 +#define R_OPENGL_LINUX_BACKEND_EGL 1 + +//////////////////////////////// +//~ rjf: Decide On Backend + +#if !defined(R_OPENGL_LINUX_BACKEND) +# define R_OPENGL_LINUX_BACKEND R_OPENGL_LINUX_BACKEND_EGL +#endif + +//////////////////////////////// +//~ rjf: Backend Includes + +#if R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_GLX +# include "glx/render_opengl_linux_glx.h" +#elif R_OPENGL_LINUX_BACKEND == R_OPENGL_LINUX_BACKEND_EGL +# include "egl/render_opengl_linux_egl.h" +#else +# error Linux OpenGL backend not specified. +#endif + +#endif // RENDER_OPENGL_LINUX_H diff --git a/src/render/opengl/render_opengl.c b/src/render/opengl/render_opengl.c new file mode 100644 index 00000000..0661e8dc --- /dev/null +++ b/src/render/opengl/render_opengl.c @@ -0,0 +1,522 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: OS Portion Includes + +#if OS_WINDOWS +# include "render/opengl/win32/render_opengl_win32.c" +#elif OS_LINUX +# include "render/opengl/linux/render_opengl_linux.c" +#else +# error OS portion of OpenGL rendering backend not defined. +#endif + +//////////////////////////////// +//~ rjf: Attribute Tables + +global read_only R_OGL_Attribute r_ogl_rect_input_attributes[] = +{ + {0, str8_lit_comp("c2v_dst_rect"), GL_FLOAT, 4}, + {1, str8_lit_comp("c2v_src_rect"), GL_FLOAT, 4}, + {2, str8_lit_comp("c2v_colors_0"), GL_FLOAT, 4}, + {3, str8_lit_comp("c2v_colors_1"), GL_FLOAT, 4}, + {4, str8_lit_comp("c2v_colors_2"), GL_FLOAT, 4}, + {5, str8_lit_comp("c2v_colors_3"), GL_FLOAT, 4}, + {6, str8_lit_comp("c2v_corner_radii"), GL_FLOAT, 4}, + {7, str8_lit_comp("c2v_style"), GL_FLOAT, 4}, +}; + +global read_only R_OGL_Attribute r_ogl_single_color_output_attributes[] = +{ + {0, str8_lit_comp("final_color")}, +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "render/opengl/generated/render_opengl.meta.c" + +//////////////////////////////// +//~ rjf: Helpers + +internal R_Handle +r_ogl_handle_from_tex2d(R_OGL_Tex2D *t) +{ + R_Handle h = {(U64)t}; + return h; +} + +internal R_OGL_Tex2D * +r_ogl_tex2d_from_handle(R_Handle h) +{ + R_OGL_Tex2D *t = (R_OGL_Tex2D *)h.u64[0]; + return t; +} + +internal R_OGL_FormatInfo +r_ogl_format_info_from_tex2dformat(R_Tex2DFormat fmt) +{ + R_OGL_FormatInfo result; + result.internal_format = GL_RGBA; + result.format = GL_RGBA; + result.base_type = GL_UNSIGNED_BYTE; + // TODO(rjf) + return result; +} + +internal GLuint +r_ogl_instance_buffer_from_size(U64 size) +{ + GLuint buffer = r_ogl_state->scratch_buffer_64kb; + if(size > KB(64)) + { + // rjf: build buffer + U64 flushed_buffer_size = size; + flushed_buffer_size += MB(1)-1; + flushed_buffer_size -= flushed_buffer_size%MB(1); + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, flushed_buffer_size, 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // rjf: push buffer to flush list + R_OGL_FlushBuffer *n = push_array(r_ogl_state->buffer_flush_arena, R_OGL_FlushBuffer, 1); + n->id = buffer; + SLLQueuePush(r_ogl_state->first_buffer_to_flush, r_ogl_state->last_buffer_to_flush, n); + } + return buffer; +} + +internal void +r_ogl_debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) +{ + raddbg_log("[OpenGL] %.*s\n", (int)length, message); + fprintf(stderr, "[OpenGL] %.*s\n", (int)length, message); +} + +//////////////////////////////// +//~ rjf: Backend Hooks + +//- rjf: top-level layer initialization + +r_hook void +r_init(CmdLine *cmdln) +{ + //- rjf: do os-specific portion of work + r_ogl_os_init(cmdln); + + //- rjf: top-level initialization + Arena *arena = arena_alloc(); + r_ogl_state = push_array(arena, R_OGL_State, 1); + r_ogl_state->arena = arena; + + //- rjf: load gl procedures +#define X(name, r, p) name = (name##_FunctionType *)r_ogl_os_load_procedure(#name); + R_OGL_ProcedureXList +#undef X + + //- rjf: build all shaders + for EachEnumVal(R_OGL_ShaderKind, k) + { + // rjf: compile + struct {GLenum type; String8 *src; GLuint out; String8 errors;} stages[] = + { + {GL_VERTEX_SHADER, r_ogl_shader_kind_vshad_src_table[k]}, + {GL_FRAGMENT_SHADER, r_ogl_shader_kind_pshad_src_table[k]}, + }; + for EachElement(idx, stages) + { + stages[idx].out = glCreateShader(stages[idx].type); + GLint src_size = stages[idx].src->size; + glShaderSource(stages[idx].out, 1, (char **)&stages[idx].src->str, &src_size); + glCompileShader(stages[idx].out); + GLint info_log_length = 0; + GLint status = 0; + glGetShaderiv(stages[idx].out, GL_COMPILE_STATUS, &status); + glGetShaderiv(stages[idx].out, GL_INFO_LOG_LENGTH, &info_log_length); + if(info_log_length != 0) + { + stages[idx].errors.str = push_array(r_ogl_state->arena, U8, info_log_length+1); + stages[idx].errors.size = info_log_length; + glGetShaderInfoLog(stages[idx].out, info_log_length, 0, (char *)stages[idx].errors.str); + } + raddbg_pin(text(stages[idx].errors.str)); + } + + // rjf: attach compilations to program + GLuint program = glCreateProgram(); + for EachElement(idx, stages) + { + glAttachShader(program, stages[idx].out); + } + + // rjf: bind inputs + R_OGL_AttributeArray inputs = r_ogl_shader_kind_input_attributes_table[k]; + for EachIndex(idx, inputs.count) + { + glBindAttribLocation(program, inputs.v[idx].index, (char *)inputs.v[idx].name.str); + } + + // rjf: bind outputs + R_OGL_AttributeArray outputs = r_ogl_shader_kind_output_attributes_table[k]; + for EachIndex(idx, outputs.count) + { + glBindFragDataLocation(program, outputs.v[idx].index, (char *)outputs.v[idx].name.str); + } + + // rjf: link / validate / store + glLinkProgram(program); + glValidateProgram(program); + r_ogl_state->shaders[k] = program; + } + + //- rjf: set up built-in resources + glGenVertexArrays(1, &r_ogl_state->all_purpose_vao); + glGenBuffers(1, &r_ogl_state->scratch_buffer_64kb); + glBindBuffer(GL_ARRAY_BUFFER, r_ogl_state->scratch_buffer_64kb); + glBufferData(GL_ARRAY_BUFFER, KB(64), 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glGenTextures(1, &r_ogl_state->white_texture); + glBindTexture(GL_TEXTURE_2D, r_ogl_state->white_texture); + U32 white_pixel = 0xffffffff; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &white_pixel); + glEnable(GL_FRAMEBUFFER_SRGB); + + //- rjf: set up buffer flush state + r_ogl_state->buffer_flush_arena = arena_alloc(); + + //- rjf: set up debug callback + B32 debug_mode = cmd_line_has_flag(cmdln, str8_lit("opengl_debug")); +#if BUILD_DEBUG + debug_mode = 1; +#endif + if(debug_mode) + { + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(r_ogl_debug_message_callback, 0); + } +} + +//- rjf: window setup/teardown + +r_hook R_Handle +r_window_equip(OS_Handle window) +{ + R_Handle result = r_ogl_os_window_equip(window); + return result; +} + +r_hook void +r_window_unequip(OS_Handle window, R_Handle window_equip) +{ + r_ogl_os_window_unequip(window, window_equip); +} + +//- rjf: textures + +r_hook R_Handle +r_tex2d_alloc(R_ResourceKind kind, Vec2S32 size, R_Tex2DFormat format, void *data) +{ + //- rjf: allocate texture record + R_OGL_Tex2D *tex2d = r_ogl_state->free_tex2d; + if(tex2d) + { + SLLStackPop(r_ogl_state->free_tex2d); + } + else + { + tex2d = push_array(r_ogl_state->arena, R_OGL_Tex2D, 1); + } + + //- rjf: map kind/format -> gl counterparts + R_OGL_FormatInfo gl_fmt_info = r_ogl_format_info_from_tex2dformat(format); + + //- rjf: allocate GL texture + { + glGenTextures(1, &tex2d->id); + glBindTexture(GL_TEXTURE_2D, tex2d->id); + glTexImage2D(GL_TEXTURE_2D, 0, gl_fmt_info.internal_format, size.x, size.y, 0, gl_fmt_info.format, gl_fmt_info.base_type, data); + glBindTexture(GL_TEXTURE_2D, 0); + } + + //- rjf: fill + tex2d->resource_kind = kind; + tex2d->fmt = format; + tex2d->size = size; + + //- rjf: bundle & return + R_Handle result = r_ogl_handle_from_tex2d(tex2d); + return result; +} + +r_hook void +r_tex2d_release(R_Handle texture) +{ + R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture); + if(t != 0) + { + glDeleteTextures(1, &t->id); + SLLStackPush(r_ogl_state->free_tex2d, t); + } +} + +r_hook R_ResourceKind +r_kind_from_tex2d(R_Handle texture) +{ + R_ResourceKind result = R_ResourceKind_Static; + R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture); + if(t) + { + result = t->resource_kind; + } + return result; +} + +r_hook Vec2S32 +r_size_from_tex2d(R_Handle texture) +{ + Vec2S32 result = {0, 0}; + R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture); + if(t) + { + result = t->size; + } + return result; +} + +r_hook R_Tex2DFormat +r_format_from_tex2d(R_Handle texture) +{ + R_Tex2DFormat result = R_Tex2DFormat_RGBA8; + R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture); + if(t) + { + result = t->fmt; + } + return result; +} + +r_hook void +r_fill_tex2d_region(R_Handle texture, Rng2S32 subrect, void *data) +{ + R_OGL_Tex2D *t = r_ogl_tex2d_from_handle(texture); + if(t) + { + R_OGL_FormatInfo fmt_info = r_ogl_format_info_from_tex2dformat(t->fmt); + glBindTexture(GL_TEXTURE_2D, t->id); + Vec2S32 rect_size = dim_2s32(subrect); + glTexSubImage2D(GL_TEXTURE_2D, 0, subrect.x0, subrect.y0, rect_size.x, rect_size.y, fmt_info.format, fmt_info.base_type, data); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + +//- rjf: buffers + +r_hook R_Handle +r_buffer_alloc(R_ResourceKind kind, U64 size, void *data) +{ + R_Handle result = {0}; + return result; +} + +r_hook void +r_buffer_release(R_Handle buffer) +{ + // TODO(rjf) +} + +//- rjf: frame markers + +r_hook void +r_begin_frame(void) +{ + // TODO(rjf) +} + +r_hook void +r_end_frame(void) +{ + // TODO(rjf) +} + +r_hook void +r_window_begin_frame(OS_Handle os, R_Handle r) +{ + r_ogl_os_select_window(os, r); + + //- rjf: unpack window viewport info + Rng2F32 client_rect = os_client_rect_from_window(os); + Vec2F32 client_rect_dim = dim_2f32(client_rect); + + //- rjf: clear and reset state + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, (S32)client_rect_dim.x, (S32)client_rect_dim.y); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +r_hook void +r_window_end_frame(OS_Handle os, R_Handle r) +{ + for(R_OGL_FlushBuffer *flush_buffer = r_ogl_state->first_buffer_to_flush; flush_buffer != 0; flush_buffer = flush_buffer->next) + { + glDeleteBuffers(1, &flush_buffer->id); + } + arena_clear(r_ogl_state->buffer_flush_arena); + r_ogl_state->first_buffer_to_flush = r_ogl_state->last_buffer_to_flush = 0; + r_ogl_os_window_swap(os, r); +} + +//- rjf: render pass submission + +r_hook void +r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes) +{ + Rng2F32 viewport_rect = os_client_rect_from_window(window); + Vec2F32 viewport_dim = dim_2f32(viewport_rect); + for(R_PassNode *pass_n = passes->first; pass_n != 0; pass_n = pass_n->next) + { + R_Pass *pass = &pass_n->v; + switch(pass->kind) + { + default:{}break; + + //////////////////////// + //- rjf: ui rendering pass + // + case R_PassKind_UI: + { + //- rjf: unpack params + R_PassParams_UI *params = pass->params_ui; + R_BatchGroup2DList *rect_batch_groups = ¶ms->rects; + + //- rjf: draw each batch group + GLuint shader = r_ogl_state->shaders[R_OGL_ShaderKind_Rect]; + glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader) + { + for(R_BatchGroup2DNode *group_n = rect_batch_groups->first; group_n != 0; group_n = group_n->next) + { + R_BatchList *batches = &group_n->batches; + R_BatchGroup2DParams *group_params = &group_n->params; + + //- rjf: unpack texture + R_Tex2DFormat texture_fmt = R_Tex2DFormat_RGBA8; + GLuint texture_id = r_ogl_state->white_texture; + { + R_OGL_Tex2D *tex = r_ogl_tex2d_from_handle(group_params->tex); + if(tex != 0) + { + texture_id = tex->id; + texture_fmt = tex->fmt; + } + } + + //- rjf: get & fill buffer + GLuint buffer = r_ogl_instance_buffer_from_size(batches->byte_count); + { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + U64 off = 0; + for(R_BatchNode *batch_n = batches->first; batch_n != 0; batch_n = batch_n->next) + { + glBufferSubData(GL_ARRAY_BUFFER, off, batch_n->v.byte_count, batch_n->v.v); + off += batch_n->v.byte_count; + } + } + + //- rjf: bind input attributes + { + R_OGL_AttributeArray inputs = r_ogl_shader_kind_input_attributes_table[R_OGL_ShaderKind_Rect]; + U64 off = 0; + for EachIndex(idx, inputs.count) + { + glEnableVertexAttribArray(inputs.v[idx].index); + glVertexAttribDivisor(inputs.v[idx].index, 1); + glVertexAttribPointer(inputs.v[idx].index, inputs.v[idx].count, inputs.v[idx].type, GL_FALSE, sizeof(R_Rect2DInst), (void *)(off)); + // TODO(rjf): this is not correct if type != GL_FLOAT + off += inputs.v[idx].count*sizeof(F32); + } + } + + //- rjf: bind texture + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + switch(group_params->tex_sample_kind) + { + default: + case R_Tex2DSampleKind_Nearest: + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + }break; + case R_Tex2DSampleKind_Linear: + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + }break; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glUniform1i(glGetUniformLocation(shader, "u_tex_color"), 0); + } + + //- rjf: upload misc. uniforms + { + Mat4x4F32 texture_sample_channel_map = r_sample_channel_map_from_tex2dformat(texture_fmt); + glUniformMatrix4fv(glGetUniformLocation(shader, "u_texture_sample_channel_map"), 1, 0, &texture_sample_channel_map.v[0][0]); + glUniform2f(glGetUniformLocation(shader, "u_viewport_size_px"), viewport_dim.x, viewport_dim.y); + glUniform1f(glGetUniformLocation(shader, "u_opacity"), 1.f - group_params->transparency); + } + + //- rjf: set up scissor + if(group_params->clip.x0 != 0 || + group_params->clip.x1 != 0 || + group_params->clip.y0 != 0 || + group_params->clip.y1 != 0) + { + Rng2F32 clip = group_params->clip; + glScissor(clip.x0, viewport_dim.y - clip.y1, (clip.x1-clip.x0) + 1, (clip.y1-clip.y0)+1); + glEnable(GL_SCISSOR_TEST); + } + + //- rjf: draw + { + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, batches->byte_count / batches->bytes_per_inst); + } + + //- rjf: unset scissor + glDisable(GL_SCISSOR_TEST); + } + } + }break; + + //////////////////////// + //- rjf: blur rendering pass + // + case R_PassKind_Blur: + { + R_PassParams_Blur *params = pass->params_blur; + GLuint shader = r_ogl_state->shaders[R_OGL_ShaderKind_Blur]; + // TODO(rjf): glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader) + { + // TODO(rjf) + } + }break; + + + //////////////////////// + //- rjf: 3d geometry rendering pass + // + case R_PassKind_Geo3D: + { + //- rjf: unpack params + R_PassParams_Geo3D *params = pass->params_geo3d; + R_BatchGroup3DMap *mesh_group_map = ¶ms->mesh_batches; + // TODO(rjf) + }break; + } + } +} diff --git a/src/render/opengl/render_opengl.h b/src/render/opengl/render_opengl.h new file mode 100644 index 00000000..618298e1 --- /dev/null +++ b/src/render/opengl/render_opengl.h @@ -0,0 +1,232 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_OPENGL_H +#define RENDER_OPENGL_H + +//////////////////////////////// +//~ rjf: Defines + +typedef char GLchar; +typedef ptrdiff_t GLsizeiptr; +typedef ptrdiff_t GLintptr; + +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#define GL_TEXTURE_MAX_LEVEL 0x813D + +#define GL_R8 0x8229 + +#define GL_ARRAY_BUFFER 0x8892 +#define GL_STREAM_DRAW 0x88E0 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA + +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#define GL_TESS_CONTROL_SHADER 0x8E88 +#define GL_INFO_LOG_LENGTH 0x8B84 + +#define GL_TEXTURE_2D_ARRAY 0x8C1A + +#define GL_COMPILE_STATUS 0x8B81 + +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF + +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 + +//////////////////////////////// +//~ rjf: OS Backend Includes + +#if OS_WINDOWS +# include "render/opengl/win32/render_opengl_win32.h" +#elif OS_LINUX +# include "render/opengl/linux/render_opengl_linux.h" +#else +# error OS portion of OpenGL rendering backend not defined. +#endif + +//////////////////////////////// +//~ rjf: Shader Metadata Types + +typedef struct R_OGL_Attribute R_OGL_Attribute; +struct R_OGL_Attribute +{ + U64 index; + String8 name; + GLenum type; + U64 count; +}; + +typedef struct R_OGL_AttributeArray R_OGL_AttributeArray; +struct R_OGL_AttributeArray +{ + R_OGL_Attribute *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Generated Code + +#include "render/opengl/generated/render_opengl.meta.h" + +//////////////////////////////// +//~ rjf: OpenGL Procedure List + +#define R_OGL_ProcedureXList \ +X(glGenBuffers, void, (GLsizei n, GLuint *buffers))\ +X(glBindBuffer, void, (GLenum target, GLuint buffer))\ +X(glDeleteBuffers, void, (GLsizei n, GLuint *buffers))\ +X(glGenVertexArrays, void, (GLsizei n, GLuint *arrays))\ +X(glBindVertexArray, void, (GLuint array))\ +X(glCreateProgram, GLuint, (void))\ +X(glCreateShader, GLuint, (GLenum type))\ +X(glShaderSource, void, (GLuint shader, GLsizei count, char **string, GLint *length))\ +X(glCompileShader, void, (GLuint shader))\ +X(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint *params))\ +X(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog))\ +X(glGetProgramiv, void, (GLuint program, GLenum pname, GLint *params))\ +X(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog))\ +X(glAttachShader, void, (GLuint program, GLuint shader))\ +X(glLinkProgram, void, (GLuint program))\ +X(glValidateProgram, void, (GLuint program))\ +X(glDeleteShader, void, (GLuint shader))\ +X(glUseProgram, void, (GLuint program))\ +X(glGetUniformLocation, GLint, (GLuint program, char *name))\ +X(glGetAttribLocation, GLint, (GLuint program, char *name))\ +X(glEnableVertexAttribArray, void, (GLuint index))\ +X(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer))\ +X(glBufferData, void, (GLenum target, ptrdiff_t size, void *data, GLenum usage))\ +X(glBufferSubData, void, (GLenum target, ptrdiff_t offset, ptrdiff_t size, const void *data))\ +X(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha))\ +X(glUniform1f, void, (GLint location, GLfloat v0))\ +X(glUniform2f, void, (GLint location, GLfloat v0, GLfloat v1))\ +X(glUniform3f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2))\ +X(glUniform4f, void, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3))\ +X(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))\ +X(glUniform1i, void, (GLint location, GLint v0))\ +X(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels))\ +X(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels))\ +X(glGenerateMipmap, void, (GLenum target))\ +X(glBindAttribLocation, void, (GLuint programObj, GLuint index, char *name))\ +X(glBindFragDataLocation, void, (GLuint program, GLuint color, char *name))\ +X(glActiveTexture, void, (GLenum texture))\ +X(glVertexAttribDivisor, void, (GLuint index, GLuint divisor))\ +X(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount))\ +X(glDebugMessageCallback, void, (void (*)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam), void *user_data))\ + +#define X(name, r, p) typedef r name##_FunctionType p; +R_OGL_ProcedureXList +#undef X +#define X(name, r, p) global name##_FunctionType *name = 0; +R_OGL_ProcedureXList +#undef X + +//////////////////////////////// +//~ rjf: State Types + +typedef struct R_OGL_FormatInfo R_OGL_FormatInfo; +struct R_OGL_FormatInfo +{ + GLint internal_format; + GLenum format; + GLenum base_type; +}; + +typedef struct R_OGL_Tex2D R_OGL_Tex2D; +struct R_OGL_Tex2D +{ + R_OGL_Tex2D *next; + GLuint id; + R_ResourceKind resource_kind; + R_Tex2DFormat fmt; + Vec2S32 size; +}; + +typedef struct R_OGL_FlushBuffer R_OGL_FlushBuffer; +struct R_OGL_FlushBuffer +{ + R_OGL_FlushBuffer *next; + GLuint id; +}; + +typedef struct R_OGL_State R_OGL_State; +struct R_OGL_State +{ + Arena *arena; + R_OGL_Tex2D *free_tex2d; + GLuint shaders[R_OGL_ShaderKind_COUNT]; + GLuint all_purpose_vao; + GLuint scratch_buffer_64kb; + GLuint white_texture; + Arena *buffer_flush_arena; + R_OGL_FlushBuffer *first_buffer_to_flush; + R_OGL_FlushBuffer *last_buffer_to_flush; +}; + +//////////////////////////////// +//~ rjf: Globals + +global R_OGL_State *r_ogl_state = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal R_Handle r_ogl_handle_from_tex2d(R_OGL_Tex2D *t); +internal R_OGL_Tex2D *r_ogl_tex2d_from_handle(R_Handle h); +internal R_OGL_FormatInfo r_ogl_format_info_from_tex2dformat(R_Tex2DFormat fmt); +internal GLuint r_ogl_instance_buffer_from_size(U64 size); +internal void r_ogl_debug_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); + +#define glUseProgramScope(...) DeferLoop(glUseProgram(__VA_ARGS__), glUseProgram(0)) +#define glBindVertexArrayScope(...) DeferLoop(glBindVertexArray(__VA_ARGS__), glBindVertexArray(0)) + +//////////////////////////////// +//~ rjf: OS-Specific Hooks + +internal VoidProc *r_ogl_os_load_procedure(char *name); +internal void r_ogl_os_init(CmdLine *cmdln); +internal R_Handle r_ogl_os_window_equip(OS_Handle window); +internal void r_ogl_os_window_unequip(OS_Handle os, R_Handle r); +internal void r_ogl_os_select_window(OS_Handle os, R_Handle r); +internal void r_ogl_os_window_swap(OS_Handle os, R_Handle r); + +#endif // RENDER_OPENGL_H diff --git a/src/render/opengl/render_opengl.mdesk b/src/render/opengl/render_opengl.mdesk new file mode 100644 index 00000000..d96874cd --- /dev/null +++ b/src/render/opengl/render_opengl.mdesk @@ -0,0 +1,292 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Shader Table + +@table(name name_lower input_atts output_atts) +R_OGL_ShaderTable: +{ + {Rect rect r_ogl_rect_input_attributes r_ogl_single_color_output_attributes} + {Blur blur 0 r_ogl_single_color_output_attributes} +} + +@enum R_OGL_ShaderKind: +{ + @expand(R_OGL_ShaderTable a) `$(a.name)`, + COUNT +} + +@data(String8) r_ogl_shader_kind_name_table: +{ + @expand(R_OGL_ShaderTable a) `str8_lit_comp("$(a.name_lower)")`, +} + +@data(`String8 *`) r_ogl_shader_kind_vshad_src_table: +{ + @expand(R_OGL_ShaderTable a) `&r_ogl_$(a.name_lower)_vshad_src`, +} + +@data(`String8 *`) r_ogl_shader_kind_pshad_src_table: +{ + @expand(R_OGL_ShaderTable a) `&r_ogl_$(a.name_lower)_pshad_src`, +} + +@data(R_OGL_AttributeArray) r_ogl_shader_kind_input_attributes_table: +{ + @expand(R_OGL_ShaderTable a) `{ $(a.input_atts), $(a.input_atts != 0 -> "ArrayCount(" .. a.input_atts .. ")") }`, +} + +@data(R_OGL_AttributeArray) r_ogl_shader_kind_output_attributes_table: +{ + @expand(R_OGL_ShaderTable a) `{ $(a.output_atts), ArrayCount($(a.output_atts)) }`, +} + +//////////////////////////////// +//~ rjf: UI Rectangle Shaders + +//- rjf: vertex +@embed_string r_ogl_rect_vshad_src: +``` +#version 330 core + +in vec4 c2v_dst_rect; +in vec4 c2v_src_rect; +in vec4 c2v_colors_0; +in vec4 c2v_colors_1; +in vec4 c2v_colors_2; +in vec4 c2v_colors_3; +in vec4 c2v_corner_radii; +in vec4 c2v_style; // x: border_thickness_px, y: softness_px, z: omit_texture, w: unused + +out vec2 v2p_sdf_sample_pos; +out vec2 v2p_texcoord_pct; +out vec2 v2p_rect_half_size_px; +out vec4 v2p_tint; +out float v2p_corner_radius; +out float v2p_border_thickness; +out float v2p_softness; +out float v2p_omit_texture; + +uniform sampler2D u_tex_color; +uniform vec2 u_viewport_size_px; + +void main(void) +{ + // rjf: constants + vec2 vertices[] = vec2[](vec2(-1, -1), vec2(-1, +1), vec2(+1, -1), vec2(+1, +1)); + + // rjf: find dst position + vec2 dst_half_size = (c2v_dst_rect.zw - c2v_dst_rect.xy) / 2; + vec2 dst_center = (c2v_dst_rect.zw + c2v_dst_rect.xy) / 2; + vec2 dst_position = vertices[gl_VertexID] * dst_half_size + dst_center; + + // rjf: find src position + vec2 src_half_size = (c2v_src_rect.zw - c2v_src_rect.xy) / 2; + vec2 src_center = (c2v_src_rect.zw + c2v_src_rect.xy) / 2; + vec2 src_position = vertices[gl_VertexID] * src_half_size + src_center; + + // rjf: find color + vec4 colors[] = vec4[](c2v_colors_0, c2v_colors_1, c2v_colors_2, c2v_colors_3); + vec4 color = colors[gl_VertexID]; + + // rjf: find corner radius + float corner_radii[] = float[](c2v_corner_radii.x, c2v_corner_radii.y, c2v_corner_radii.z, c2v_corner_radii.w); + float corner_radius = corner_radii[gl_VertexID]; + + // rjf: fill outputs + vec2 dst_verts_pct = vec2(((gl_VertexID >> 1) != 1) ? 1.f : 0.f, + ((gl_VertexID & 1) != 0) ? 0.f : 1.f); + ivec2 u_tex_color_size_i = textureSize(u_tex_color, 0); + vec2 u_tex_color_size = vec2(float(u_tex_color_size_i.x), float(u_tex_color_size_i.y)); + { + gl_Position = vec4(2 * dst_position.x / u_viewport_size_px.x - 1, + 2 * (1 - dst_position.y / u_viewport_size_px.y) - 1, + 0.0, 1.0); + v2p_sdf_sample_pos = (2.f * dst_verts_pct - 1.f) * dst_half_size; + v2p_texcoord_pct = src_position / u_tex_color_size; + v2p_rect_half_size_px = dst_half_size; + v2p_tint = color; + v2p_corner_radius = corner_radius; + v2p_border_thickness = c2v_style.x; + v2p_softness = c2v_style.y; + v2p_omit_texture = c2v_style.z; + } +} +``` + +//- rjf: pixel +@embed_string r_ogl_rect_pshad_src: +``` +#version 330 core + +in vec2 v2p_sdf_sample_pos; +in vec2 v2p_texcoord_pct; +in vec2 v2p_rect_half_size_px; +in vec4 v2p_tint; +in float v2p_corner_radius; +in float v2p_border_thickness; +in float v2p_softness; +in float v2p_omit_texture; + +out vec4 final_color; + +uniform float u_opacity; +uniform sampler2D u_tex_color; +uniform mat4 u_texture_sample_channel_map; + +float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r) +{ + return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r; +} + +float linear_from_srgb_f32(float x) +{ + return x < 0.0404482362771082 ? x / 12.92 : pow((x + 0.055) / 1.055, 2.4); +} + +vec4 linear_from_srgba(vec4 v) +{ + vec4 result = vec4(linear_from_srgb_f32(v.x), + linear_from_srgb_f32(v.y), + linear_from_srgb_f32(v.z), + v.w); + return result; +} + +void main(void) +{ + // rjf: sample texture + vec4 albedo_sample = vec4(1, 1, 1, 1); + if(v2p_omit_texture < 1) + { + albedo_sample = u_texture_sample_channel_map * texture(u_tex_color, v2p_texcoord_pct); + albedo_sample = linear_from_srgba(albedo_sample); + } + + // rjf: sample for borders + float border_sdf_t = 1; + if(v2p_border_thickness > 0) + { + float border_sdf_s = rect_sdf(v2p_sdf_sample_pos, + v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f) - v2p_border_thickness, + max(v2p_corner_radius-v2p_border_thickness, 0)); + border_sdf_t = smoothstep(0, 2*v2p_softness, border_sdf_s); + } + if(border_sdf_t < 0.001f) + { + discard; + } + + // rjf: sample for corners + float corner_sdf_t = 1; + if(v2p_corner_radius > 0 || v2p_softness > 0.75f) + { + float corner_sdf_s = rect_sdf(v2p_sdf_sample_pos, + v2p_rect_half_size_px - vec2(v2p_softness*2.f, v2p_softness*2.f), + v2p_corner_radius); + corner_sdf_t = 1-smoothstep(0, 2*v2p_softness, corner_sdf_s); + } + + // rjf: form+return final color + final_color = albedo_sample; + final_color *= v2p_tint; + final_color.a *= u_opacity; + final_color.a *= corner_sdf_t; + final_color.a *= border_sdf_t; +} +``` + +//////////////////////////////// +//~ rjf: Blur Shaders + +//- rjf: vertex +@embed_string r_ogl_blur_vshad_src: +``` +#version 330 core + +uniform vec4 rect; +uniform vec4 corner_radii_px; +uniform vec2 viewport_size; +uniform uint blur_count; + +out vec2 texcoord; +out vec2 sdf_sample_pos; +out vec2 rect_half_size; +out float corner_radius; + +void main(void) +{ + vec2 vertex_positions_scrn[] = vec2[](rect.xw, + rect.xy, + rect.zw, + rect.zy); + float corner_radii_px[] = float[](corner_radii_px.y, + corner_radii_px.x, + corner_radii_px.w, + corner_radii_px.z); + vec2 cornercoords_pct = vec2((gl_VertexID >> 1) != 0 ? 1.f : 0.f, + (gl_VertexID & 1) != 0 ? 0.f : 1.f); + + vec2 vertex_position_pct = vertex_positions_scrn[gl_VertexID] / viewport_size; + vec2 vertex_position_scr = 2.f * vertex_position_pct - 1.f; + + vec2 rect_half_size = vec2((rect.z-rect.x)/2, (rect.w-rect.y)/2); + + gl_Position = vec4(vertex_position_scr.x, -vertex_position_scr.y, 0.f, 1.f); + texcoord = vertex_position_pct; + sdf_sample_pos = (2.f * cornercoords_pct - 1.f) * rect_half_size; + rect_half_size = rect_half_size - 2.f; + corner_radius = corner_radii_px[gl_VertexID]; +} +``` + +//- rjf: pixel +@embed_string r_ogl_blur_pshad_src: +``` +#version 330 core + +uniform sampler2D tex; +uniform vec4 kernel[32]; +uniform int blur_count; +uniform vec2 direction; + +in vec2 texcoord; +in vec2 sdf_sample_pos; +in vec2 rect_half_size; +in float corner_radius; + +out vec4 final_color; + +float rect_sdf(vec2 sample_pos, vec2 rect_half_size, float r) +{ + return length(max(abs(sample_pos) - rect_half_size + r, 0.0)) - r; +} + +void main(void) +{ + // rjf: blend weighted texture samples into color + vec3 color = kernel[0].x * texture(tex, texcoord).rgb; + + for(int i = 1; i < blur_count; i += 1) + { + float weight = kernel[i].x; + float offset = kernel[i].y; + color += weight * texture(tex, texcoord - offset * direction).rgb; + color += weight * texture(tex, texcoord + offset * direction).rgb; + } + + // rjf: sample for corners + float corner_sdf_s = rect_sdf(sdf_sample_pos, rect_half_size, corner_radius); + float corner_sdf_t = 1-smoothstep(0, 2, corner_sdf_s); + + // rjf: weight output color by sdf + // this is doing alpha testing, leave blurring only where mostly opaque pixels are + if(corner_sdf_t < 0.9f) + { + discard; + } + + final_color = vec4(color, 1.f); +} +``` diff --git a/src/render/opengl/win32/render_opengl_win32.c b/src/render/opengl/win32/render_opengl_win32.c new file mode 100644 index 00000000..f031758f --- /dev/null +++ b/src/render/opengl/win32/render_opengl_win32.c @@ -0,0 +1,183 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +internal VoidProc * +r_ogl_os_load_procedure(char *name) +{ + VoidProc *p = (VoidProc*)wglGetProcAddress(name); + if(p == (VoidProc*)1 || p == (VoidProc*)2 || p == (VoidProc*)3 || p == (VoidProc*)-1) + { + p = 0; + } + return p; +} + +internal void +r_ogl_os_init(CmdLine *cmdline) +{ + //- rjf: create bootstrapping window + HWND bootstrap_hwnd = 0; + { + WNDCLASSEXW wndclass = { sizeof(wndclass) }; + wndclass.lpfnWndProc = DefWindowProcW; + wndclass.hInstance = GetModuleHandle(0); + wndclass.lpszClassName = L"bootstrap-window"; + ATOM wndatom = RegisterClassExW(&wndclass); + bootstrap_hwnd = CreateWindowExW(0, L"bootstrap-window", L"", 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, 0, wndclass.hInstance, 0); + } + + //- rjf: grab dc + HDC dc = GetDC(bootstrap_hwnd); + + //- rjf: build pixel format descriptor + int pf = 0; + { + PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)}; + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + pf = ChoosePixelFormat(dc, &pfd); + BOOL describe = DescribePixelFormat(dc, pf, sizeof(pfd), &pfd); + BOOL set_pf = SetPixelFormat(dc, pf, &pfd); + } + + //- rjf: make bootstrap ctx + make current + HGLRC bootstrap_ctx = wglCreateContext(dc); + wglMakeCurrent(dc, bootstrap_ctx); + + //- rjf: load modern extensions + wglChoosePixelFormatARB = (FNWGLCHOOSEPIXELFORMATARBPROC*) r_ogl_os_load_procedure("wglChoosePixelFormatARB"); + wglCreateContextAttribsARB = (FNWGLCREATECONTEXTATTRIBSARBPROC*)r_ogl_os_load_procedure("wglCreateContextAttribsARB"); + wglSwapIntervalEXT = (FNWGLSWAPINTERVALEXTPROC*) r_ogl_os_load_procedure("wglSwapIntervalEXT"); + + //- rjf: set up real pixel format + { + int pf_attribs_i[] = + { + WGL_DRAW_TO_WINDOW_ARB, 1, + WGL_SUPPORT_OPENGL_ARB, 1, + WGL_DOUBLE_BUFFER_ARB, 1, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 32, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0 + }; + UINT num_formats = 0; + wglChoosePixelFormatARB(dc, pf_attribs_i, 0, 1, &pf, &num_formats); + } + + //- rjf: make real gl ctx + HGLRC real_ctx = 0; + if(pf) + { + B32 debug_mode = cmd_line_has_flag(cmdline, str8_lit("opengl_debug")); +#if BUILD_DEBUG + debug_mode = 1; +#endif + int context_attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, + WGL_CONTEXT_MINOR_VERSION_ARB, 3, + WGL_CONTEXT_FLAGS_ARB, !!debug_mode*WGL_CONTEXT_DEBUG_BIT_ARB, + 0 + }; + real_ctx = wglCreateContextAttribsARB(dc, bootstrap_ctx, context_attribs); + r_ogl_w32_hglrc = real_ctx; + } + + //- rjf: clean up bootstrap context + wglMakeCurrent(dc, 0); + wglDeleteContext(bootstrap_ctx); + wglMakeCurrent(dc, real_ctx); + wglSwapIntervalEXT(1); +} + +internal R_Handle +r_ogl_os_window_equip(OS_Handle window) +{ + //- rjf: unpack window + OS_W32_Window *w = os_w32_window_from_handle(window); + HWND hwnd = w->hwnd; + HDC hdc = w->hdc; + + //- rjf: select in ctx + wglMakeCurrent(hdc, r_ogl_w32_hglrc); + + //- rjf: setup real pixel format + int pixel_format = 0; + UINT num_formats = 0; + int pf_attribs_i[] = + { + WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, + WGL_SUPPORT_OPENGL_ARB, GL_TRUE, + WGL_DOUBLE_BUFFER_ARB, GL_TRUE, + WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, + WGL_COLOR_BITS_ARB, 32, + WGL_DEPTH_BITS_ARB, 24, + WGL_STENCIL_BITS_ARB, 8, + 0 + }; + wglChoosePixelFormatARB(hdc, + pf_attribs_i, + 0, + 1, + &pixel_format, + &num_formats); + + // NOTE(rjf): This doesn't seem to be necessary for SetPixelFormat, we can + // just pass 0 for it, and SetPixelFormat needs to be called here, but the + // docs don't seem to suggest that 0 is an acceptable value, so I am just + // filling this out with the same attribs as that for the wgl function, + // and passing it. + PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)}; + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + + //- rjf: set pixel format + SetPixelFormat(hdc, pixel_format, &pfd); + + //- rjf: release hdc + R_Handle result = {0}; + return result; +} + +internal void +r_ogl_os_window_unequip(OS_Handle os, R_Handle r) +{ +} + +internal void +r_ogl_os_select_window(OS_Handle os, R_Handle r) +{ + OS_W32_Window *w = os_w32_window_from_handle(os); + if(w != 0) + { + HWND hwnd = w->hwnd; + HDC hdc = w->hdc; + wglMakeCurrent(hdc, r_ogl_w32_hglrc); + } +} + +internal void +r_ogl_os_window_swap(OS_Handle os, R_Handle r) +{ + OS_W32_Window *w = os_w32_window_from_handle(os); + if(w != 0) + { + HDC dc = w->hdc; + SwapBuffers(dc); + } +} diff --git a/src/render/opengl/win32/render_opengl_win32.h b/src/render/opengl/win32/render_opengl_win32.h new file mode 100644 index 00000000..24e53c14 --- /dev/null +++ b/src/render/opengl/win32/render_opengl_win32.h @@ -0,0 +1,34 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RENDER_OPENGL_WIN32_H +#define RENDER_OPENGL_WIN32_H + +#include +#pragma comment(lib, "opengl32") + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 + +typedef BOOL WINAPI FNWGLCHOOSEPIXELFORMATARBPROC(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +typedef HGLRC WINAPI FNWGLCREATECONTEXTATTRIBSARBPROC(HDC hDC, HGLRC hShareContext, const int *attribList); +typedef BOOL WINAPI FNWGLSWAPINTERVALEXTPROC(int interval); + +FNWGLCHOOSEPIXELFORMATARBPROC *wglChoosePixelFormatARB; +FNWGLCREATECONTEXTATTRIBSARBPROC *wglCreateContextAttribsARB; +FNWGLSWAPINTERVALEXTPROC *wglSwapIntervalEXT; + +global HGLRC r_ogl_w32_hglrc = 0; + +#endif // RENDER_OPENGL_WIN32_H diff --git a/src/render/render_core.c b/src/render/render_core.c index 4d6ebdf7..80ca84bf 100644 --- a/src/render/render_core.c +++ b/src/render/render_core.c @@ -6,6 +6,33 @@ #include "generated/render.meta.c" +//////////////////////////////// +//~ rjf: Helpers + +internal Mat4x4F32 +r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt) +{ + Mat4x4F32 result = + { + { + {1, 0, 0, 0}, + {0, 1, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 1}, + } + }; + switch(fmt) + { + default:{}break; + case R_Tex2DFormat_R8: + { + MemoryZeroArray(result.v[0]); + result.v[0][0] = result.v[0][1] = result.v[0][2] = result.v[0][3] = 1.f; + }break; + } + return result; +} + //////////////////////////////// //~ rjf: Basic Type Functions diff --git a/src/render/render_core.h b/src/render/render_core.h index a7ef99c9..7725c5a3 100644 --- a/src/render/render_core.h +++ b/src/render/render_core.h @@ -194,6 +194,11 @@ struct R_PassList U64 count; }; +//////////////////////////////// +//~ rjf: Helpers + +internal Mat4x4F32 r_sample_channel_map_from_tex2dformat(R_Tex2DFormat fmt); + //////////////////////////////// //~ rjf: Handle Type Functions diff --git a/src/render/render_inc.c b/src/render/render_inc.c index 84612fa8..bb15be84 100644 --- a/src/render/render_inc.c +++ b/src/render/render_inc.c @@ -1,12 +1,17 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xc22121ff + #include "render_core.c" #if R_BACKEND == R_BACKEND_STUB # include "stub/render_stub.c" #elif R_BACKEND == R_BACKEND_D3D11 # include "d3d11/render_d3d11.c" +#elif R_BACKEND == R_BACKEND_OPENGL +# include "opengl/render_opengl.c" #else # error Renderer backend not specified. #endif diff --git a/src/render/render_inc.h b/src/render/render_inc.h index 64802e5c..d0e87c3c 100644 --- a/src/render/render_inc.h +++ b/src/render/render_inc.h @@ -9,12 +9,15 @@ #define R_BACKEND_STUB 0 #define R_BACKEND_D3D11 1 +#define R_BACKEND_OPENGL 2 //////////////////////////////// //~ rjf: Decide On Backend #if !defined(R_BACKEND) && OS_WINDOWS # define R_BACKEND R_BACKEND_D3D11 +#elif !defined(R_BACKEND) && OS_LINUX +# define R_BACKEND R_BACKEND_OPENGL #endif //////////////////////////////// @@ -29,6 +32,8 @@ # include "stub/render_stub.h" #elif R_BACKEND == R_BACKEND_D3D11 # include "d3d11/render_d3d11.h" +#elif R_BACKEND == R_BACKEND_OPENGL +# include "opengl/render_opengl.h" #else # error Renderer backend not specified. #endif diff --git a/src/scratch/eval_scratch.c b/src/scratch/eval_scratch.c new file mode 100644 index 00000000..233a773b --- /dev/null +++ b/src/scratch/eval_scratch.c @@ -0,0 +1,51 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "rdi_format/rdi_format_local.h" +#include "regs/regs.h" +#include "regs/rdi/regs_rdi.h" +#include "eval/eval_inc.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "rdi_format/rdi_format_local.c" +#include "regs/regs.c" +#include "regs/rdi/regs_rdi.c" +#include "eval/eval_inc.c" + +//////////////////////////////// +//~ rjf: Entry Point + +internal void +entry_point(CmdLine *cmdline) +{ + Arena *arena = arena_alloc(); + E_TypeCtx *type_ctx = push_array(arena, E_TypeCtx, 1); + e_select_type_ctx(type_ctx); + E_ParseCtx *parse_ctx = push_array(arena, E_ParseCtx, 1); + e_select_parse_ctx(parse_ctx); + E_IRCtx *ir_ctx = push_array(arena, E_IRCtx, 1); + e_select_ir_ctx(ir_ctx); + E_InterpretCtx *interpret_ctx = push_array(arena, E_InterpretCtx, 1); + e_select_interpret_ctx(interpret_ctx, 0, 0); + String8 exprs[] = + { + str8_lit("123"), + str8_lit("1 + 2"), + str8_lit("foo"), + str8_lit("foo(bar)"), + str8_lit("foo(bar(baz))"), + }; + for EachElement(idx, exprs) + { + String8 debug_string = e_debug_log_from_expr_string(arena, exprs[idx]); + raddbg_log("%S", debug_string); + } +} diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 317413f3..48b3a3fc 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -10,37 +10,27 @@ //////////////////////////////// //~ rjf: Includes -//- rjf: [lib] -#include "lib_rdi_format/rdi_format.h" -#include "lib_rdi_format/rdi_format.c" -#include "third_party/rad_lzb_simple/rad_lzb_simple.h" -#include "third_party/rad_lzb_simple/rad_lzb_simple.c" - //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" -#include "rdi_make/rdi_make_local.h" -#include "coff/coff.h" -#include "codeview/codeview.h" -#include "codeview/codeview_stringize.h" -#include "msf/msf.h" -#include "msf/msf_parse.h" -#include "pdb/pdb.h" -#include "pdb/pdb_parse.h" -#include "pdb/pdb_stringize.h" +#include "render/render_inc.h" +#include "font_provider/font_provider_inc.h" +#include "font_cache/font_cache.h" +#include "draw/draw.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" -#include "rdi_make/rdi_make_local.c" -#include "coff/coff.c" -#include "codeview/codeview.c" -#include "codeview/codeview_stringize.c" -#include "msf/msf.c" -#include "msf/msf_parse.c" -#include "pdb/pdb.c" -#include "pdb/pdb_parse.c" -#include "pdb/pdb_stringize.c" +#include "render/render_inc.c" +#include "font_provider/font_provider_inc.c" +#include "font_cache/font_cache.c" +#include "draw/draw.c" + +//////////////////////////////// +//~ rjf: Globals + +global OS_Handle window_os = {0}; +global R_Handle window_r = {0}; //////////////////////////////// //~ rjf: Entry Points @@ -50,6 +40,8 @@ frame(void) { B32 quit = 0; Temp scratch = scratch_begin(0, 0); + + //- rjf: events test OS_EventList events = os_get_events(scratch.arena, 0); for(OS_Event *ev = events.first; ev != 0; ev = ev->next) { @@ -57,12 +49,12 @@ frame(void) { String8 string = push_str8f(scratch.arena, "%S (%S)\n", os_string_from_event_kind(ev->kind), os_g_key_display_string_table[ev->key]); printf("%.*s", str8_varg(string)); - OutputDebugStringA((char *)string.str); + raddbg_log((char *)string.str); fflush(stdout); } if(ev->kind == OS_EventKind_Press && ev->key == OS_Key_X) { - *(int *)0 = 0; + *(volatile int *)0 = 0; } } for(OS_Event *ev = events.first; ev != 0; ev = ev->next) @@ -73,6 +65,32 @@ frame(void) break; } } + + //- rjf: drawing test + r_begin_frame(); + r_window_begin_frame(window_os, window_r); + { + R_PassList passes = {0}; + R_Pass *pass = r_pass_from_kind(scratch.arena, &passes, R_PassKind_UI); + R_PassParams_UI *pass_ui = pass->params_ui; + R_BatchGroup2DNode group = {0}; + pass_ui->rects.first = pass_ui->rects.last = &group; + pass_ui->rects.count = 1; + group.batches = r_batch_list_make(sizeof(R_Rect2DInst)); + group.params.xform = mat_3x3f32(1.f); + group.params.clip = os_client_rect_from_window(window_os); + Vec2F32 mouse = os_mouse_from_window(window_os); + R_Rect2DInst *inst = r_batch_list_push_inst(scratch.arena, &group.batches, 256); + MemoryZeroStruct(inst); + inst->dst = r2f32p(mouse.x+30, mouse.y+30, mouse.x+100, mouse.y+100); + inst->src = r2f32p(0, 0, 1, 1); + inst->colors[Corner_00] = inst->colors[Corner_01] = inst->colors[Corner_10] = inst->colors[Corner_11] = v4f32(1, 0, 0, 1); + inst->corner_radii[Corner_00] = inst->corner_radii[Corner_01] = inst->corner_radii[Corner_10] = inst->corner_radii[Corner_11] = 8.f; + r_window_submit(window_os, window_r, &passes); + } + r_window_end_frame(window_os, window_r); + r_end_frame(); + scratch_end(scratch); return quit; } @@ -80,7 +98,8 @@ frame(void) internal void entry_point(CmdLine *cmdline) { - OS_Handle window = os_window_open(v2f32(1280, 720), 0, str8_lit("Window")); - os_window_first_paint(window); + window_os = os_window_open(r2f32p(0, 0, 1280, 720), OS_WindowFlag_UseDefaultPosition, str8_lit("Window")); + os_window_first_paint(window_os); + window_r = r_window_equip(window_os); for(;!update();); } diff --git a/src/scratch/textperf.c b/src/scratch/textperf.c index c9e3792e..b252b9e1 100644 --- a/src/scratch/textperf.c +++ b/src/scratch/textperf.c @@ -51,7 +51,7 @@ frame(void) } } r_begin_frame(); - dr_begin_frame(); + dr_begin_frame(fnt_tag_zero()); r_window_begin_frame(os_window, r_window); DR_Bucket *bucket = dr_bucket_make(); DR_BucketScope(bucket) ProfScope("draw") @@ -77,7 +77,7 @@ frame(void) internal void entry_point(CmdLine *cmdline) { - os_window = os_window_open(v2f32(1600, 900), 0, str8_lit("textperf")); + os_window = os_window_open(r2f32p(0, 0, 1600, 900), OS_WindowFlag_UseDefaultPosition, str8_lit("textperf")); r_window = r_window_equip(os_window); os_window_first_paint(os_window); for(;!update();); diff --git a/src/strip_lib_debug/strip_lib_debug.c b/src/strip_lib_debug/strip_lib_debug.c new file mode 100644 index 00000000..6cae4820 --- /dev/null +++ b/src/strip_lib_debug/strip_lib_debug.c @@ -0,0 +1,116 @@ +// Copyright (c) 2025 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#define BUILD_TITLE "Epic Games Tools (R) Lib Strip Debug" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +// Headers + +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "coff/coff.h" +#include "coff/coff_parse.h" + +//////////////////////////////// +// Implementations + +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "coff/coff.c" +#include "coff/coff_parse.c" + +internal void +sld_main(CmdLine *cmdl) +{ + B32 do_help = cmd_line_has_flag(cmdl, str8_lit("help")) || + cmd_line_has_flag(cmdl, str8_lit("h")) || + cmd_line_has_flag(cmdl, str8_lit("?")) || + cmdl->argc == 1; + if (do_help) { fprintf(stderr, "--- Help ---------------------------------------------------------------------\n"); + fprintf(stderr, " %s\n\n", BUILD_TITLE_STRING_LITERAL); + fprintf(stderr, " Usage: strip_lib_debug [Options]\n\n"); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -in: Path to input lib file\n"); + fprintf(stderr, " -out: Path to output lib file\n"); + os_abort(0); + } + + Temp scratch = scratch_begin(0,0); + + String8 in_lib_path = cmd_line_string(cmdl, str8_lit("in")); + String8 out_lib_path = cmd_line_string(cmdl, str8_lit("out")); + + if (in_lib_path.size == 0) { + fprintf(stderr, "ERROR: please provide an input path via -in:\n"); + os_abort(1); + } + if (out_lib_path.size == 0) { + fprintf(stderr, "ERROR: please provide an output path via -out:\n"); + os_abort(1); + } + + String8 in_lib = os_data_from_file_path(scratch.arena, in_lib_path); + if (in_lib.size == 0) { + fprintf(stderr, "ERROR: unable to read file %.*s\n", str8_varg(in_lib_path)); + os_abort(1); + } + + if (!coff_is_regular_archive(in_lib)) { + fprintf(stderr, "ERROR: input lib is not COFF archive\n"); + os_abort(1); + } + + // read & parse lib + String8 out_lib = push_str8_copy(scratch.arena, in_lib); + COFF_ArchiveParse parse = coff_archive_parse_from_data(out_lib); + + // was parse successful? + if (parse.error.size) { + fprintf(stderr, "ERROR: %.*s: %.*s\n", str8_varg(in_lib_path), str8_varg(parse.error)); + os_abort(1); + } + + // convert big endian offsets + U32 member_offsets_count = parse.first_member.symbol_count; + U32 *member_offsets = push_array(scratch.arena, U32, parse.first_member.member_offset_count); + for (U32 offset_idx = 0; offset_idx < member_offsets_count; offset_idx += 1) { + member_offsets[offset_idx] = from_be_u32(parse.first_member.member_offsets[offset_idx]); + } + + // fixup sections + for (U64 member_idx = 0; member_idx < member_offsets_count; member_idx += 1) { + COFF_ParsedArchiveMemberHeader member_header = {0}; + coff_parse_archive_member_header(out_lib, member_offsets[member_idx], &member_header); + String8 member_data = str8_substr(out_lib, member_header.data_range); + COFF_DataType member_type = coff_data_type_from_data(member_data); + if (member_type == COFF_DataType_BigObj || member_type == COFF_DataType_Obj) { + COFF_FileHeaderInfo file_header_info = coff_file_header_info_from_data(member_data); + COFF_SectionHeader *section_table = (COFF_SectionHeader *)str8_substr(member_data, file_header_info.section_table_range).str; + String8 string_table = str8_substr(member_data, file_header_info.string_table_range); + for (U64 sect_idx = 0; sect_idx < file_header_info.section_count_no_null; sect_idx += 1) { + COFF_SectionHeader *sect_header = §ion_table[sect_idx]; + String8 name = coff_name_from_section_header(string_table, sect_header); + if (str8_match(str8_lit(".debug$S"), name, 0) || str8_match(str8_lit(".debug$T"), name, 0)) { + sect_header->flags = COFF_SectionFlag_LnkRemove; + MemorySet(sect_header->name, 'x', sizeof(sect_header->name)); + } + } + } + } + + // wirte modified library + if (!os_write_data_to_file_path(out_lib_path, out_lib)) { + fprintf(stderr, "ERROR: unable to write output file to %.*s\n", str8_varg(out_lib_path)); + os_abort(1); + } + + scratch_end(scratch); +} + +internal void +entry_point(CmdLine *cmdl) +{ + sld_main(cmdl); +} + diff --git a/src/tester/tester_main.c b/src/tester/tester_main.c index c62ea4f1..45b3e61f 100644 --- a/src/tester/tester_main.c +++ b/src/tester/tester_main.c @@ -16,12 +16,20 @@ #include "os/os_inc.h" #include "path/path.h" #include "hash_store/hash_store.h" +#include "rdi_format/rdi_format_local.h" +#include "regs/regs.h" +#include "regs/rdi/regs_rdi.h" +#include "eval/eval_inc.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "path/path.c" #include "hash_store/hash_store.c" +#include "rdi_format/rdi_format_local.c" +#include "regs/regs.c" +#include "regs/rdi/regs_rdi.c" +#include "eval/eval_inc.c" //////////////////////////////// //~ rjf: Entry Points @@ -32,6 +40,14 @@ internal void entry_point(CmdLine *cmdline) { Arena *arena = arena_alloc(); + E_TypeCtx *type_ctx = push_array(arena, E_TypeCtx, 1); + e_select_type_ctx(type_ctx); + E_ParseCtx *parse_ctx = push_array(arena, E_ParseCtx, 1); + e_select_parse_ctx(parse_ctx); + E_IRCtx *ir_ctx = push_array(arena, E_IRCtx, 1); + e_select_ir_ctx(ir_ctx); + E_InterpretCtx *interpret_ctx = push_array(arena, E_InterpretCtx, 1); + e_select_interpret_ctx(interpret_ctx, 0, 0); ////////////////////////////// //- rjf: unpack command line @@ -49,14 +65,31 @@ entry_point(CmdLine *cmdline) String8 artifacts_path = path_normalized_from_string(arena, str8_lit("./tester_artifacts")); os_make_directory(artifacts_path); + ////////////////////////////// + //- rjf: set up list of test artifacts + // + typedef struct Test Test; + struct Test + { + Test *next; + String8 name; + String8List out; + B32 good; + }; + Test *first_test = 0; + Test *last_test = 0; +#define Test(name_identifier) \ +Test *test_##name_identifier = push_array(arena, Test, 1);\ +test_##name_identifier->name = str8_lit(#name_identifier);\ +test_##name_identifier->good = 1;\ +SLLQueuePush(first_test, last_test, test_##name_identifier);\ +for(Test *test = test_##name_identifier; test != 0; test = 0) + ////////////////////////////// //- rjf: PDB -> RDI determinism // - String8 name = {0}; - B32 good = 1; - String8List out = {0}; + Test(pdb2rdi_determinism) { - name = str8_lit("pdb2rdi_determinism"); U64 num_repeats_per_pdb = 32; String8 pdb_paths[] = { @@ -67,7 +100,7 @@ entry_point(CmdLine *cmdline) { // rjf: unpack paths, make output directory String8 pdb_path = path_normalized_from_string(arena, pdb_paths[pdb_idx]); - String8 repeat_folder = push_str8f(arena, "%S/%S", artifacts_path, name); + String8 repeat_folder = push_str8f(arena, "%S/%S", artifacts_path, test->name); os_make_directory(repeat_folder); // rjf: generate all RDIs @@ -157,29 +190,72 @@ entry_point(CmdLine *cmdline) // rjf: output bad case info if(!matches) { - good = 0; - str8_list_pushf(arena, &out, " pdb[%I64u] \"%S\"\n", pdb_idx, pdb_path); + test->good = 0; + str8_list_pushf(arena, &test->out, " pdb[%I64u] \"%S\"\n", pdb_idx, pdb_path); for EachIndex(idx, rdi_hashes_count) { - str8_list_pushf(arena, &out, " rdi[%I64u] \"%S\": 0x%I64x:%I64x\n", idx, rdi_paths_array[idx], rdi_hashes[idx].u64[0], rdi_hashes[idx].u64[1]); + str8_list_pushf(arena, &test->out, " rdi[%I64u] \"%S\": 0x%I64x:%I64x\n", idx, rdi_paths_array[idx], rdi_hashes[idx].u64[0], rdi_hashes[idx].u64[1]); } for EachIndex(idx, dump_hashes_count) { - str8_list_pushf(arena, &out, " dump[%I64u] \"%S\": 0x%I64x:%I64x\n", idx, dump_paths_array[idx], dump_hashes[idx].u64[0], dump_hashes[idx].u64[1]); + str8_list_pushf(arena, &test->out, " dump[%I64u] \"%S\": 0x%I64x:%I64x\n", idx, dump_paths_array[idx], dump_hashes[idx].u64[0], dump_hashes[idx].u64[1]); } } } } + ////////////////////////////// + //- rjf: eval compiler basics + // + Test(eval_compiler_basics) + { + String8 exprs[] = + { + str8_lit("123"), + str8_lit("1 + 2"), + str8_lit("foo"), + str8_lit("foo(bar)"), + str8_lit("foo(bar(baz))"), + }; + String8List logs = {0}; + for EachElement(idx, exprs) + { + String8 log = e_debug_log_from_expr_string(arena, exprs[idx]); + str8_list_push(arena, &logs, log); + } + String8 log = str8_list_join(arena, &logs, 0); + String8 test_artifacts_path = push_str8f(arena, "%S/%S", artifacts_path, test->name); + os_make_directory(test_artifacts_path); + String8 current_file_path = push_str8f(arena, "%S/current.txt", test_artifacts_path); + String8 correct_file_path = push_str8f(arena, "%S/%S/correct.txt", test_data_folder_path, test->name); + os_write_data_to_file_path(current_file_path, log); + String8 current_file_data = log; + String8 correct_file_data = os_data_from_file_path(arena, correct_file_path); + test->good = str8_match(correct_file_data, current_file_data, 0); + } + ////////////////////////////// //- rjf: dump results // - fprintf(stderr, "[%s] \"%.*s\"\n", good ? "." : "X", str8_varg(name)); - if(!good) + B32 all_good = 1; + for(Test *t = first_test; t != 0; t = t->next) { - for(String8Node *n = out.first; n != 0; n = n->next) + if(!t->good) { - fprintf(stderr, "%.*s", str8_varg(n->string)); + all_good = 0; + break; + } + } + fprintf(stderr, "[%s]\n", all_good ? "." : "X"); + for(Test *t = first_test; t != 0; t = t->next) + { + fprintf(stderr, " [%s] \"%.*s\"\n", t->good ? "." : "X", str8_varg(t->name)); + if(!t->good) + { + for(String8Node *n = t->out.first; n != 0; n = n->next) + { + fprintf(stderr, " %.*s", str8_varg(n->string)); + } } } diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 377ee516..29200950 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xe34cd4ff + //////////////////////////////// //~ rjf: Basic Helpers @@ -259,7 +262,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S }break; case TXT_TokenKind_Identifier: { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$' && byte < 128); }break; case TXT_TokenKind_Numeric: { @@ -603,7 +606,7 @@ txt_token_array_from_string__odin(Arena *arena, U64 *bytes_processed_counter, St }break; case TXT_TokenKind_Identifier: { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$' && byte < 128); }break; case TXT_TokenKind_Numeric: { @@ -889,7 +892,7 @@ txt_token_array_from_string__jai(Arena *arena, U64 *bytes_processed_counter, Str }break; case TXT_TokenKind_Identifier: { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$' && byte < 128); }break; case TXT_TokenKind_Numeric: { @@ -1174,7 +1177,7 @@ txt_token_array_from_string__zig(Arena *arena, U64 *bytes_processed_counter, Str }break; case TXT_TokenKind_Identifier: { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$' && byte < 128); }break; case TXT_TokenKind_Numeric: { @@ -1768,7 +1771,7 @@ txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) } internal TXT_TextInfo -txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out) +txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out) { TXT_TextInfo result = {0}; for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) @@ -2313,6 +2316,7 @@ ASYNC_WORK_DEF(txt_parse_work) { if(u128_match(n->hash, hash) && n->lang == lang) { + hs_hash_downstream_inc(n->hash); n->arena = info_arena; info.bytes_processed = n->info.bytes_processed; info.bytes_to_process = n->info.bytes_to_process; @@ -2340,7 +2344,7 @@ txt_evictor_thread__entry_point(void *p) { U64 check_time_us = os_now_microseconds(); U64 check_time_user_clocks = update_tick_idx(); - U64 evict_threshold_us = 10*1000000; + U64 evict_threshold_us = 2*1000000; U64 evict_threshold_user_clocks = 10; for(U64 slot_idx = 0; slot_idx < txt_shared->slots_count; slot_idx += 1) { @@ -2375,6 +2379,7 @@ txt_evictor_thread__entry_point(void *p) n->is_working == 0) { DLLRemove(slot->first, slot->last, n); + hs_hash_downstream_dec(n->hash); if(n->arena != 0) { arena_release(n->arena); @@ -2383,8 +2388,7 @@ txt_evictor_thread__entry_point(void *p) } } } - os_sleep_milliseconds(5); } - os_sleep_milliseconds(1000); + os_sleep_milliseconds(500); } } diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 2311139e..143a7b75 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -274,7 +274,7 @@ internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node //~ rjf: Cache Lookups internal TXT_TextInfo txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang); -internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out); +internal TXT_TextInfo txt_text_info_from_key_lang(TXT_Scope *scope, HS_Key key, TXT_LangKind lang, U128 *hash_out); //////////////////////////////// //~ rjf: Text Info Extractor Helpers diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 8a663a5c..8bc7e657 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -1,6 +1,9 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#undef LAYER_COLOR +#define LAYER_COLOR 0xe34cd4ff + //////////////////////////////// //~ rjf: Basic Helpers @@ -193,7 +196,7 @@ tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topolog } internal R_Handle -tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out) +tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out) { R_Handle handle = {0}; for(U64 rewind_idx = 0; rewind_idx < HS_KEY_HASH_HISTORY_COUNT; rewind_idx += 1) diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 617618dd..25a00be1 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -135,7 +135,7 @@ internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node //~ rjf: Cache Lookups internal R_Handle tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology); -internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology, U128 *hash_out); +internal R_Handle tex_texture_from_key_topology(TEX_Scope *scope, HS_Key key, TEX_Topology topology, U128 *hash_out); //////////////////////////////// //~ rjf: Transfer Threads diff --git a/src/third_party/sinfl/sinfl.h b/src/third_party/sinfl/sinfl.h new file mode 100644 index 00000000..8075a12d --- /dev/null +++ b/src/third_party/sinfl/sinfl.h @@ -0,0 +1,618 @@ +// NOTE: +// - updated library to handle 64-bit inputs +// - fixed a bug where on decomp would exit on blocks with zero length + +/* +# Small Deflate +`sdefl` is a small bare bone lossless compression library in ANSI C (ISO C90) +which implements the Deflate (RFC 1951) compressed data format specification standard. +It is mainly tuned to get as much speed and compression ratio from as little code +as needed to keep the implementation as concise as possible. + +## Features +- Portable single header and source file duo written in ANSI C (ISO C90) +- Dual license with either MIT or public domain +- Small implementation + - Deflate: 525 LoC + - Inflate: 500 LoC +- Webassembly: + - Deflate ~3.7 KB (~2.2KB compressed) + - Inflate ~3.6 KB (~2.2KB compressed) + +## Usage: +This file behaves differently depending on what symbols you define +before including it. + +Header-File mode: +If you do not define `SINFL_IMPLEMENTATION` before including this file, it +will operate in header only mode. In this mode it declares all used structs +and the API of the library without including the implementation of the library. + +Implementation mode: +If you define `SINFL_IMPLEMENTATION` before including this file, it will +compile the implementation. Make sure that you only include +this file implementation in *one* C or C++ file to prevent collisions. + +### Benchmark + +| Compressor name | Compression| Decompress.| Compr. size | Ratio | +| ------------------------| -----------| -----------| ----------- | ----- | +| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 | +| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 | +| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 | +| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 | +| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 | +| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 | +| sdefl 1.0 -0 | 127 MB/s | 355 MB/s | 40004116 | 39.88 | +| sdefl 1.0 -1 | 111 MB/s | 413 MB/s | 38940674 | 38.82 | +| sdefl 1.0 -5 | 45 MB/s | 436 MB/s | 36577183 | 36.46 | +| sdefl 1.0 -7 | 38 MB/s | 432 MB/s | 36523781 | 36.41 | +| libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 | +| libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 | +| libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 | +| libdeflate 1.3 -12 | 8.13 MB/s | 670 MB/s | 35100568 | 35.10 | + +### Compression +Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia): + +| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` | +| --------| -----------| -------------| ---------- | ------------| +| dickens | 10.192.446 | 4,260,187 | 3,845,261 | 3,833,657 | +| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 | +| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 | +| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 | +| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 | +| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 | +| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 | +| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 | +| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 | +| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 | +| xml | 5.345.280 | 886,620 | 674,009 | 662,141 | +| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 | + +## License +``` +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2020-2023 Micha Mettke +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +``` +*/ +#ifndef SINFL_H_INCLUDED +#define SINFL_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define SINFL_PRE_TBL_SIZE 128 +#define SINFL_LIT_TBL_SIZE 1334 +#define SINFL_OFF_TBL_SIZE 402 + +struct sinfl { + const unsigned char *bitptr; + unsigned long long bitbuf; + int bitcnt; + + unsigned lits[SINFL_LIT_TBL_SIZE]; + unsigned dsts[SINFL_OFF_TBL_SIZE]; +}; +extern size_t sinflate(void *out, size_t cap, const void *in, size_t size); +extern size_t zsinflate(void *out, size_t cap, const void *in, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* SINFL_H_INCLUDED */ + +#ifdef SINFL_IMPLEMENTATION + +#include /* memcpy, memset */ +#include /* assert */ + +#if defined(__GNUC__) || defined(__clang__) +#define sinfl_likely(x) __builtin_expect((x),1) +#define sinfl_unlikely(x) __builtin_expect((x),0) +#else +#define sinfl_likely(x) (x) +#define sinfl_unlikely(x) (x) +#endif + +#ifndef SINFL_NO_SIMD +#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64) + #include + #define sinfl_char16 uint8x16_t + #define sinfl_char16_ld(p) vld1q_u8((const unsigned char*)(p)) + #define sinfl_char16_str(d, v) vst1q_u8((unsigned char*)(d), v) + #define sinfl_char16_char(c) vdupq_n_u8(c) +#elif defined(__x86_64__) || defined(_WIN32) || defined(_WIN64) + #include + #define sinfl_char16 __m128i + #define sinfl_char16_ld(p) _mm_loadu_si128((const __m128i *)(void*)(p)) + #define sinfl_char16_str(d,v) _mm_storeu_si128((__m128i*)(void*)(d), v) + #define sinfl_char16_char(c) _mm_set1_epi8(c) +#else + #define SINFL_NO_SIMD +#endif +#endif + +static int +sinfl_bsr(unsigned n) { +#ifdef _MSC_VER + unsigned long r = 0; + _BitScanReverse(&r, n); + return (int)r; +#elif defined(__GNUC__) || defined(__clang__) + return 31 - __builtin_clz(n); +#endif +} +static unsigned long long +sinfl_read64(const void *p) { + unsigned long long n; + memcpy(&n, p, 8); + return n; +} +static void +sinfl_copy64(unsigned char **dst, unsigned char **src) { + unsigned long long n; + memcpy(&n, *src, 8); + memcpy(*dst, &n, 8); + *dst += 8, *src += 8; +} +static unsigned char* +sinfl_write64(unsigned char *dst, unsigned long long w) { + memcpy(dst, &w, 8); + return dst + 8; +} +#ifndef SINFL_NO_SIMD +static unsigned char* +sinfl_write128(unsigned char *dst, sinfl_char16 w) { + sinfl_char16_str(dst, w); + return dst + 8; +} +static void +sinfl_copy128(unsigned char **dst, unsigned char **src) { + sinfl_char16 n = sinfl_char16_ld(*src); + sinfl_char16_str(*dst, n); + *dst += 16, *src += 16; +} +#endif +static void +sinfl_refill(struct sinfl *s) { + s->bitbuf |= sinfl_read64(s->bitptr) << s->bitcnt; + s->bitptr += (63 - s->bitcnt) >> 3; + s->bitcnt |= 56; /* bitcount in range [56,63] */ +} +static int +sinfl_peek(struct sinfl *s, int cnt) { + assert(cnt >= 0 && cnt <= 56); + assert(cnt <= s->bitcnt); + return s->bitbuf & ((1ull << cnt) - 1); +} +static void +sinfl_eat(struct sinfl *s, int cnt) { + assert(cnt <= s->bitcnt); + s->bitbuf >>= cnt; + s->bitcnt -= cnt; +} +static int +sinfl__get(struct sinfl *s, int cnt) { + int res = sinfl_peek(s, cnt); + sinfl_eat(s, cnt); + return res; +} +static int +sinfl_get(struct sinfl *s, int cnt) { + sinfl_refill(s); + return sinfl__get(s, cnt); +} +struct sinfl_gen { + int len; + int cnt; + int word; + short* sorted; +}; +static int +sinfl_build_tbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, + const int *cnt) { + int tbl_end = 0; + while (!(gen->cnt = cnt[gen->len])) { + ++gen->len; + } + tbl_end = 1 << gen->len; + while (gen->len <= tbl_bits) { + do {unsigned bit = 0; + tbl[gen->word] = (*gen->sorted++ << 16) | gen->len; + if (gen->word == tbl_end - 1) { + for (; gen->len < tbl_bits; gen->len++) { + memcpy(&tbl[tbl_end], tbl, (size_t)tbl_end * sizeof(tbl[0])); + tbl_end <<= 1; + } + return 1; + } + bit = 1 << sinfl_bsr((unsigned)(gen->word ^ (tbl_end - 1))); + gen->word &= bit - 1; + gen->word |= bit; + } while (--gen->cnt); + do { + if (++gen->len <= tbl_bits) { + memcpy(&tbl[tbl_end], tbl, (size_t)tbl_end * sizeof(tbl[0])); + tbl_end <<= 1; + } + } while (!(gen->cnt = cnt[gen->len])); + } + return 0; +} +static void +sinfl_build_subtbl(struct sinfl_gen *gen, unsigned *tbl, int tbl_bits, + const int *cnt) { + int sub_bits = 0; + int sub_start = 0; + int sub_prefix = -1; + int tbl_end = 1 << tbl_bits; + while (1) { + unsigned entry; + int bit, stride, i; + /* start new sub-table */ + if ((gen->word & ((1 << tbl_bits)-1)) != sub_prefix) { + int used = 0; + sub_prefix = gen->word & ((1 << tbl_bits)-1); + sub_start = tbl_end; + sub_bits = gen->len - tbl_bits; + used = gen->cnt; + while (used < (1 << sub_bits)) { + sub_bits++; + used = (used << 1) + cnt[tbl_bits + sub_bits]; + } + tbl_end = sub_start + (1 << sub_bits); + tbl[sub_prefix] = (sub_start << 16) | 0x10 | (sub_bits & 0xf); + } + /* fill sub-table */ + entry = (*gen->sorted << 16) | ((gen->len - tbl_bits) & 0xf); + gen->sorted++; + i = sub_start + (gen->word >> tbl_bits); + stride = 1 << (gen->len - tbl_bits); + do { + tbl[i] = entry; + i += stride; + } while (i < tbl_end); + if (gen->word == (1 << gen->len)-1) { + return; + } + bit = 1 << sinfl_bsr(gen->word ^ ((1 << gen->len) - 1)); + gen->word &= bit - 1; + gen->word |= bit; + gen->cnt--; + while (!gen->cnt) { + gen->cnt = cnt[++gen->len]; + } + } +} +static void +sinfl_build(unsigned *tbl, unsigned char *lens, int tbl_bits, int maxlen, + int symcnt) { + int i, used = 0; + short sort[288]; + int cnt[16] = {0}, off[16]= {0}; + struct sinfl_gen gen = {0}; + gen.sorted = sort; + gen.len = 1; + + for (i = 0; i < symcnt; ++i) + cnt[lens[i]]++; + off[1] = cnt[0]; + for (i = 1; i < maxlen; ++i) { + off[i + 1] = off[i] + cnt[i]; + used = (used << 1) + cnt[i]; + } + used = (used << 1) + cnt[i]; + for (i = 0; i < symcnt; ++i) + gen.sorted[off[lens[i]]++] = (short)i; + gen.sorted += off[0]; + + if (used < (1 << maxlen)){ + for (i = 0; i < 1 << tbl_bits; ++i) + tbl[i] = (0 << 16u) | 1; + return; + } + if (!sinfl_build_tbl(&gen, tbl, tbl_bits, cnt)){ + sinfl_build_subtbl(&gen, tbl, tbl_bits, cnt); + } +} +static int +sinfl_decode(struct sinfl *s, const unsigned *tbl, int bit_len) { + int idx = sinfl_peek(s, bit_len); + unsigned key = tbl[idx]; + if (key & 0x10) { + /* sub-table lookup */ + int len = key & 0x0f; + sinfl_eat(s, bit_len); + idx = sinfl_peek(s, len); + key = tbl[((key >> 16) & 0xffff) + (unsigned)idx]; + } + sinfl_eat(s, key & 0x0f); + return (key >> 16) & 0x0fff; +} +static size_t +sinfl_decompress(unsigned char *out, size_t cap, const unsigned char *in, size_t size) { + static const unsigned char order[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; + static const short dbase[30+2] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, + 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577}; + static const unsigned char dbits[30+2] = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9, + 10,10,11,11,12,12,13,13,0,0}; + static const short lbase[29+2] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35, + 43,51,59,67,83,99,115,131,163,195,227,258,0,0}; + static const unsigned char lbits[29+2] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4, + 4,4,4,5,5,5,5,0,0,0}; + + const unsigned char *oe = out + cap; + const unsigned char *e = in + size, *o = out; + enum sinfl_states {hdr,stored,fixed,dyn,blk}; + enum sinfl_states state = hdr; + struct sinfl s = {0}; + int last = 0; + + s.bitptr = in; + while (1) { + switch (state) { + case hdr: { + /* block header */ + int type = 0; + sinfl_refill(&s); + last = sinfl__get(&s,1); + type = sinfl__get(&s,2); + + switch (type) {default: return (size_t)(out-o); + case 0x00: state = stored; break; + case 0x01: state = fixed; break; + case 0x02: state = dyn; break;} + } break; + case stored: { + /* uncompressed block */ + unsigned len, nlen; + sinfl__get(&s,s.bitcnt & 7); + len = (unsigned short)sinfl__get(&s,16); + nlen = (unsigned short)sinfl__get(&s,16); + s.bitptr -= s.bitcnt / 8; + s.bitbuf = s.bitcnt = 0; + + if ((unsigned short)len != (unsigned short)~nlen) + return (size_t)(out-o); + if (len > (e - s.bitptr)) + return (size_t)(out-o); + + memcpy(out, s.bitptr, (size_t)len); + s.bitptr += len, out += len; + if (last) return (size_t)(out-o); + state = hdr; + } break; + case fixed: { + /* fixed huffman codes */ + int n; unsigned char lens[288+32]; + for (n = 0; n <= 143; n++) lens[n] = 8; + for (n = 144; n <= 255; n++) lens[n] = 9; + for (n = 256; n <= 279; n++) lens[n] = 7; + for (n = 280; n <= 287; n++) lens[n] = 8; + for (n = 0; n < 32; n++) lens[288+n] = 5; + + /* build lit/dist tables */ + sinfl_build(s.lits, lens, 10, 15, 288); + sinfl_build(s.dsts, lens + 288, 8, 15, 32); + state = blk; + } break; + case dyn: { + /* dynamic huffman codes */ + int n, i; + unsigned hlens[SINFL_PRE_TBL_SIZE]; + unsigned char nlens[19] = {0}, lens[288+32]; + + sinfl_refill(&s); + {int nlit = 257 + sinfl__get(&s,5); + int ndist = 1 + sinfl__get(&s,5); + int nlen = 4 + sinfl__get(&s,4); + for (n = 0; n < nlen; n++) + nlens[order[n]] = (unsigned char)sinfl_get(&s,3); + sinfl_build(hlens, nlens, 7, 7, 19); + + /* decode code lengths */ + for (n = 0; n < nlit + ndist;) { + int sym = 0; + sinfl_refill(&s); + sym = sinfl_decode(&s, hlens, 7); + switch (sym) {default: lens[n++] = (unsigned char)sym; break; + case 16: for (i=3+sinfl_get(&s,2);i;i--,n++) lens[n]=lens[n-1]; break; + case 17: for (i=3+sinfl_get(&s,3);i;i--,n++) lens[n]=0; break; + case 18: for (i=11+sinfl_get(&s,7);i;i--,n++) lens[n]=0; break;} + } + /* build lit/dist tables */ + sinfl_build(s.lits, lens, 10, 15, nlit); + sinfl_build(s.dsts, lens + nlit, 8, 15, ndist); + state = blk;} + } break; + case blk: { + /* decompress block */ + while (1) { + int sym; + sinfl_refill(&s); + sym = sinfl_decode(&s, s.lits, 10); + if (sym < 256) { + /* literal */ + if (sinfl_unlikely(out >= oe)) { + return (size_t)(out-o); + } + *out++ = (unsigned char)sym; + sym = sinfl_decode(&s, s.lits, 10); + if (sym < 256) { + *out++ = (unsigned char)sym; + continue; + } + } + if (sinfl_unlikely(sym == 256)) { + /* end of block */ + if (last) return (size_t)(out-o); + state = hdr; + break; + } + /* match */ + if (sym >= 286) { + /* length codes 286 and 287 must not appear in compressed data */ + return (size_t)(out-o); + } + sym -= 257; + {int len = sinfl__get(&s, lbits[sym]) + lbase[sym]; + int dsym = sinfl_decode(&s, s.dsts, 8); + int offs = sinfl__get(&s, dbits[dsym]) + dbase[dsym]; + unsigned char *dst = out, *src = out - offs; + if (sinfl_unlikely(offs > (size_t)(out-o))) { + return (size_t)(out-o); + } + out = out + len; + +#ifndef SINFL_NO_SIMD + if (sinfl_likely(oe - out >= 16 * 3)) { + if (offs >= 16) { + /* simd copy match */ + sinfl_copy128(&dst, &src); + sinfl_copy128(&dst, &src); + do sinfl_copy128(&dst, &src); + while (dst < out); + } else if (offs >= 8) { + /* word copy match */ + sinfl_copy64(&dst, &src); + sinfl_copy64(&dst, &src); + do sinfl_copy64(&dst, &src); + while (dst < out); + } else if (offs == 1) { + /* rle match copying */ + sinfl_char16 w = sinfl_char16_char(src[0]); + dst = sinfl_write128(dst, w); + dst = sinfl_write128(dst, w); + do dst = sinfl_write128(dst, w); + while (dst < out); + } else { + /* byte copy match */ + *dst++ = *src++; + *dst++ = *src++; + do *dst++ = *src++; + while (dst < out); + } + } +#else + if (sinfl_likely(oe - out >= 3 * 8 - 3)) { + if (offs >= 8) { + /* word copy match */ + sinfl_copy64(&dst, &src); + sinfl_copy64(&dst, &src); + do sinfl_copy64(&dst, &src); + while (dst < out); + } else if (offs == 1) { + /* rle match copying */ + unsigned int c = src[0]; + unsigned int hw = (c << 24u) | (c << 16u) | (c << 8u) | (unsigned)c; + unsigned long long w = (unsigned long long)hw << 32llu | hw; + dst = sinfl_write64(dst, w); + dst = sinfl_write64(dst, w); + do dst = sinfl_write64(dst, w); + while (dst < out); + } else { + /* byte copy match */ + *dst++ = *src++; + *dst++ = *src++; + do *dst++ = *src++; + while (dst < out); + } + } +#endif + else { + *dst++ = *src++; + *dst++ = *src++; + do *dst++ = *src++; + while (dst < out); + }} + } + } break;} + } + return (size_t)(out-o); +} +extern size_t +sinflate(void *out, size_t cap, const void *in, size_t size) { + return sinfl_decompress((unsigned char*)out, cap, (const unsigned char*)in, size); +} +static unsigned +sinfl_adler32(unsigned adler32, const unsigned char *in, size_t in_len) { + const unsigned ADLER_MOD = 65521; + unsigned s1 = adler32 & 0xffff; + unsigned s2 = adler32 >> 16; + size_t blk_len, i; + + blk_len = in_len % 5552; + while (in_len) { + for (i=0; i + 7 < blk_len; i += 8) { + s1 += in[0]; s2 += s1; + s1 += in[1]; s2 += s1; + s1 += in[2]; s2 += s1; + s1 += in[3]; s2 += s1; + s1 += in[4]; s2 += s1; + s1 += in[5]; s2 += s1; + s1 += in[6]; s2 += s1; + s1 += in[7]; s2 += s1; + in += 8; + } + for (; i < blk_len; ++i) + s1 += *in++, s2 += s1; + s1 %= ADLER_MOD; s2 %= ADLER_MOD; + in_len -= blk_len; + blk_len = 5552; + } return (unsigned)(s2 << 16) + (unsigned)s1; +} +extern size_t +zsinflate(void *out, size_t cap, const void *mem, size_t size) { + const unsigned char *in = (const unsigned char*)mem; + if (size >= 6) { + const unsigned char *eob = in + size - 4; + size_t n = sinfl_decompress((unsigned char*)out, cap, in + 2u, size); + unsigned a = sinfl_adler32(1u, (unsigned char*)out, n); + unsigned h = eob[0] << 24 | eob[1] << 16 | eob[2] << 8 | eob[3] << 0; + return a == h ? n : -1; + } else { + return -1; + } +} +#endif + diff --git a/src/ui/generated/ui.meta.c b/src/ui/generated/ui.meta.c index f1490347..f66c6b76 100644 --- a/src/ui/generated/ui.meta.c +++ b/src/ui/generated/ui.meta.c @@ -12,14 +12,19 @@ #define UI_FixedHeight(v) DeferLoop(ui_push_fixed_height(v), ui_pop_fixed_height()) #define UI_PrefWidth(v) DeferLoop(ui_push_pref_width(v), ui_pop_pref_width()) #define UI_PrefHeight(v) DeferLoop(ui_push_pref_height(v), ui_pop_pref_height()) +#define UI_MinWidth(v) DeferLoop(ui_push_min_width(v), ui_pop_min_width()) +#define UI_MinHeight(v) DeferLoop(ui_push_min_height(v), ui_pop_min_height()) #define UI_PermissionFlags(v) DeferLoop(ui_push_permission_flags(v), ui_pop_permission_flags()) #define UI_Flags(v) DeferLoop(ui_push_flags(v), ui_pop_flags()) +#define UI_OmitFlags(v) DeferLoop(ui_push_omit_flags(v), ui_pop_omit_flags()) #define UI_FocusHot(v) DeferLoop(ui_push_focus_hot(v), ui_pop_focus_hot()) #define UI_FocusActive(v) DeferLoop(ui_push_focus_active(v), ui_pop_focus_active()) #define UI_FastpathCodepoint(v) DeferLoop(ui_push_fastpath_codepoint(v), ui_pop_fastpath_codepoint()) #define UI_GroupKey(v) DeferLoop(ui_push_group_key(v), ui_pop_group_key()) #define UI_Transparency(v) DeferLoop(ui_push_transparency(v), ui_pop_transparency()) -#define UI_Palette(v) DeferLoop(ui_push_palette(v), ui_pop_palette()) +#define UI_Tag(v) DeferLoop(ui_push_tag(v), ui_pop_tag()) +#define UI_BackgroundColor(v) DeferLoop(ui_push_background_color(v), ui_pop_background_color()) +#define UI_TextColor(v) DeferLoop(ui_push_text_color(v), ui_pop_text_color()) #define UI_Squish(v) DeferLoop(ui_push_squish(v), ui_pop_squish()) #define UI_HoverCursor(v) DeferLoop(ui_push_hover_cursor(v), ui_pop_hover_cursor()) #define UI_Font(v) DeferLoop(ui_push_font(v), ui_pop_font()) @@ -42,14 +47,18 @@ internal F32 ui_top_fixed_width(void) { UI_StackTopImpl(ui_state, FixedWidth, fi internal F32 ui_top_fixed_height(void) { UI_StackTopImpl(ui_state, FixedHeight, fixed_height) } internal UI_Size ui_top_pref_width(void) { UI_StackTopImpl(ui_state, PrefWidth, pref_width) } internal UI_Size ui_top_pref_height(void) { UI_StackTopImpl(ui_state, PrefHeight, pref_height) } +internal F32 ui_top_min_width(void) { UI_StackTopImpl(ui_state, MinWidth, min_width) } +internal F32 ui_top_min_height(void) { UI_StackTopImpl(ui_state, MinHeight, min_height) } internal UI_PermissionFlags ui_top_permission_flags(void) { UI_StackTopImpl(ui_state, PermissionFlags, permission_flags) } internal UI_BoxFlags ui_top_flags(void) { UI_StackTopImpl(ui_state, Flags, flags) } +internal UI_BoxFlags ui_top_omit_flags(void) { UI_StackTopImpl(ui_state, OmitFlags, omit_flags) } internal UI_FocusKind ui_top_focus_hot(void) { UI_StackTopImpl(ui_state, FocusHot, focus_hot) } internal UI_FocusKind ui_top_focus_active(void) { UI_StackTopImpl(ui_state, FocusActive, focus_active) } internal U32 ui_top_fastpath_codepoint(void) { UI_StackTopImpl(ui_state, FastpathCodepoint, fastpath_codepoint) } internal UI_Key ui_top_group_key(void) { UI_StackTopImpl(ui_state, GroupKey, group_key) } internal F32 ui_top_transparency(void) { UI_StackTopImpl(ui_state, Transparency, transparency) } -internal UI_Palette* ui_top_palette(void) { UI_StackTopImpl(ui_state, Palette, palette) } +internal Vec4F32 ui_top_background_color(void) { UI_StackTopImpl(ui_state, BackgroundColor, background_color) } +internal Vec4F32 ui_top_text_color(void) { UI_StackTopImpl(ui_state, TextColor, text_color) } internal F32 ui_top_squish(void) { UI_StackTopImpl(ui_state, Squish, squish) } internal OS_Cursor ui_top_hover_cursor(void) { UI_StackTopImpl(ui_state, HoverCursor, hover_cursor) } internal FNT_Tag ui_top_font(void) { UI_StackTopImpl(ui_state, Font, font) } @@ -71,14 +80,18 @@ internal F32 ui_bottom_fixed_width(void) { UI_StackBottomImpl(ui_state, FixedWid internal F32 ui_bottom_fixed_height(void) { UI_StackBottomImpl(ui_state, FixedHeight, fixed_height) } internal UI_Size ui_bottom_pref_width(void) { UI_StackBottomImpl(ui_state, PrefWidth, pref_width) } internal UI_Size ui_bottom_pref_height(void) { UI_StackBottomImpl(ui_state, PrefHeight, pref_height) } +internal F32 ui_bottom_min_width(void) { UI_StackBottomImpl(ui_state, MinWidth, min_width) } +internal F32 ui_bottom_min_height(void) { UI_StackBottomImpl(ui_state, MinHeight, min_height) } internal UI_PermissionFlags ui_bottom_permission_flags(void) { UI_StackBottomImpl(ui_state, PermissionFlags, permission_flags) } internal UI_BoxFlags ui_bottom_flags(void) { UI_StackBottomImpl(ui_state, Flags, flags) } +internal UI_BoxFlags ui_bottom_omit_flags(void) { UI_StackBottomImpl(ui_state, OmitFlags, omit_flags) } internal UI_FocusKind ui_bottom_focus_hot(void) { UI_StackBottomImpl(ui_state, FocusHot, focus_hot) } internal UI_FocusKind ui_bottom_focus_active(void) { UI_StackBottomImpl(ui_state, FocusActive, focus_active) } internal U32 ui_bottom_fastpath_codepoint(void) { UI_StackBottomImpl(ui_state, FastpathCodepoint, fastpath_codepoint) } internal UI_Key ui_bottom_group_key(void) { UI_StackBottomImpl(ui_state, GroupKey, group_key) } internal F32 ui_bottom_transparency(void) { UI_StackBottomImpl(ui_state, Transparency, transparency) } -internal UI_Palette* ui_bottom_palette(void) { UI_StackBottomImpl(ui_state, Palette, palette) } +internal Vec4F32 ui_bottom_background_color(void) { UI_StackBottomImpl(ui_state, BackgroundColor, background_color) } +internal Vec4F32 ui_bottom_text_color(void) { UI_StackBottomImpl(ui_state, TextColor, text_color) } internal F32 ui_bottom_squish(void) { UI_StackBottomImpl(ui_state, Squish, squish) } internal OS_Cursor ui_bottom_hover_cursor(void) { UI_StackBottomImpl(ui_state, HoverCursor, hover_cursor) } internal FNT_Tag ui_bottom_font(void) { UI_StackBottomImpl(ui_state, Font, font) } @@ -100,14 +113,18 @@ internal F32 ui_push_fixed_width(F32 v) { UI_StackPushImpl(ui_state, FixedWidth, internal F32 ui_push_fixed_height(F32 v) { UI_StackPushImpl(ui_state, FixedHeight, fixed_height, F32, v) } internal UI_Size ui_push_pref_width(UI_Size v) { UI_StackPushImpl(ui_state, PrefWidth, pref_width, UI_Size, v) } internal UI_Size ui_push_pref_height(UI_Size v) { UI_StackPushImpl(ui_state, PrefHeight, pref_height, UI_Size, v) } +internal F32 ui_push_min_width(F32 v) { UI_StackPushImpl(ui_state, MinWidth, min_width, F32, v) } +internal F32 ui_push_min_height(F32 v) { UI_StackPushImpl(ui_state, MinHeight, min_height, F32, v) } internal UI_PermissionFlags ui_push_permission_flags(UI_PermissionFlags v) { UI_StackPushImpl(ui_state, PermissionFlags, permission_flags, UI_PermissionFlags, v) } internal UI_BoxFlags ui_push_flags(UI_BoxFlags v) { UI_StackPushImpl(ui_state, Flags, flags, UI_BoxFlags, v) } +internal UI_BoxFlags ui_push_omit_flags(UI_BoxFlags v) { UI_StackPushImpl(ui_state, OmitFlags, omit_flags, UI_BoxFlags, v) } internal UI_FocusKind ui_push_focus_hot(UI_FocusKind v) { UI_StackPushImpl(ui_state, FocusHot, focus_hot, UI_FocusKind, v) } internal UI_FocusKind ui_push_focus_active(UI_FocusKind v) { UI_StackPushImpl(ui_state, FocusActive, focus_active, UI_FocusKind, v) } internal U32 ui_push_fastpath_codepoint(U32 v) { UI_StackPushImpl(ui_state, FastpathCodepoint, fastpath_codepoint, U32, v) } internal UI_Key ui_push_group_key(UI_Key v) { UI_StackPushImpl(ui_state, GroupKey, group_key, UI_Key, v) } internal F32 ui_push_transparency(F32 v) { UI_StackPushImpl(ui_state, Transparency, transparency, F32, v) } -internal UI_Palette* ui_push_palette(UI_Palette* v) { UI_StackPushImpl(ui_state, Palette, palette, UI_Palette* , v) } +internal Vec4F32 ui_push_background_color(Vec4F32 v) { UI_StackPushImpl(ui_state, BackgroundColor, background_color, Vec4F32, v) } +internal Vec4F32 ui_push_text_color(Vec4F32 v) { UI_StackPushImpl(ui_state, TextColor, text_color, Vec4F32, v) } internal F32 ui_push_squish(F32 v) { UI_StackPushImpl(ui_state, Squish, squish, F32, v) } internal OS_Cursor ui_push_hover_cursor(OS_Cursor v) { UI_StackPushImpl(ui_state, HoverCursor, hover_cursor, OS_Cursor, v) } internal FNT_Tag ui_push_font(FNT_Tag v) { UI_StackPushImpl(ui_state, Font, font, FNT_Tag, v) } @@ -129,14 +146,18 @@ internal F32 ui_pop_fixed_width(void) { UI_StackPopImpl(ui_state, FixedWidth, fi internal F32 ui_pop_fixed_height(void) { UI_StackPopImpl(ui_state, FixedHeight, fixed_height) } internal UI_Size ui_pop_pref_width(void) { UI_StackPopImpl(ui_state, PrefWidth, pref_width) } internal UI_Size ui_pop_pref_height(void) { UI_StackPopImpl(ui_state, PrefHeight, pref_height) } +internal F32 ui_pop_min_width(void) { UI_StackPopImpl(ui_state, MinWidth, min_width) } +internal F32 ui_pop_min_height(void) { UI_StackPopImpl(ui_state, MinHeight, min_height) } internal UI_PermissionFlags ui_pop_permission_flags(void) { UI_StackPopImpl(ui_state, PermissionFlags, permission_flags) } internal UI_BoxFlags ui_pop_flags(void) { UI_StackPopImpl(ui_state, Flags, flags) } +internal UI_BoxFlags ui_pop_omit_flags(void) { UI_StackPopImpl(ui_state, OmitFlags, omit_flags) } internal UI_FocusKind ui_pop_focus_hot(void) { UI_StackPopImpl(ui_state, FocusHot, focus_hot) } internal UI_FocusKind ui_pop_focus_active(void) { UI_StackPopImpl(ui_state, FocusActive, focus_active) } internal U32 ui_pop_fastpath_codepoint(void) { UI_StackPopImpl(ui_state, FastpathCodepoint, fastpath_codepoint) } internal UI_Key ui_pop_group_key(void) { UI_StackPopImpl(ui_state, GroupKey, group_key) } internal F32 ui_pop_transparency(void) { UI_StackPopImpl(ui_state, Transparency, transparency) } -internal UI_Palette* ui_pop_palette(void) { UI_StackPopImpl(ui_state, Palette, palette) } +internal Vec4F32 ui_pop_background_color(void) { UI_StackPopImpl(ui_state, BackgroundColor, background_color) } +internal Vec4F32 ui_pop_text_color(void) { UI_StackPopImpl(ui_state, TextColor, text_color) } internal F32 ui_pop_squish(void) { UI_StackPopImpl(ui_state, Squish, squish) } internal OS_Cursor ui_pop_hover_cursor(void) { UI_StackPopImpl(ui_state, HoverCursor, hover_cursor) } internal FNT_Tag ui_pop_font(void) { UI_StackPopImpl(ui_state, Font, font) } @@ -158,14 +179,18 @@ internal F32 ui_set_next_fixed_width(F32 v) { UI_StackSetNextImpl(ui_state, Fixe internal F32 ui_set_next_fixed_height(F32 v) { UI_StackSetNextImpl(ui_state, FixedHeight, fixed_height, F32, v) } internal UI_Size ui_set_next_pref_width(UI_Size v) { UI_StackSetNextImpl(ui_state, PrefWidth, pref_width, UI_Size, v) } internal UI_Size ui_set_next_pref_height(UI_Size v) { UI_StackSetNextImpl(ui_state, PrefHeight, pref_height, UI_Size, v) } +internal F32 ui_set_next_min_width(F32 v) { UI_StackSetNextImpl(ui_state, MinWidth, min_width, F32, v) } +internal F32 ui_set_next_min_height(F32 v) { UI_StackSetNextImpl(ui_state, MinHeight, min_height, F32, v) } internal UI_PermissionFlags ui_set_next_permission_flags(UI_PermissionFlags v) { UI_StackSetNextImpl(ui_state, PermissionFlags, permission_flags, UI_PermissionFlags, v) } internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v) { UI_StackSetNextImpl(ui_state, Flags, flags, UI_BoxFlags, v) } +internal UI_BoxFlags ui_set_next_omit_flags(UI_BoxFlags v) { UI_StackSetNextImpl(ui_state, OmitFlags, omit_flags, UI_BoxFlags, v) } internal UI_FocusKind ui_set_next_focus_hot(UI_FocusKind v) { UI_StackSetNextImpl(ui_state, FocusHot, focus_hot, UI_FocusKind, v) } internal UI_FocusKind ui_set_next_focus_active(UI_FocusKind v) { UI_StackSetNextImpl(ui_state, FocusActive, focus_active, UI_FocusKind, v) } internal U32 ui_set_next_fastpath_codepoint(U32 v) { UI_StackSetNextImpl(ui_state, FastpathCodepoint, fastpath_codepoint, U32, v) } internal UI_Key ui_set_next_group_key(UI_Key v) { UI_StackSetNextImpl(ui_state, GroupKey, group_key, UI_Key, v) } internal F32 ui_set_next_transparency(F32 v) { UI_StackSetNextImpl(ui_state, Transparency, transparency, F32, v) } -internal UI_Palette* ui_set_next_palette(UI_Palette* v) { UI_StackSetNextImpl(ui_state, Palette, palette, UI_Palette* , v) } +internal Vec4F32 ui_set_next_background_color(Vec4F32 v) { UI_StackSetNextImpl(ui_state, BackgroundColor, background_color, Vec4F32, v) } +internal Vec4F32 ui_set_next_text_color(Vec4F32 v) { UI_StackSetNextImpl(ui_state, TextColor, text_color, Vec4F32, v) } internal F32 ui_set_next_squish(F32 v) { UI_StackSetNextImpl(ui_state, Squish, squish, F32, v) } internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v) { UI_StackSetNextImpl(ui_state, HoverCursor, hover_cursor, OS_Cursor, v) } internal FNT_Tag ui_set_next_font(FNT_Tag v) { UI_StackSetNextImpl(ui_state, Font, font, FNT_Tag, v) } diff --git a/src/ui/generated/ui.meta.h b/src/ui/generated/ui.meta.h index 28c38de8..2b666b2a 100644 --- a/src/ui/generated/ui.meta.h +++ b/src/ui/generated/ui.meta.h @@ -14,14 +14,19 @@ typedef struct UI_FixedWidthNode UI_FixedWidthNode; struct UI_FixedWidthNode{UI_ typedef struct UI_FixedHeightNode UI_FixedHeightNode; struct UI_FixedHeightNode{UI_FixedHeightNode *next; F32 v;}; typedef struct UI_PrefWidthNode UI_PrefWidthNode; struct UI_PrefWidthNode{UI_PrefWidthNode *next; UI_Size v;}; typedef struct UI_PrefHeightNode UI_PrefHeightNode; struct UI_PrefHeightNode{UI_PrefHeightNode *next; UI_Size v;}; +typedef struct UI_MinWidthNode UI_MinWidthNode; struct UI_MinWidthNode{UI_MinWidthNode *next; F32 v;}; +typedef struct UI_MinHeightNode UI_MinHeightNode; struct UI_MinHeightNode{UI_MinHeightNode *next; F32 v;}; typedef struct UI_PermissionFlagsNode UI_PermissionFlagsNode; struct UI_PermissionFlagsNode{UI_PermissionFlagsNode *next; UI_PermissionFlags v;}; typedef struct UI_FlagsNode UI_FlagsNode; struct UI_FlagsNode{UI_FlagsNode *next; UI_BoxFlags v;}; +typedef struct UI_OmitFlagsNode UI_OmitFlagsNode; struct UI_OmitFlagsNode{UI_OmitFlagsNode *next; UI_BoxFlags v;}; typedef struct UI_FocusHotNode UI_FocusHotNode; struct UI_FocusHotNode{UI_FocusHotNode *next; UI_FocusKind v;}; typedef struct UI_FocusActiveNode UI_FocusActiveNode; struct UI_FocusActiveNode{UI_FocusActiveNode *next; UI_FocusKind v;}; typedef struct UI_FastpathCodepointNode UI_FastpathCodepointNode; struct UI_FastpathCodepointNode{UI_FastpathCodepointNode *next; U32 v;}; typedef struct UI_GroupKeyNode UI_GroupKeyNode; struct UI_GroupKeyNode{UI_GroupKeyNode *next; UI_Key v;}; typedef struct UI_TransparencyNode UI_TransparencyNode; struct UI_TransparencyNode{UI_TransparencyNode *next; F32 v;}; -typedef struct UI_PaletteNode UI_PaletteNode; struct UI_PaletteNode{UI_PaletteNode *next; UI_Palette* v;}; +typedef struct UI_TagNode UI_TagNode; struct UI_TagNode{UI_TagNode *next; String8 v;}; +typedef struct UI_BackgroundColorNode UI_BackgroundColorNode; struct UI_BackgroundColorNode{UI_BackgroundColorNode *next; Vec4F32 v;}; +typedef struct UI_TextColorNode UI_TextColorNode; struct UI_TextColorNode{UI_TextColorNode *next; Vec4F32 v;}; typedef struct UI_SquishNode UI_SquishNode; struct UI_SquishNode{UI_SquishNode *next; F32 v;}; typedef struct UI_HoverCursorNode UI_HoverCursorNode; struct UI_HoverCursorNode{UI_HoverCursorNode *next; OS_Cursor v;}; typedef struct UI_FontNode UI_FontNode; struct UI_FontNode{UI_FontNode *next; FNT_Tag v;}; @@ -46,14 +51,19 @@ UI_FixedWidthNode fixed_width_nil_stack_top;\ UI_FixedHeightNode fixed_height_nil_stack_top;\ UI_PrefWidthNode pref_width_nil_stack_top;\ UI_PrefHeightNode pref_height_nil_stack_top;\ +UI_MinWidthNode min_width_nil_stack_top;\ +UI_MinHeightNode min_height_nil_stack_top;\ UI_PermissionFlagsNode permission_flags_nil_stack_top;\ UI_FlagsNode flags_nil_stack_top;\ +UI_OmitFlagsNode omit_flags_nil_stack_top;\ UI_FocusHotNode focus_hot_nil_stack_top;\ UI_FocusActiveNode focus_active_nil_stack_top;\ UI_FastpathCodepointNode fastpath_codepoint_nil_stack_top;\ UI_GroupKeyNode group_key_nil_stack_top;\ UI_TransparencyNode transparency_nil_stack_top;\ -UI_PaletteNode palette_nil_stack_top;\ +UI_TagNode tag_nil_stack_top;\ +UI_BackgroundColorNode background_color_nil_stack_top;\ +UI_TextColorNode text_color_nil_stack_top;\ UI_SquishNode squish_nil_stack_top;\ UI_HoverCursorNode hover_cursor_nil_stack_top;\ UI_FontNode font_nil_stack_top;\ @@ -77,14 +87,19 @@ state->fixed_width_nil_stack_top.v = 0;\ state->fixed_height_nil_stack_top.v = 0;\ state->pref_width_nil_stack_top.v = ui_px(250.f, 1.f);\ state->pref_height_nil_stack_top.v = ui_px(30.f, 1.f);\ +state->min_width_nil_stack_top.v = 0;\ +state->min_height_nil_stack_top.v = 0;\ state->permission_flags_nil_stack_top.v = UI_PermissionFlag_All;\ state->flags_nil_stack_top.v = 0;\ +state->omit_flags_nil_stack_top.v = 0;\ state->focus_hot_nil_stack_top.v = UI_FocusKind_Null;\ state->focus_active_nil_stack_top.v = UI_FocusKind_Null;\ state->fastpath_codepoint_nil_stack_top.v = 0;\ state->group_key_nil_stack_top.v = ui_key_zero();\ state->transparency_nil_stack_top.v = 0;\ -state->palette_nil_stack_top.v = &ui_g_nil_palette;\ +state->tag_nil_stack_top.v = str8_lit("");\ +state->background_color_nil_stack_top.v = v4f32(0, 0, 0, 0);\ +state->text_color_nil_stack_top.v = v4f32(0, 0, 0, 0);\ state->squish_nil_stack_top.v = 0;\ state->hover_cursor_nil_stack_top.v = OS_Cursor_Pointer;\ state->font_nil_stack_top.v = fnt_tag_zero();\ @@ -102,35 +117,40 @@ state->text_alignment_nil_stack_top.v = UI_TextAlign_Left;\ #define UI_DeclStacks \ struct\ {\ -struct { UI_ParentNode *top; UI_Box * bottom_val; UI_ParentNode *free; B32 auto_pop; } parent_stack;\ -struct { UI_ChildLayoutAxisNode *top; Axis2 bottom_val; UI_ChildLayoutAxisNode *free; B32 auto_pop; } child_layout_axis_stack;\ -struct { UI_FixedXNode *top; F32 bottom_val; UI_FixedXNode *free; B32 auto_pop; } fixed_x_stack;\ -struct { UI_FixedYNode *top; F32 bottom_val; UI_FixedYNode *free; B32 auto_pop; } fixed_y_stack;\ -struct { UI_FixedWidthNode *top; F32 bottom_val; UI_FixedWidthNode *free; B32 auto_pop; } fixed_width_stack;\ -struct { UI_FixedHeightNode *top; F32 bottom_val; UI_FixedHeightNode *free; B32 auto_pop; } fixed_height_stack;\ -struct { UI_PrefWidthNode *top; UI_Size bottom_val; UI_PrefWidthNode *free; B32 auto_pop; } pref_width_stack;\ -struct { UI_PrefHeightNode *top; UI_Size bottom_val; UI_PrefHeightNode *free; B32 auto_pop; } pref_height_stack;\ -struct { UI_PermissionFlagsNode *top; UI_PermissionFlags bottom_val; UI_PermissionFlagsNode *free; B32 auto_pop; } permission_flags_stack;\ -struct { UI_FlagsNode *top; UI_BoxFlags bottom_val; UI_FlagsNode *free; B32 auto_pop; } flags_stack;\ -struct { UI_FocusHotNode *top; UI_FocusKind bottom_val; UI_FocusHotNode *free; B32 auto_pop; } focus_hot_stack;\ -struct { UI_FocusActiveNode *top; UI_FocusKind bottom_val; UI_FocusActiveNode *free; B32 auto_pop; } focus_active_stack;\ -struct { UI_FastpathCodepointNode *top; U32 bottom_val; UI_FastpathCodepointNode *free; B32 auto_pop; } fastpath_codepoint_stack;\ -struct { UI_GroupKeyNode *top; UI_Key bottom_val; UI_GroupKeyNode *free; B32 auto_pop; } group_key_stack;\ -struct { UI_TransparencyNode *top; F32 bottom_val; UI_TransparencyNode *free; B32 auto_pop; } transparency_stack;\ -struct { UI_PaletteNode *top; UI_Palette* bottom_val; UI_PaletteNode *free; B32 auto_pop; } palette_stack;\ -struct { UI_SquishNode *top; F32 bottom_val; UI_SquishNode *free; B32 auto_pop; } squish_stack;\ -struct { UI_HoverCursorNode *top; OS_Cursor bottom_val; UI_HoverCursorNode *free; B32 auto_pop; } hover_cursor_stack;\ -struct { UI_FontNode *top; FNT_Tag bottom_val; UI_FontNode *free; B32 auto_pop; } font_stack;\ -struct { UI_FontSizeNode *top; F32 bottom_val; UI_FontSizeNode *free; B32 auto_pop; } font_size_stack;\ -struct { UI_TextRasterFlagsNode *top; FNT_RasterFlags bottom_val; UI_TextRasterFlagsNode *free; B32 auto_pop; } text_raster_flags_stack;\ -struct { UI_TabSizeNode *top; F32 bottom_val; UI_TabSizeNode *free; B32 auto_pop; } tab_size_stack;\ -struct { UI_CornerRadius00Node *top; F32 bottom_val; UI_CornerRadius00Node *free; B32 auto_pop; } corner_radius_00_stack;\ -struct { UI_CornerRadius01Node *top; F32 bottom_val; UI_CornerRadius01Node *free; B32 auto_pop; } corner_radius_01_stack;\ -struct { UI_CornerRadius10Node *top; F32 bottom_val; UI_CornerRadius10Node *free; B32 auto_pop; } corner_radius_10_stack;\ -struct { UI_CornerRadius11Node *top; F32 bottom_val; UI_CornerRadius11Node *free; B32 auto_pop; } corner_radius_11_stack;\ -struct { UI_BlurSizeNode *top; F32 bottom_val; UI_BlurSizeNode *free; B32 auto_pop; } blur_size_stack;\ -struct { UI_TextPaddingNode *top; F32 bottom_val; UI_TextPaddingNode *free; B32 auto_pop; } text_padding_stack;\ -struct { UI_TextAlignmentNode *top; UI_TextAlign bottom_val; UI_TextAlignmentNode *free; B32 auto_pop; } text_alignment_stack;\ +struct { UI_ParentNode *top; UI_Box * bottom_val; UI_ParentNode *free; U64 gen; B32 auto_pop; } parent_stack;\ +struct { UI_ChildLayoutAxisNode *top; Axis2 bottom_val; UI_ChildLayoutAxisNode *free; U64 gen; B32 auto_pop; } child_layout_axis_stack;\ +struct { UI_FixedXNode *top; F32 bottom_val; UI_FixedXNode *free; U64 gen; B32 auto_pop; } fixed_x_stack;\ +struct { UI_FixedYNode *top; F32 bottom_val; UI_FixedYNode *free; U64 gen; B32 auto_pop; } fixed_y_stack;\ +struct { UI_FixedWidthNode *top; F32 bottom_val; UI_FixedWidthNode *free; U64 gen; B32 auto_pop; } fixed_width_stack;\ +struct { UI_FixedHeightNode *top; F32 bottom_val; UI_FixedHeightNode *free; U64 gen; B32 auto_pop; } fixed_height_stack;\ +struct { UI_PrefWidthNode *top; UI_Size bottom_val; UI_PrefWidthNode *free; U64 gen; B32 auto_pop; } pref_width_stack;\ +struct { UI_PrefHeightNode *top; UI_Size bottom_val; UI_PrefHeightNode *free; U64 gen; B32 auto_pop; } pref_height_stack;\ +struct { UI_MinWidthNode *top; F32 bottom_val; UI_MinWidthNode *free; U64 gen; B32 auto_pop; } min_width_stack;\ +struct { UI_MinHeightNode *top; F32 bottom_val; UI_MinHeightNode *free; U64 gen; B32 auto_pop; } min_height_stack;\ +struct { UI_PermissionFlagsNode *top; UI_PermissionFlags bottom_val; UI_PermissionFlagsNode *free; U64 gen; B32 auto_pop; } permission_flags_stack;\ +struct { UI_FlagsNode *top; UI_BoxFlags bottom_val; UI_FlagsNode *free; U64 gen; B32 auto_pop; } flags_stack;\ +struct { UI_OmitFlagsNode *top; UI_BoxFlags bottom_val; UI_OmitFlagsNode *free; U64 gen; B32 auto_pop; } omit_flags_stack;\ +struct { UI_FocusHotNode *top; UI_FocusKind bottom_val; UI_FocusHotNode *free; U64 gen; B32 auto_pop; } focus_hot_stack;\ +struct { UI_FocusActiveNode *top; UI_FocusKind bottom_val; UI_FocusActiveNode *free; U64 gen; B32 auto_pop; } focus_active_stack;\ +struct { UI_FastpathCodepointNode *top; U32 bottom_val; UI_FastpathCodepointNode *free; U64 gen; B32 auto_pop; } fastpath_codepoint_stack;\ +struct { UI_GroupKeyNode *top; UI_Key bottom_val; UI_GroupKeyNode *free; U64 gen; B32 auto_pop; } group_key_stack;\ +struct { UI_TransparencyNode *top; F32 bottom_val; UI_TransparencyNode *free; U64 gen; B32 auto_pop; } transparency_stack;\ +struct { UI_TagNode *top; String8 bottom_val; UI_TagNode *free; U64 gen; B32 auto_pop; } tag_stack;\ +struct { UI_BackgroundColorNode *top; Vec4F32 bottom_val; UI_BackgroundColorNode *free; U64 gen; B32 auto_pop; } background_color_stack;\ +struct { UI_TextColorNode *top; Vec4F32 bottom_val; UI_TextColorNode *free; U64 gen; B32 auto_pop; } text_color_stack;\ +struct { UI_SquishNode *top; F32 bottom_val; UI_SquishNode *free; U64 gen; B32 auto_pop; } squish_stack;\ +struct { UI_HoverCursorNode *top; OS_Cursor bottom_val; UI_HoverCursorNode *free; U64 gen; B32 auto_pop; } hover_cursor_stack;\ +struct { UI_FontNode *top; FNT_Tag bottom_val; UI_FontNode *free; U64 gen; B32 auto_pop; } font_stack;\ +struct { UI_FontSizeNode *top; F32 bottom_val; UI_FontSizeNode *free; U64 gen; B32 auto_pop; } font_size_stack;\ +struct { UI_TextRasterFlagsNode *top; FNT_RasterFlags bottom_val; UI_TextRasterFlagsNode *free; U64 gen; B32 auto_pop; } text_raster_flags_stack;\ +struct { UI_TabSizeNode *top; F32 bottom_val; UI_TabSizeNode *free; U64 gen; B32 auto_pop; } tab_size_stack;\ +struct { UI_CornerRadius00Node *top; F32 bottom_val; UI_CornerRadius00Node *free; U64 gen; B32 auto_pop; } corner_radius_00_stack;\ +struct { UI_CornerRadius01Node *top; F32 bottom_val; UI_CornerRadius01Node *free; U64 gen; B32 auto_pop; } corner_radius_01_stack;\ +struct { UI_CornerRadius10Node *top; F32 bottom_val; UI_CornerRadius10Node *free; U64 gen; B32 auto_pop; } corner_radius_10_stack;\ +struct { UI_CornerRadius11Node *top; F32 bottom_val; UI_CornerRadius11Node *free; U64 gen; B32 auto_pop; } corner_radius_11_stack;\ +struct { UI_BlurSizeNode *top; F32 bottom_val; UI_BlurSizeNode *free; U64 gen; B32 auto_pop; } blur_size_stack;\ +struct { UI_TextPaddingNode *top; F32 bottom_val; UI_TextPaddingNode *free; U64 gen; B32 auto_pop; } text_padding_stack;\ +struct { UI_TextAlignmentNode *top; UI_TextAlign bottom_val; UI_TextAlignmentNode *free; U64 gen; B32 auto_pop; } text_alignment_stack;\ } #define UI_InitStacks(state) \ state->parent_stack.top = &state->parent_nil_stack_top; state->parent_stack.bottom_val = &ui_nil_box; state->parent_stack.free = 0; state->parent_stack.auto_pop = 0;\ @@ -141,14 +161,19 @@ state->fixed_width_stack.top = &state->fixed_width_nil_stack_top; state->fixed_w state->fixed_height_stack.top = &state->fixed_height_nil_stack_top; state->fixed_height_stack.bottom_val = 0; state->fixed_height_stack.free = 0; state->fixed_height_stack.auto_pop = 0;\ state->pref_width_stack.top = &state->pref_width_nil_stack_top; state->pref_width_stack.bottom_val = ui_px(250.f, 1.f); state->pref_width_stack.free = 0; state->pref_width_stack.auto_pop = 0;\ state->pref_height_stack.top = &state->pref_height_nil_stack_top; state->pref_height_stack.bottom_val = ui_px(30.f, 1.f); state->pref_height_stack.free = 0; state->pref_height_stack.auto_pop = 0;\ +state->min_width_stack.top = &state->min_width_nil_stack_top; state->min_width_stack.bottom_val = 0; state->min_width_stack.free = 0; state->min_width_stack.auto_pop = 0;\ +state->min_height_stack.top = &state->min_height_nil_stack_top; state->min_height_stack.bottom_val = 0; state->min_height_stack.free = 0; state->min_height_stack.auto_pop = 0;\ state->permission_flags_stack.top = &state->permission_flags_nil_stack_top; state->permission_flags_stack.bottom_val = UI_PermissionFlag_All; state->permission_flags_stack.free = 0; state->permission_flags_stack.auto_pop = 0;\ state->flags_stack.top = &state->flags_nil_stack_top; state->flags_stack.bottom_val = 0; state->flags_stack.free = 0; state->flags_stack.auto_pop = 0;\ +state->omit_flags_stack.top = &state->omit_flags_nil_stack_top; state->omit_flags_stack.bottom_val = 0; state->omit_flags_stack.free = 0; state->omit_flags_stack.auto_pop = 0;\ state->focus_hot_stack.top = &state->focus_hot_nil_stack_top; state->focus_hot_stack.bottom_val = UI_FocusKind_Null; state->focus_hot_stack.free = 0; state->focus_hot_stack.auto_pop = 0;\ state->focus_active_stack.top = &state->focus_active_nil_stack_top; state->focus_active_stack.bottom_val = UI_FocusKind_Null; state->focus_active_stack.free = 0; state->focus_active_stack.auto_pop = 0;\ state->fastpath_codepoint_stack.top = &state->fastpath_codepoint_nil_stack_top; state->fastpath_codepoint_stack.bottom_val = 0; state->fastpath_codepoint_stack.free = 0; state->fastpath_codepoint_stack.auto_pop = 0;\ state->group_key_stack.top = &state->group_key_nil_stack_top; state->group_key_stack.bottom_val = ui_key_zero(); state->group_key_stack.free = 0; state->group_key_stack.auto_pop = 0;\ state->transparency_stack.top = &state->transparency_nil_stack_top; state->transparency_stack.bottom_val = 0; state->transparency_stack.free = 0; state->transparency_stack.auto_pop = 0;\ -state->palette_stack.top = &state->palette_nil_stack_top; state->palette_stack.bottom_val = &ui_g_nil_palette; state->palette_stack.free = 0; state->palette_stack.auto_pop = 0;\ +state->tag_stack.top = &state->tag_nil_stack_top; state->tag_stack.bottom_val = str8_lit(""); state->tag_stack.free = 0; state->tag_stack.auto_pop = 0;\ +state->background_color_stack.top = &state->background_color_nil_stack_top; state->background_color_stack.bottom_val = v4f32(0, 0, 0, 0); state->background_color_stack.free = 0; state->background_color_stack.auto_pop = 0;\ +state->text_color_stack.top = &state->text_color_nil_stack_top; state->text_color_stack.bottom_val = v4f32(0, 0, 0, 0); state->text_color_stack.free = 0; state->text_color_stack.auto_pop = 0;\ state->squish_stack.top = &state->squish_nil_stack_top; state->squish_stack.bottom_val = 0; state->squish_stack.free = 0; state->squish_stack.auto_pop = 0;\ state->hover_cursor_stack.top = &state->hover_cursor_nil_stack_top; state->hover_cursor_stack.bottom_val = OS_Cursor_Pointer; state->hover_cursor_stack.free = 0; state->hover_cursor_stack.auto_pop = 0;\ state->font_stack.top = &state->font_nil_stack_top; state->font_stack.bottom_val = fnt_tag_zero(); state->font_stack.free = 0; state->font_stack.auto_pop = 0;\ @@ -172,14 +197,19 @@ if(state->fixed_width_stack.auto_pop) { ui_pop_fixed_width(); state->fixed_width if(state->fixed_height_stack.auto_pop) { ui_pop_fixed_height(); state->fixed_height_stack.auto_pop = 0; }\ if(state->pref_width_stack.auto_pop) { ui_pop_pref_width(); state->pref_width_stack.auto_pop = 0; }\ if(state->pref_height_stack.auto_pop) { ui_pop_pref_height(); state->pref_height_stack.auto_pop = 0; }\ +if(state->min_width_stack.auto_pop) { ui_pop_min_width(); state->min_width_stack.auto_pop = 0; }\ +if(state->min_height_stack.auto_pop) { ui_pop_min_height(); state->min_height_stack.auto_pop = 0; }\ if(state->permission_flags_stack.auto_pop) { ui_pop_permission_flags(); state->permission_flags_stack.auto_pop = 0; }\ if(state->flags_stack.auto_pop) { ui_pop_flags(); state->flags_stack.auto_pop = 0; }\ +if(state->omit_flags_stack.auto_pop) { ui_pop_omit_flags(); state->omit_flags_stack.auto_pop = 0; }\ if(state->focus_hot_stack.auto_pop) { ui_pop_focus_hot(); state->focus_hot_stack.auto_pop = 0; }\ if(state->focus_active_stack.auto_pop) { ui_pop_focus_active(); state->focus_active_stack.auto_pop = 0; }\ if(state->fastpath_codepoint_stack.auto_pop) { ui_pop_fastpath_codepoint(); state->fastpath_codepoint_stack.auto_pop = 0; }\ if(state->group_key_stack.auto_pop) { ui_pop_group_key(); state->group_key_stack.auto_pop = 0; }\ if(state->transparency_stack.auto_pop) { ui_pop_transparency(); state->transparency_stack.auto_pop = 0; }\ -if(state->palette_stack.auto_pop) { ui_pop_palette(); state->palette_stack.auto_pop = 0; }\ +if(state->tag_stack.auto_pop) { ui_pop_tag(); state->tag_stack.auto_pop = 0; }\ +if(state->background_color_stack.auto_pop) { ui_pop_background_color(); state->background_color_stack.auto_pop = 0; }\ +if(state->text_color_stack.auto_pop) { ui_pop_text_color(); state->text_color_stack.auto_pop = 0; }\ if(state->squish_stack.auto_pop) { ui_pop_squish(); state->squish_stack.auto_pop = 0; }\ if(state->hover_cursor_stack.auto_pop) { ui_pop_hover_cursor(); state->hover_cursor_stack.auto_pop = 0; }\ if(state->font_stack.auto_pop) { ui_pop_font(); state->font_stack.auto_pop = 0; }\ @@ -202,14 +232,19 @@ internal F32 ui_top_fixed_width(void); internal F32 ui_top_fixed_height(void); internal UI_Size ui_top_pref_width(void); internal UI_Size ui_top_pref_height(void); +internal F32 ui_top_min_width(void); +internal F32 ui_top_min_height(void); internal UI_PermissionFlags ui_top_permission_flags(void); internal UI_BoxFlags ui_top_flags(void); +internal UI_BoxFlags ui_top_omit_flags(void); internal UI_FocusKind ui_top_focus_hot(void); internal UI_FocusKind ui_top_focus_active(void); internal U32 ui_top_fastpath_codepoint(void); internal UI_Key ui_top_group_key(void); internal F32 ui_top_transparency(void); -internal UI_Palette* ui_top_palette(void); +internal String8 ui_top_tag(void); +internal Vec4F32 ui_top_background_color(void); +internal Vec4F32 ui_top_text_color(void); internal F32 ui_top_squish(void); internal OS_Cursor ui_top_hover_cursor(void); internal FNT_Tag ui_top_font(void); @@ -231,14 +266,19 @@ internal F32 ui_bottom_fixed_width(void); internal F32 ui_bottom_fixed_height(void); internal UI_Size ui_bottom_pref_width(void); internal UI_Size ui_bottom_pref_height(void); +internal F32 ui_bottom_min_width(void); +internal F32 ui_bottom_min_height(void); internal UI_PermissionFlags ui_bottom_permission_flags(void); internal UI_BoxFlags ui_bottom_flags(void); +internal UI_BoxFlags ui_bottom_omit_flags(void); internal UI_FocusKind ui_bottom_focus_hot(void); internal UI_FocusKind ui_bottom_focus_active(void); internal U32 ui_bottom_fastpath_codepoint(void); internal UI_Key ui_bottom_group_key(void); internal F32 ui_bottom_transparency(void); -internal UI_Palette* ui_bottom_palette(void); +internal String8 ui_bottom_tag(void); +internal Vec4F32 ui_bottom_background_color(void); +internal Vec4F32 ui_bottom_text_color(void); internal F32 ui_bottom_squish(void); internal OS_Cursor ui_bottom_hover_cursor(void); internal FNT_Tag ui_bottom_font(void); @@ -260,14 +300,19 @@ internal F32 ui_push_fixed_width(F32 v); internal F32 ui_push_fixed_height(F32 v); internal UI_Size ui_push_pref_width(UI_Size v); internal UI_Size ui_push_pref_height(UI_Size v); +internal F32 ui_push_min_width(F32 v); +internal F32 ui_push_min_height(F32 v); internal UI_PermissionFlags ui_push_permission_flags(UI_PermissionFlags v); internal UI_BoxFlags ui_push_flags(UI_BoxFlags v); +internal UI_BoxFlags ui_push_omit_flags(UI_BoxFlags v); internal UI_FocusKind ui_push_focus_hot(UI_FocusKind v); internal UI_FocusKind ui_push_focus_active(UI_FocusKind v); internal U32 ui_push_fastpath_codepoint(U32 v); internal UI_Key ui_push_group_key(UI_Key v); internal F32 ui_push_transparency(F32 v); -internal UI_Palette* ui_push_palette(UI_Palette* v); +internal String8 ui_push_tag(String8 v); +internal Vec4F32 ui_push_background_color(Vec4F32 v); +internal Vec4F32 ui_push_text_color(Vec4F32 v); internal F32 ui_push_squish(F32 v); internal OS_Cursor ui_push_hover_cursor(OS_Cursor v); internal FNT_Tag ui_push_font(FNT_Tag v); @@ -289,14 +334,19 @@ internal F32 ui_pop_fixed_width(void); internal F32 ui_pop_fixed_height(void); internal UI_Size ui_pop_pref_width(void); internal UI_Size ui_pop_pref_height(void); +internal F32 ui_pop_min_width(void); +internal F32 ui_pop_min_height(void); internal UI_PermissionFlags ui_pop_permission_flags(void); internal UI_BoxFlags ui_pop_flags(void); +internal UI_BoxFlags ui_pop_omit_flags(void); internal UI_FocusKind ui_pop_focus_hot(void); internal UI_FocusKind ui_pop_focus_active(void); internal U32 ui_pop_fastpath_codepoint(void); internal UI_Key ui_pop_group_key(void); internal F32 ui_pop_transparency(void); -internal UI_Palette* ui_pop_palette(void); +internal String8 ui_pop_tag(void); +internal Vec4F32 ui_pop_background_color(void); +internal Vec4F32 ui_pop_text_color(void); internal F32 ui_pop_squish(void); internal OS_Cursor ui_pop_hover_cursor(void); internal FNT_Tag ui_pop_font(void); @@ -318,14 +368,19 @@ internal F32 ui_set_next_fixed_width(F32 v); internal F32 ui_set_next_fixed_height(F32 v); internal UI_Size ui_set_next_pref_width(UI_Size v); internal UI_Size ui_set_next_pref_height(UI_Size v); +internal F32 ui_set_next_min_width(F32 v); +internal F32 ui_set_next_min_height(F32 v); internal UI_PermissionFlags ui_set_next_permission_flags(UI_PermissionFlags v); internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v); +internal UI_BoxFlags ui_set_next_omit_flags(UI_BoxFlags v); internal UI_FocusKind ui_set_next_focus_hot(UI_FocusKind v); internal UI_FocusKind ui_set_next_focus_active(UI_FocusKind v); internal U32 ui_set_next_fastpath_codepoint(U32 v); internal UI_Key ui_set_next_group_key(UI_Key v); internal F32 ui_set_next_transparency(F32 v); -internal UI_Palette* ui_set_next_palette(UI_Palette* v); +internal String8 ui_set_next_tag(String8 v); +internal Vec4F32 ui_set_next_background_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_color(Vec4F32 v); internal F32 ui_set_next_squish(F32 v); internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v); internal FNT_Tag ui_set_next_font(FNT_Tag v); diff --git a/src/ui/ui.mdesk b/src/ui/ui.mdesk index 07978b11..cbe35c8a 100644 --- a/src/ui/ui.mdesk +++ b/src/ui/ui.mdesk @@ -3,11 +3,11 @@ //- rjf: stack table -@table(name, name_lower, type, default) +@table(name, name_lower, type, default, manual_impl) UI_StackTable: { //- rjf: parents - { Parent parent `UI_Box *` `&ui_nil_box` } + { Parent parent `UI_Box *` `&ui_nil_box` } //- rjf: layout params { ChildLayoutAxis child_layout_axis Axis2 `Axis2_X` } @@ -19,10 +19,13 @@ UI_StackTable: { FixedHeight fixed_height F32 0 } { PrefWidth pref_width UI_Size `ui_px(250.f, 1.f)` } { PrefHeight pref_height UI_Size `ui_px(30.f, 1.f)` } + { MinWidth min_width F32 0 } + { MinHeight min_height F32 0 } //- rjf: flags { PermissionFlags permission_flags UI_PermissionFlags UI_PermissionFlag_All } { Flags flags UI_BoxFlags 0 } + { OmitFlags omit_flags UI_BoxFlags 0 } //- rjf: interaction { FocusHot focus_hot UI_FocusKind UI_FocusKind_Null } @@ -32,7 +35,9 @@ UI_StackTable: //- rjf: colors { Transparency transparency F32 0 } - { Palette palette `UI_Palette* ` `&ui_g_nil_palette` } + { Tag tag String8 `str8_lit("")` 1 } + { BackgroundColor background_color Vec4F32 `v4f32(0, 0, 0, 0)` } + { TextColor text_color Vec4F32 `v4f32(0, 0, 0, 0)` } //- rjf: squish { Squish squish F32 0 } @@ -94,7 +99,7 @@ UI_StackTable: `#define UI_DeclStacks \\`; `struct\\`; `{\\`; - @expand(UI_StackTable a) `struct { UI_$(a.name)Node *top; $(a.type) bottom_val; UI_$(a.name)Node *free; B32 auto_pop; } $(a.name_lower)_stack;\\`; + @expand(UI_StackTable a) `struct { UI_$(a.name)Node *top; $(a.type) bottom_val; UI_$(a.name)Node *free; U64 gen; B32 auto_pop; } $(a.name_lower)_stack;\\`; `}`; } @@ -148,13 +153,13 @@ UI_StackTable: @gen @c_file { @expand(UI_StackTable a) - `internal $(a.type) ui_top_$(a.name_lower)(void) { UI_StackTopImpl(ui_state, $(a.name), $(a.name_lower)) }`; + `$(a.manual_impl == "" -> "internal " .. a.type .. " ui_top_" .. a.name_lower .. "(void) { UI_StackTopImpl(ui_state, " .. a.name .. ", " .. a.name_lower .. ") }")`; @expand(UI_StackTable a) - `internal $(a.type) ui_bottom_$(a.name_lower)(void) { UI_StackBottomImpl(ui_state, $(a.name), $(a.name_lower)) }`; + `$(a.manual_impl == "" -> "internal " .. a.type .. " ui_bottom_" .. a.name_lower .. "(void) { UI_StackBottomImpl(ui_state, " .. a.name .. ", " .. a.name_lower .. ") }")`; @expand(UI_StackTable a) - `internal $(a.type) ui_push_$(a.name_lower)($(a.type) v) { UI_StackPushImpl(ui_state, $(a.name), $(a.name_lower), $(a.type), v) }`; + `$(a.manual_impl == "" -> "internal " .. a.type .. " ui_push_" .. a.name_lower .. "(" .. a.type .. " v) { UI_StackPushImpl(ui_state, " .. a.name .. ", " .. a.name_lower .. ", " .. a.type .. ", v) }")`; @expand(UI_StackTable a) - `internal $(a.type) ui_pop_$(a.name_lower)(void) { UI_StackPopImpl(ui_state, $(a.name), $(a.name_lower)) }`; + `$(a.manual_impl == "" -> "internal " .. a.type .. " ui_pop_" .. a.name_lower .. "(void) { UI_StackPopImpl(ui_state, " .. a.name .. ", " .. a.name_lower .. ") }")`; @expand(UI_StackTable a) - `internal $(a.type) ui_set_next_$(a.name_lower)($(a.type) v) { UI_StackSetNextImpl(ui_state, $(a.name), $(a.name_lower), $(a.type), v) }`; + `$(a.manual_impl == "" -> "internal " .. a.type .. " ui_set_next_" .. a.name_lower .. "(" .. a.type .. " v) { UI_StackSetNextImpl(ui_state, " .. a.name .. ", " .. a.name_lower .. ", " .. a.type .. ", v) }")`; } diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c index 22c61052..de24ce72 100644 --- a/src/ui/ui_basic_widgets.c +++ b/src/ui/ui_basic_widgets.c @@ -70,7 +70,6 @@ ui_label_multilinef(F32 max, char *fmt, ...) internal UI_Signal ui_button(String8 string) { - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBorder| @@ -134,9 +133,9 @@ internal UI_BOX_CUSTOM_DRAW(ui_line_edit_draw) FNT_Tag font = box->font; F32 font_size = box->font_size; F32 tab_size = box->tab_size; - Vec4F32 cursor_color = box->palette->colors[UI_ColorCode_Cursor]; + Vec4F32 cursor_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("cursor")); cursor_color.w *= box->parent->parent->focus_active_t; - Vec4F32 select_color = box->palette->colors[UI_ColorCode_Selection]; + Vec4F32 select_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("selection")); select_color.w *= (box->parent->parent->focus_active_t*0.2f + 0.8f); Vec2F32 text_position = ui_box_text_position(box); String8 edited_string = draw_data->edited_string; @@ -144,24 +143,24 @@ internal UI_BOX_CUSTOM_DRAW(ui_line_edit_draw) TxtPt mark = draw_data->mark; F32 cursor_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, cursor.column-1)).x; F32 mark_pixel_off = fnt_dim_from_tag_size_string(font, font_size, 0, tab_size, str8_prefix(edited_string, mark.column-1)).x; - F32 cursor_thickness = ClampBot(4.f, font_size/6.f); + F32 cursor_thickness = ClampBot(1.f, floor_f32(font_size/10.f)); Rng2F32 cursor_rect = { - text_position.x + cursor_pixel_off - cursor_thickness*0.50f, - box->rect.y0+4.f, - text_position.x + cursor_pixel_off + cursor_thickness*0.50f, - box->rect.y1-4.f, + text_position.x + cursor_pixel_off, + box->parent->parent->rect.y0+ui_top_font_size()*0.5f, + text_position.x + cursor_pixel_off + cursor_thickness, + box->parent->parent->rect.y1-ui_top_font_size()*0.5f, }; Rng2F32 mark_rect = { - text_position.x + mark_pixel_off - cursor_thickness*0.50f, - box->rect.y0+2.f, - text_position.x + mark_pixel_off + cursor_thickness*0.50f, - box->rect.y1-2.f, + text_position.x + mark_pixel_off - cursor_thickness, + box->parent->parent->rect.y0+ui_top_font_size()*0.5f, + text_position.x + mark_pixel_off + cursor_thickness, + box->parent->parent->rect.y1-ui_top_font_size()*0.5f, }; Rng2F32 select_rect = union_2f32(cursor_rect, mark_rect); dr_rect(select_rect, select_color, font_size/2.f, 0, 1.f); - dr_rect(cursor_rect, cursor_color, 0.f, 0, 1.f); + dr_rect(cursor_rect, cursor_color, 0.f, 0, 0.f); } internal UI_Signal @@ -181,7 +180,7 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, B32 is_focus_active_disabled = (!is_focus_active && ui_top_focus_active() == UI_FocusKind_On); //- rjf: build top-level box - ui_set_next_hover_cursor(is_focus_active ? OS_Cursor_IBar : OS_Cursor_HandPoint); + ui_set_next_hover_cursor(is_focus_active ? OS_Cursor_IBar : OS_Cursor_Pointer); UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawBackground| UI_BoxFlag_DrawBorder| UI_BoxFlag_MouseClickable| @@ -480,7 +479,7 @@ ui_do_color_tooltip_hsv(Vec3F32 hsv) { UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) UI_Row UI_Padding(ui_pct(1, 0)) { - UI_Palette(ui_build_palette(ui_top_palette(), .background = v4f32(rgb.x, rgb.y, rgb.z, 1.f))) + UI_BackgroundColor(linear_from_srgba(v4f32(rgb.x, rgb.y, rgb.z, 1.f))) UI_CornerRadius(4.f) UI_PrefWidth(ui_em(6.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) ui_build_box_from_string(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, str8_lit("")); @@ -519,7 +518,7 @@ ui_do_color_tooltip_hsva(Vec4F32 hsva) { UI_PrefWidth(ui_em(22.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) UI_Row UI_Padding(ui_pct(1, 0)) { - UI_Palette(ui_build_palette(ui_top_palette(), .background = rgba)) + UI_BackgroundColor(linear_from_srgba(rgba)) UI_CornerRadius(4.f) UI_PrefWidth(ui_em(6.f, 1.f)) UI_PrefHeight(ui_em(6.f, 1.f)) ui_build_box_from_string(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, str8_lit("")); @@ -566,20 +565,40 @@ internal UI_BOX_CUSTOM_DRAW(ui_sat_val_picker_draw) // rjf: hue => rgb Vec3F32 hue_rgb = rgb_from_hsv(v3f32(data->hue, 1, 1)); + Vec3F32 hue_rgb_linear = linear_from_srgb(hue_rgb); - // rjf: white -> rgb background + // rjf: rgb background { - R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, -1.f), v4f32(hue_rgb.x, hue_rgb.y, hue_rgb.z, 1), 4.f, 0, 1.f); + dr_rect(pad_2f32(box->rect, -1.f), v4f32(hue_rgb_linear.x, hue_rgb_linear.y, hue_rgb_linear.z, 1), 4.f, 0, 1.f); + } + + // rjf: white gradient overlay + { + R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, -1.f), v4f32(hue_rgb_linear.x, hue_rgb_linear.y, hue_rgb_linear.z, 0), 4.f, 0, 1.f); inst->colors[Corner_00] = inst->colors[Corner_01] = v4f32(1, 1, 1, 1); } - // rjf: black gradient overlay + // rjf: black gradient overlay pt. 1 + { + R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, -1.f), v4f32(0, 0, 0, 0), 4.f, 0, 1.f); + inst->colors[Corner_01] = v4f32(0, 0, 0, 1.f); + inst->colors[Corner_11] = v4f32(0, 0, 0, 1.f); + } + + // rjf: black gradient overlay pt. 2 { R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, -1.f), v4f32(0, 0, 0, 0), 4.f, 0, 1.f); inst->colors[Corner_01] = v4f32(0, 0, 0, 1); inst->colors[Corner_11] = v4f32(0, 0, 0, 1); } + // rjf: black gradient overlay pt. 3 + { + R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, -1.f), v4f32(0, 0, 0, 0), 4.f, 0, 1.f); + inst->colors[Corner_01] = v4f32(0, 0, 0, 0.2f); + inst->colors[Corner_11] = v4f32(0, 0, 0, 0.2f); + } + // rjf: indicator { Vec2F32 box_rect_dim = dim_2f32(box->rect); @@ -589,7 +608,7 @@ internal UI_BOX_CUSTOM_DRAW(ui_sat_val_picker_draw) center.y - half_size, center.x + half_size, center.y + half_size); - dr_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + dr_rect(rect, v4f32(1, 1, 1, 1), half_size/2.f, 2.f, 1.f); } } @@ -678,13 +697,13 @@ internal UI_BOX_CUSTOM_DRAW(ui_hue_picker_draw) F32 hue1 = (F32)(seg+1)/6; Vec3F32 rgb0 = rgb_from_hsv(v3f32(hue0, 1, 1)); Vec3F32 rgb1 = rgb_from_hsv(v3f32(hue1, 1, 1)); - Vec4F32 rgba0 = v4f32(rgb0.x, rgb0.y, rgb0.z, 1); - Vec4F32 rgba1 = v4f32(rgb1.x, rgb1.y, rgb1.z, 1); + Vec4F32 rgba0_linear = linear_from_srgba(v4f32(rgb0.x, rgb0.y, rgb0.z, 1)); + Vec4F32 rgba1_linear = linear_from_srgba(v4f32(rgb1.x, rgb1.y, rgb1.z, 1)); R_Rect2DInst *inst = dr_rect(rect, v4f32(0, 0, 0, 0), 0, 0, 0.f); - inst->colors[Corner_00] = rgba0; - inst->colors[Corner_01] = rgba1; - inst->colors[Corner_10] = rgba0; - inst->colors[Corner_11] = rgba1; + inst->colors[Corner_00] = rgba0_linear; + inst->colors[Corner_01] = rgba1_linear; + inst->colors[Corner_10] = rgba0_linear; + inst->colors[Corner_11] = rgba1_linear; rect.y0 += segment_dim; rect.y1 += segment_dim; } @@ -692,13 +711,13 @@ internal UI_BOX_CUSTOM_DRAW(ui_hue_picker_draw) // rjf: indicator { Vec2F32 box_rect_dim = dim_2f32(box->rect); - Vec2F32 center = v2f32((box->rect.x0+box->rect.x1)/2, box->rect.y0 + data->hue*box_rect_dim.y); - F32 half_size = box->font_size * (0.5f + box->active_t*0.2f); + Vec2F32 center = v2f32((box->rect.x0+box->rect.x1)/2, box->rect.y0 + (data->hue)*box_rect_dim.y); + F32 half_size = box_rect_dim.x * (0.52f + 0.02f * box->active_t); Rng2F32 rect = r2f32p(center.x - half_size, - center.y - 2.f, + center.y - box->font_size * (0.5f + 0.1f * box->active_t), center.x + half_size, - center.y + 2.f); - dr_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + center.y + box->font_size * (0.5f + 0.1f * box->active_t)); + dr_rect(rect, v4f32(1, 1, 1, 1), 1.f, 2.f, 1.f); } } @@ -780,12 +799,12 @@ internal UI_BOX_CUSTOM_DRAW(ui_alpha_picker_draw) { Vec2F32 box_rect_dim = dim_2f32(box->rect); Vec2F32 center = v2f32((box->rect.x0+box->rect.x1)/2, box->rect.y0 + (1-data->alpha)*box_rect_dim.y); - F32 half_size = box->font_size * (0.5f + box->active_t*0.2f); + F32 half_size = box_rect_dim.x * (0.52f + 0.02f * box->active_t); Rng2F32 rect = r2f32p(center.x - half_size, - center.y - 2.f, + center.y - box->font_size * (0.5f + 0.1f * box->active_t), center.x + half_size, - center.y + 2.f); - dr_rect(rect, v4f32(1, 1, 1, 1), half_size/2, 2.f, 1.f); + center.y + box->font_size * (0.5f + 0.1f * box->active_t)); + dr_rect(rect, v4f32(1, 1, 1, 1), 1.f, 2.f, 1.f); } } @@ -1212,7 +1231,8 @@ ui_scroll_list_item_from_row(UI_ScrollListRowBlockArray *blocks, U64 row) internal UI_ScrollPt ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_range, S64 view_num_indices) { - ui_push_palette(ui_state->widget_palette_info.scrollbar_palette); + ui_push_tag(str8_lit("scroll_bar")); + ui_push_font_size(ui_bottom_font_size()*0.65f); //- rjf: unpack S64 idx_range_dim = Max(dim_1s64(idx_range), 1); @@ -1258,13 +1278,12 @@ ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_ran if(idx_range.max != idx_range.min) { ui_set_next_pref_size(axis, ui_pct((F32)((F64)(pt.idx-idx_range.min)/(F64)idx_range_dim), 0)); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *space_before_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "##scroll_area_before"); space_before_sig = ui_signal_from_box(space_before_box); } // rjf: scroller - UI_Flags(disabled_flags) UI_PrefSize(axis, ui_pct(Clamp(0.01f, (F32)((F64)Max(view_num_indices, 1)/(F64)idx_range_dim), 1.f), 0.f)) + UI_Flags(disabled_flags) UI_PrefSize(axis, ui_pct(Clamp(0.05f, (F32)((F64)Max(view_num_indices, 1)/(F64)idx_range_dim), 1.f), 0.f)) { scroller_sig = ui_buttonf("##_scroller_%i", axis); scroller_box = scroller_sig.box; @@ -1274,7 +1293,6 @@ ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_ran if(idx_range.max != idx_range.min) { ui_set_next_pref_size(axis, ui_pct(1.f - (F32)((F64)(pt.idx-idx_range.min)/(F64)idx_range_dim), 0)); - ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *space_after_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable, "##scroll_area_after"); space_after_sig = ui_signal_from_box(space_after_box); } @@ -1332,7 +1350,8 @@ ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_ran } } - ui_pop_palette(); + ui_pop_font_size(); + ui_pop_tag(); return new_pt; } @@ -1458,7 +1477,7 @@ ui_scroll_list_begin(UI_ScrollListParams *params, UI_ScrollPt *scroll_pt, Vec2S6 *visible_row_range_out = visible_row_range; //- rjf: store thread-locals - ui_scroll_list_scroll_bar_dim_px = ui_top_font_size()*1.5f; + ui_scroll_list_scroll_bar_dim_px = ui_bottom_font_size()*1.5f; ui_scroll_list_scroll_pt_ptr = scroll_pt; ui_scroll_list_dim_px = params->dim_px; ui_scroll_list_scroll_idx_rng = scroll_row_idx_range; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 532ed66f..9659939d 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1,9 +1,6 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.80f, 0.40f, 0.35f - //////////////////////////////// //~ rjf: Globals @@ -435,6 +432,8 @@ ui_state_alloc(void) ui->box_table = push_array(arena, UI_BoxHashSlot, ui->box_table_size); ui->anim_slots_count = 4096; ui->anim_slots = push_array(arena, UI_AnimSlot, ui->anim_slots_count); + ui->theme_pattern_cache_slots_count = 1024; + ui->theme_pattern_cache_slots = push_array(arena, UI_ThemePatternCacheSlot, ui->theme_pattern_cache_slots_count); UI_InitStackNils(ui); return ui; } @@ -557,22 +556,30 @@ ui_next_event(UI_Event **ev) { good = 0; } - if(!(perms & UI_PermissionFlag_ScrollX) && (n->v.kind == UI_EventKind_Scroll) && (n->v.delta_2f32.x != 0 || n->v.modifiers & OS_Modifier_Shift)) + if(!(perms & UI_PermissionFlag_ScrollX) && (n->v.kind == UI_EventKind_Scroll) && (n->v.delta_2f32.x != 0 || n->v.modifiers == OS_Modifier_Shift)) { good = 0; } - if(!(perms & UI_PermissionFlag_ScrollY) && (n->v.kind == UI_EventKind_Scroll) && n->v.delta_2f32.y != 0 && !(n->v.modifiers & OS_Modifier_Shift)) + if(!(perms & UI_PermissionFlag_ScrollY) && (n->v.kind == UI_EventKind_Scroll) && n->v.delta_2f32.y != 0 && n->v.modifiers == 0) { good = 0; } - if(!(perms & UI_PermissionFlag_Keyboard) && - (n->v.kind == UI_EventKind_Press || - n->v.kind == UI_EventKind_Release) && + if((n->v.kind == UI_EventKind_Press || + n->v.kind == UI_EventKind_Release || + n->v.kind == UI_EventKind_Navigate || + n->v.kind == UI_EventKind_Edit) && (n->v.key != OS_Key_LeftMouseButton && n->v.key != OS_Key_MiddleMouseButton && n->v.key != OS_Key_RightMouseButton)) { - good = 0; + if((perms & UI_PermissionFlag_Keyboard) == UI_PermissionFlag_KeyboardSecondary) + { + good = !!(n->v.flags & UI_EventFlag_Secondary); + } + else if(!(perms & UI_PermissionFlag_Keyboard)) + { + good = 0; + } } else if(!(perms & UI_PermissionFlag_Text) && (n->v.kind == UI_EventKind_Text)) { @@ -668,6 +675,28 @@ ui_slot_press(UI_EventActionSlot slot) return result; } +//- rjf: autocomplete info + +internal void +ui_set_autocomplete_string(String8 string) +{ + ui_state->autocomplete_string = push_str8_copy(ui_build_arena(), string); +} + +internal String8 +ui_autocomplete_string(void) +{ + return ui_state->autocomplete_string; +} + +internal String8 +ui_autocomplete(void) +{ + String8 result = ui_state->autocomplete_string; + MemoryZeroStruct(&ui_state->autocomplete_string); + return result; +} + //- rjf: drag data internal Vec2F32 @@ -717,17 +746,10 @@ ui_string_hover_begin_time_us(void) return ui_state->string_hover_begin_us; } -internal String8 -ui_string_hover_string(Arena *arena) +internal DR_FStrList +ui_string_hover_fstrs(Arena *arena) { - String8 result = push_str8_copy(arena, ui_state->string_hover_string); - return result; -} - -internal DR_FancyRunList -ui_string_hover_runs(Arena *arena) -{ - DR_FancyRunList result = dr_fancy_run_list_copy(arena, &ui_state->string_hover_fancy_runs); + DR_FStrList result = dr_fstrs_copy(arena, &ui_state->string_hover_fstrs); return result; } @@ -789,7 +811,7 @@ ui_box_from_key(UI_Key key) //~ rjf: Top-Level Building API internal void -ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, UI_WidgetPaletteInfo *widget_palette_info, UI_AnimationInfo *animation_info, F32 real_dt, F32 animation_dt) +ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, UI_Theme *theme, UI_AnimationInfo *animation_info, F32 real_dt, F32 animation_dt) { //- rjf: reset per-build ui state { @@ -802,7 +824,13 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U ui_state->build_box_count = 0; ui_state->tooltip_open = 0; ui_state->ctx_menu_changed = 0; - ui_state->default_animation_rate = 1 - pow_f32(2, (-50.f * ui_state->animation_dt)); + ui_state->default_animation_rate = 1 - pow_f32(2, (-60.f * ui_state->animation_dt)); + ui_state->tooltip_can_overflow_window = 0; + ui_state->tooltip_anchor_key = ui_key_zero(); + ui_state->tags_key_stack_top = ui_state->tags_key_stack_free = 0; + ui_state->tags_cache_slots_count = 512; + ui_state->tags_cache_slots = push_array(ui_build_arena(), UI_TagsCacheSlot, ui_state->tags_cache_slots_count); + ui_state->autocomplete_string = str8_zero(); } //- rjf: prune unused animation nodes @@ -811,7 +839,7 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U for(UI_AnimNode *n = ui_state->lru_anim_node, *next = &ui_nil_anim_node; n != &ui_nil_anim_node && n != 0; n = next) { next = n->lru_next; - if(n->last_touched_build_index+1 < ui_state->build_index) + if(n->last_touched_build_index+2 < ui_state->build_index) { U64 slot_idx = n->key.u64[0]%ui_state->anim_slots_count; UI_AnimSlot *slot = &ui_state->anim_slots[slot_idx]; @@ -826,6 +854,27 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U } } + //- rjf: prune unused theme pattern cache nodes + ProfScope("ui prune unused theme pattern cache") + { + for(UI_ThemePatternCacheNode *n = ui_state->lru_theme_pattern_cache_node, *next = 0; n != 0; n = next) + { + next = n->lru_next; + if(n->last_build_index_accessed+2 < ui_state->build_index) + { + U64 slot_idx = n->key.u64[0]%ui_state->theme_pattern_cache_slots_count; + UI_ThemePatternCacheSlot *slot = &ui_state->theme_pattern_cache_slots[slot_idx]; + DLLRemove_NP(slot->first, slot->last, n, slot_next, slot_prev); + DLLRemove_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, n, lru_next, lru_prev); + SLLStackPush_N(ui_state->theme_pattern_cache_node_free, n, slot_next); + } + else + { + break; + } + } + } + //- rjf: detect mouse-moves for(UI_EventNode *n = events->first; n != 0; n = n->next) { @@ -850,6 +899,7 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U //- rjf: fill build phase parameters { + ui_state->theme = theme; ui_state->events = events; ui_state->window = window; ui_state->mouse = (os_window_is_focused(window) || ui_state->last_time_mousemoved_us+500000 >= os_now_microseconds()) ? os_mouse_from_window(window) : v2f32(-100, -100); @@ -862,7 +912,6 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U { ui_state->icon_info.icon_kind_text_map[icon_kind] = push_str8_copy(ui_build_arena(), icon_info->icon_kind_text_map[icon_kind]); } - MemoryCopyStruct(&ui_state->widget_palette_info, widget_palette_info); MemoryCopyStruct(&ui_state->animation_info, animation_info); } @@ -1118,11 +1167,15 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U Vec2F32 anchor = add_2f32(ui_state->ctx_menu_anchor_box_last_pos, ui_state->ctx_menu_anchor_off); UI_FixedX(anchor.x) UI_FixedY(anchor.y) UI_PrefWidth(ui_children_sum(1.f)) UI_PrefHeight(ui_children_sum(1.f)) UI_Focus(UI_FocusKind_On) - UI_Squish(0.25f-ui_state->ctx_menu_open_t*0.25f) + UI_Squish(0.1f-ui_state->ctx_menu_open_t*0.1f) UI_Transparency(1-ui_state->ctx_menu_open_t) { ui_set_next_child_layout_axis(Axis2_Y); - ui_state->ctx_menu_root = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawDropShadow|(ui_state->ctx_menu_open*UI_BoxFlag_DefaultFocusNavY), "###ctx_menu_%I64x", window.u64[0]); + ui_state->ctx_menu_root = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_SquishAnchored| + UI_BoxFlag_DrawDropShadow| + (ui_state->ctx_menu_open*UI_BoxFlag_DefaultFocusNavY), + "###ctx_menu_%I64x", window.u64[0]); } } @@ -1169,6 +1222,12 @@ ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, U ui_state->active_box_key[k] = ui_key_zero(); } } + + //- rjf: escape -> close context menu + if(ui_any_ctx_menu_is_open() && ui_slot_press(UI_EventActionSlot_Cancel)) + { + ui_ctx_menu_close(); + } } internal void @@ -1176,12 +1235,6 @@ ui_end_build(void) { ProfBeginFunction(); - //- rjf: escape -> close context menu - if(ui_state->ctx_menu_open != 0 && ui_slot_press(UI_EventActionSlot_Cancel)) - { - ui_ctx_menu_close(); - } - //- rjf: prune untouched or transient boxes in the cache ProfScope("ui prune unused boxes") { @@ -1237,13 +1290,30 @@ ui_end_build(void) } } + //- rjf: anchor tooltips + if(!ui_key_match(ui_state->tooltip_anchor_key, ui_key_zero())) + { + UI_Box *anchor_box = ui_box_from_key(ui_state->tooltip_anchor_key); + if(!ui_box_is_nil(anchor_box)) + { + Vec2F32 dim = dim_2f32(ui_state->tooltip_root->rect); + ui_state->tooltip_root->fixed_position.x = ui_state->tooltip_root->rect.x0 = anchor_box->rect.x0; + ui_state->tooltip_root->fixed_position.y = ui_state->tooltip_root->rect.y0 = anchor_box->rect.y1 + anchor_box->font_size*0.5f; + ui_state->tooltip_root->rect.x1 = ui_state->tooltip_root->rect.x0 + dim.x; + ui_state->tooltip_root->rect.y1 = ui_state->tooltip_root->rect.y0 + dim.y; + } + else + { + ui_state->tooltip_root->rect.x0 = 10000; + ui_state->tooltip_root->rect.y0 = 10000; + } + } + //- rjf: ensure special floating roots are within screen bounds UI_Box *floating_roots[] = {ui_state->tooltip_root, ui_state->ctx_menu_root}; B32 force_contain[] = { - (ui_key_match(ui_active_key(UI_MouseButtonKind_Left), ui_key_zero()) && - ui_key_match(ui_active_key(UI_MouseButtonKind_Right), ui_key_zero()) && - ui_key_match(ui_active_key(UI_MouseButtonKind_Middle), ui_key_zero())), + !ui_state->tooltip_can_overflow_window, 1, }; for(U64 idx = 0; idx < ArrayCount(floating_roots); idx += 1) @@ -1271,11 +1341,11 @@ ui_end_build(void) root->rect = new_root_rect; for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis + 1)) { - ui_calc_sizes_standalone__in_place_rec(root, axis); - ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); - ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); - ui_layout_enforce_constraints__in_place_rec(root, axis); - ui_layout_position__in_place_rec(root, axis); + ui_calc_sizes_standalone__in_place(root, axis); + ui_calc_sizes_upwards_dependent__in_place(root, axis); + ui_calc_sizes_downwards_dependent__in_place(root, axis); + ui_layout_enforce_constraints__in_place(root, axis); + ui_layout_position__in_place(root, axis); } } } @@ -1288,9 +1358,31 @@ ui_end_build(void) !ui_box_is_nil(box); box = box->hash_next) { - if(box->flags & UI_BoxFlag_RoundChildrenByParent && - !ui_box_is_nil(box->first) && !ui_box_is_nil(box->last)) + if(box->flags & UI_BoxFlag_RoundChildrenByParent) { + for(UI_Box *b = box; !ui_box_is_nil(b); b = ui_box_rec_df_pre(b, box).next) + { + if(floor_f32(b->rect.x0) <= floor_f32(box->rect.x0) && + floor_f32(b->rect.y0) <= floor_f32(box->rect.y0)) + { + b->corner_radii[Corner_00] = box->corner_radii[Corner_00]; + } + if(floor_f32(b->rect.x1) >= floor_f32(box->rect.x1) && + floor_f32(b->rect.y0) <= floor_f32(box->rect.y0)) + { + b->corner_radii[Corner_10] = box->corner_radii[Corner_10]; + } + if(floor_f32(b->rect.x0) <= floor_f32(box->rect.x0) && + floor_f32(b->rect.y1) >= floor_f32(box->rect.y1)) + { + b->corner_radii[Corner_01] = box->corner_radii[Corner_01]; + } + if(floor_f32(b->rect.x1) >= floor_f32(box->rect.x1) && + floor_f32(b->rect.y1) >= floor_f32(box->rect.y1)) + { + b->corner_radii[Corner_11] = box->corner_radii[Corner_11]; + } + } box->first->corner_radii[Corner_00] = box->corner_radii[Corner_00]; box->first->corner_radii[Corner_10] = box->corner_radii[Corner_10]; box->last->corner_radii[Corner_01] = box->corner_radii[Corner_01]; @@ -1313,19 +1405,28 @@ ui_end_build(void) ui_state->is_animating = (ui_state->is_animating || abs_f32(n->params.target - n->current) > n->params.epsilon); } } - F32 vast_rate = 1 - pow_f32(2, (-60.f * ui_state->animation_dt)); - F32 fast_rate = 1 - pow_f32(2, (-50.f * ui_state->animation_dt)); - F32 fish_rate = 1 - pow_f32(2, (-40.f * ui_state->animation_dt)); + F32 fast_rate = ui_state->default_animation_rate; F32 slow_rate = 1 - pow_f32(2, (-30.f * ui_state->animation_dt)); - F32 slug_rate = 1 - pow_f32(2, (-15.f * ui_state->animation_dt)); - F32 slaf_rate = 1 - pow_f32(2, (-8.f * ui_state->animation_dt)); - ui_state->ctx_menu_open_t += ((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) * (ui_state->animation_info.flags & UI_AnimationInfoFlag_ContextMenuAnimations ? vast_rate : 1); + for(U64 slot_idx = 0; slot_idx < ui_state->theme_pattern_cache_slots_count; slot_idx += 1) + { + for(UI_ThemePatternCacheNode *n = ui_state->theme_pattern_cache_slots[slot_idx].first; + n != 0; + n = n->slot_next) + { + for EachIndex(idx, 4) + { + n->current_rgba.v[idx] += (n->target_rgba.v[idx] - n->current_rgba.v[idx]) * slow_rate; + ui_state->is_animating = (ui_state->is_animating || abs_f32(n->target_rgba.v[idx] - n->current_rgba.v[idx]) > 0.001f); + } + } + } + ui_state->ctx_menu_open_t += ((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) * ui_state->animation_info.menu_animation_rate; ui_state->is_animating = (ui_state->is_animating || abs_f32((F32)!!ui_state->ctx_menu_open - ui_state->ctx_menu_open_t) > 0.01f); if(ui_state->ctx_menu_open_t >= 0.99f && ui_state->ctx_menu_open) { ui_state->ctx_menu_open_t = 1.f; } - ui_state->tooltip_open_t += ((F32)!!ui_state->tooltip_open - ui_state->tooltip_open_t) * (ui_state->animation_info.flags & UI_AnimationInfoFlag_TooltipAnimations ? vast_rate : 1); + ui_state->tooltip_open_t += ((F32)!!ui_state->tooltip_open - ui_state->tooltip_open_t) * ui_state->animation_info.tooltip_animation_rate; ui_state->is_animating = (ui_state->is_animating || abs_f32((F32)!!ui_state->tooltip_open - ui_state->tooltip_open_t) > 0.01f); if(ui_state->tooltip_open_t >= 0.99f && ui_state->tooltip_open) { @@ -1338,7 +1439,8 @@ ui_end_build(void) box = box->hash_next) { // rjf: grab states informing animation - B32 is_hot = ui_key_match(box->key, ui_state->hot_box_key); + B32 is_hot = (ui_key_match(box->key, ui_state->hot_box_key) || + ui_key_match(box->key, ui_state->drop_hot_box_key)); B32 is_active = ui_key_match(box->key, ui_state->active_box_key[UI_MouseButtonKind_Left]); B32 is_disabled = !!(box->flags & UI_BoxFlag_Disabled) && (box->first_disabled_build_index+2 < ui_state->build_index || box->first_touched_build_index == box->first_disabled_build_index); @@ -1347,10 +1449,10 @@ ui_end_build(void) B32 is_focus_active_disabled = !!(box->flags & UI_BoxFlag_FocusActiveDisabled); // rjf: determine rates - F32 hot_rate = (ui_state->animation_info.flags & UI_AnimationInfoFlag_HotAnimations ? fast_rate : 1); - F32 active_rate = (ui_state->animation_info.flags & UI_AnimationInfoFlag_ActiveAnimations ? fast_rate : 1); - F32 disabled_rate = (ui_state->animation_info.flags & UI_AnimationInfoFlag_HotAnimations ? slow_rate : 1); - F32 focus_rate = (ui_state->animation_info.flags & UI_AnimationInfoFlag_FocusAnimations ? fast_rate : 1); + F32 hot_rate = ui_state->animation_info.hot_animation_rate; + F32 active_rate = ui_state->animation_info.active_animation_rate; + F32 disabled_rate = slow_rate; + F32 focus_rate = ui_state->animation_info.focus_animation_rate; // rjf: determine animating status B32 box_is_animating = 0; @@ -1381,7 +1483,7 @@ ui_end_build(void) // rjf: animate interaction transition states box->hot_t += hot_rate * ((F32)is_hot - box->hot_t); - box->active_t += active_rate * ((F32)is_active - box->active_t); + box->active_t = is_active ? 1.f : box->active_t + (active_rate * ((F32)is_active - box->active_t)); box->disabled_t += disabled_rate * ((F32)is_disabled - box->disabled_t); box->focus_hot_t += focus_rate * ((F32)is_focus_hot - box->focus_hot_t); box->focus_active_t += focus_rate * ((F32)is_focus_active - box->focus_active_t); @@ -1415,8 +1517,8 @@ ui_end_build(void) // rjf: animate view offset { - box->view_off.x += fast_rate * (box->view_off_target.x - box->view_off.x); - box->view_off.y += fast_rate * (box->view_off_target.y - box->view_off.y); + box->view_off.x += ui_state->animation_info.scroll_animation_rate * (box->view_off_target.x - box->view_off.x); + box->view_off.y += ui_state->animation_info.scroll_animation_rate * (box->view_off_target.y - box->view_off.y); if(abs_f32(box->view_off.x - box->view_off_target.x) < 2) { box->view_off.x = box->view_off_target.x; @@ -1430,12 +1532,14 @@ ui_end_build(void) } } - //- rjf: animate context menu - if(ui_state->ctx_menu_open && !ui_box_is_nil(ui_state->ctx_menu_root) && !ui_state->ctx_menu_changed) + //- rjf: use group keys for box animation data if possible + for(UI_Box *b = ui_state->root; !ui_box_is_nil(b); b = ui_box_rec_df_pre(b, ui_state->root).next) { - UI_Box *root = ui_state->ctx_menu_root; - Rng2F32 rect = root->rect; - root->rect.y1 = root->rect.y0 + dim_2f32(rect).y * ui_state->ctx_menu_open_t; + if(ui_key_match(b->key, ui_key_zero()) && !ui_key_match(b->group_key, ui_key_zero())) + { + UI_Box *group_box = ui_box_from_key(b->group_key); + b->hot_t = group_box->hot_t; + } } //- rjf: fall-through interact with context menu @@ -1533,7 +1637,13 @@ ui_end_build(void) } String8 box_display_string = ui_box_display_string(b); Vec2F32 text_pos = ui_box_text_position(b); - Vec2F32 drawn_text_dim = b->display_string_runs.dim; + Vec2F32 drawn_text_dim = {0}; + { + Temp scratch = scratch_begin(0, 0); + DR_FRunList fruns = dr_fruns_from_fstrs(scratch.arena, b->tab_size, &b->display_fstrs); + drawn_text_dim = fruns.dim; + scratch_end(scratch); + } B32 text_is_truncated = (drawn_text_dim.x + text_pos.x > rect.x1); B32 mouse_is_hovering = contains_2f32(r2f32p(text_pos.x, rect.y0, @@ -1542,11 +1652,12 @@ ui_end_build(void) ui_state->mouse); if(text_is_truncated && mouse_is_hovering && !(b->flags & UI_BoxFlag_DisableTruncatedHover)) { - if(!str8_match(box_display_string, ui_state->string_hover_string, 0)) + if(!str8_match(box_display_string, ui_state->string_hover_string, 0) || box->font_size != ui_state->string_hover_size) { arena_clear(ui_state->string_hover_arena); ui_state->string_hover_string = push_str8_copy(ui_state->string_hover_arena, box_display_string); - ui_state->string_hover_fancy_runs = dr_fancy_run_list_copy(ui_state->string_hover_arena, &b->display_string_runs); + ui_state->string_hover_size = box->font_size; + ui_state->string_hover_fstrs = dr_fstrs_copy(ui_state->string_hover_arena, &b->display_fstrs); ui_state->string_hover_begin_us = os_now_microseconds(); } ui_state->string_hover_build_index = ui_state->build_index; @@ -1584,293 +1695,269 @@ ui_end_build(void) } internal void -ui_calc_sizes_standalone__in_place_rec(UI_Box *root, Axis2 axis) +ui_calc_sizes_standalone__in_place(UI_Box *root, Axis2 axis) { ProfBeginFunction(); - - switch(root->pref_size[axis].kind) + for(UI_Box *b = root; !ui_box_is_nil(b); b = ui_box_rec_df_pre(b, root).next) { - default:{}break; - case UI_SizeKind_Pixels: + switch(b->pref_size[axis].kind) { - root->fixed_size.v[axis] = root->pref_size[axis].value; - }break; - - case UI_SizeKind_TextContent: - { - F32 padding = root->pref_size[axis].value; - F32 text_size = root->display_string_runs.dim.x; - root->fixed_size.v[axis] = padding + text_size + root->text_padding*2; - }break; + default:{}break; + case UI_SizeKind_Pixels: + { + b->fixed_size.v[axis] = b->pref_size[axis].value; + }break; + case UI_SizeKind_TextContent: + { + F32 padding = b->pref_size[axis].value; + F32 text_size = b->display_fruns.dim.x; + b->fixed_size.v[axis] = padding + text_size + b->text_padding*2; + }break; + } } - - //- rjf: recurse - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - ui_calc_sizes_standalone__in_place_rec(child, axis); - } - ProfEnd(); } internal void -ui_calc_sizes_upwards_dependent__in_place_rec(UI_Box *root, Axis2 axis) +ui_calc_sizes_upwards_dependent__in_place(UI_Box *root, Axis2 axis) { ProfBeginFunction(); - - //- rjf: solve for all kinds that are upwards-dependent - switch(root->pref_size[axis].kind) + for(UI_Box *b = root; !ui_box_is_nil(b); b = ui_box_rec_df_pre(b, root).next) { - default: break; - - // rjf: if root has a parent percentage, figure out its size - case UI_SizeKind_ParentPct: + switch(b->pref_size[axis].kind) { - // rjf: find parent that has a fixed size - UI_Box *fixed_parent = &ui_nil_box; - for(UI_Box *p = root->parent; !ui_box_is_nil(p); p = p->parent) + default:{}break; + case UI_SizeKind_ParentPct: { - if(p->flags & (UI_BoxFlag_FixedWidth<pref_size[axis].kind == UI_SizeKind_Pixels || - p->pref_size[axis].kind == UI_SizeKind_TextContent || - p->pref_size[axis].kind == UI_SizeKind_ParentPct) + // rjf: find parent that has a fixed size + UI_Box *fixed_parent = &ui_nil_box; + for(UI_Box *p = b->parent; !ui_box_is_nil(p); p = p->parent) { - fixed_parent = p; - break; - } - } - - // rjf: figure out root's size on this axis - F32 size = fixed_parent->fixed_size.v[axis] * root->pref_size[axis].value; - - // rjf: mutate root to have this size - root->fixed_size.v[axis] = size; - }break; - } - - //- rjf: recurse - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - ui_calc_sizes_upwards_dependent__in_place_rec(child, axis); - } - - ProfEnd(); -} - -internal void -ui_calc_sizes_downwards_dependent__in_place_rec(UI_Box *root, Axis2 axis) -{ - ProfBeginFunction(); - - //- rjf: recurse first. we may depend on children that have - // the same property - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - ui_calc_sizes_downwards_dependent__in_place_rec(child, axis); - } - - //- rjf: solve for all kinds that are downwards-dependent - switch(root->pref_size[axis].kind) - { - default: break; - - // rjf: sum children - case UI_SizeKind_ChildrenSum: - { - F32 sum = 0; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - if(!(child->flags & (UI_BoxFlag_FloatingX<child_layout_axis) + if(p->flags & (UI_BoxFlag_FixedWidth<pref_size[axis].kind == UI_SizeKind_Pixels || + p->pref_size[axis].kind == UI_SizeKind_TextContent || + p->pref_size[axis].kind == UI_SizeKind_ParentPct) { - sum += child->fixed_size.v[axis]; - } - else - { - sum = Max(sum, child->fixed_size.v[axis]); + fixed_parent = p; + break; } } - } - - // rjf: figure out root's size on this axis - root->fixed_size.v[axis] = sum; - }break; + + // rjf: figure out box's size on this axis + F32 size = fixed_parent->fixed_size.v[axis] * b->pref_size[axis].value; + + // rjf: mutate box to have this size + b->fixed_size.v[axis] = size; + }break; + } } - ProfEnd(); } internal void -ui_layout_enforce_constraints__in_place_rec(UI_Box *root, Axis2 axis) +ui_calc_sizes_downwards_dependent__in_place(UI_Box *root, Axis2 axis) +{ + ProfBeginFunction(); + UI_BoxRec rec = {0}; + for(UI_Box *box = root; !ui_box_is_nil(box); box = rec.next) + { + rec = ui_box_rec_df_pre(box, root); + S32 pop_idx = 0; + for(UI_Box *b = box; + !ui_box_is_nil(b) && pop_idx <= rec.pop_count; + b = b->parent, pop_idx += 1) + { + if(b->pref_size[axis].kind == UI_SizeKind_ChildrenSum) + { + F32 sum = 0; + for(UI_Box *child = b->first; !ui_box_is_nil(child); child = child->next) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<child_layout_axis) + { + sum += child->fixed_size.v[axis]; + } + else + { + sum = Max(sum, child->fixed_size.v[axis]); + } + } + } + b->fixed_size.v[axis] = sum; + } + } + } + ProfEnd(); +} + +internal void +ui_layout_enforce_constraints__in_place(UI_Box *root, Axis2 axis) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - - // NOTE(rjf): The "layout axis" is the direction in which children - // of some node are intended to be laid out. - - //- rjf: fixup children sizes (if we're solving along the *non-layout* axis) - if(axis != root->child_layout_axis && !(root->flags & (UI_BoxFlag_AllowOverflowX << axis))) + for(UI_Box *box = root; !ui_box_is_nil(box); box = ui_box_rec_df_pre(box, root).next) { - F32 allowed_size = root->fixed_size.v[axis]; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + //- rjf: fixup children sizes (if we're solving along the *non-layout* axis) + if(axis != box->child_layout_axis && !(box->flags & (UI_BoxFlag_AllowOverflowX << axis))) { - if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis]; + for(UI_Box *child = box->first; !ui_box_is_nil(child); child = child->next) { - F32 child_size = child->fixed_size.v[axis]; - F32 violation = child_size - allowed_size; - F32 max_fixup = child_size; - F32 fixup = Clamp(0, violation, max_fixup); - if(fixup > 0) + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] -= fixup; + F32 child_size = child->fixed_size.v[axis]; + F32 violation = child_size - allowed_size; + F32 max_fixup = child_size; + F32 fixup = Clamp(0, violation, max_fixup); + if(fixup > 0) + { + child->fixed_size.v[axis] -= fixup; + } } } } - } - - //- rjf: fixup children sizes (in the direction of the layout axis) - if(axis == root->child_layout_axis && !(root->flags & (UI_BoxFlag_AllowOverflowX << axis))) - { - // rjf: figure out total allowed size & total size - F32 total_allowed_size = root->fixed_size.v[axis]; - F32 total_size = 0; - F32 total_weighted_size = 0; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + //- rjf: fixup children sizes (in the direction of the layout axis) + if(axis == box->child_layout_axis && !(box->flags & (UI_BoxFlag_AllowOverflowX << axis))) { - if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis]; + F32 total_size = 0; + F32 total_weighted_size = 0; + for(UI_Box *child = box->first; !ui_box_is_nil(child); child = child->next) { - total_size += child->fixed_size.v[axis]; - total_weighted_size += child->fixed_size.v[axis] * (1-child->pref_size[axis].strictness); - } - } - - // rjf: if we have a violation, we need to subtract some amount from all children - F32 violation = total_size - total_allowed_size; - if(violation > 0) - { - // rjf: figure out how much we can take in totality - F32 child_fixup_sum = 0; - F32 *child_fixups = push_array(scratch.arena, F32, root->child_count); - { - U64 child_idx = 0; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next, child_idx += 1) + if(!(child->flags & (UI_BoxFlag_FloatingX<flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] * (1-child->pref_size[axis].strictness); - fixup_size_this_child = ClampBot(0, fixup_size_this_child); - child_fixups[child_idx] = fixup_size_this_child; - child_fixup_sum += fixup_size_this_child; - } + total_size += child->fixed_size.v[axis]; + total_weighted_size += child->fixed_size.v[axis] * (1-child->pref_size[axis].strictness); } } - // rjf: fixup child sizes + // rjf: if we have a violation, we need to subtract some amount from all children + F32 violation = total_size - total_allowed_size; + if(violation > 0 && total_weighted_size > 0) { - U64 child_idx = 0; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next, child_idx += 1) + Temp temp = temp_begin(scratch.arena); + + // rjf: figure out how much we can take in totality + F32 child_fixup_sum = 0; + F32 *child_fixups = push_array(temp.arena, F32, box->child_count); { - if(!(child->flags & (UI_BoxFlag_FloatingX<first; !ui_box_is_nil(child); child = child->next, child_idx += 1) { - F32 fixup_pct = (violation / total_weighted_size); - fixup_pct = Clamp(0, fixup_pct, 1); - child->fixed_size.v[axis] -= child_fixups[child_idx] * fixup_pct; + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] * (1-child->pref_size[axis].strictness); + fixup_size_this_child = ClampBot(0, fixup_size_this_child); + child_fixups[child_idx] = fixup_size_this_child; + child_fixup_sum += fixup_size_this_child; + } } } + + // rjf: fixup child sizes + { + U64 child_idx = 0; + for(UI_Box *child = box->first; !ui_box_is_nil(child); child = child->next, child_idx += 1) + { + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis] -= child_fixups[child_idx] * fixup_pct; + } + } + } + + temp_end(temp); + } + } + + //- rjf: fixup upwards-relative sizes + if(box->flags & (UI_BoxFlag_AllowOverflowX << axis)) + { + for(UI_Box *child = box->first; !ui_box_is_nil(child); child = child->next) + { + if(child->pref_size[axis].kind == UI_SizeKind_ParentPct) + { + child->fixed_size.v[axis] = box->fixed_size.v[axis] * child->pref_size[axis].value; + } } } - } - - //- rjf: fixup upwards-relative sizes - if(root->flags & (UI_BoxFlag_AllowOverflowX << axis)) - { - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + + //- rjf: enforce clamps + for(UI_Box *child = box->first; !ui_box_is_nil(child); child = child->next) { - if(child->pref_size[axis].kind == UI_SizeKind_ParentPct) - { - child->fixed_size.v[axis] = root->fixed_size.v[axis] * child->pref_size[axis].value; - } + child->fixed_size.v[axis] = Max(child->fixed_size.v[axis], child->min_size.v[axis]); } } - - //- rjf: recurse - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - ui_layout_enforce_constraints__in_place_rec(child, axis); - } - scratch_end(scratch); ProfEnd(); } internal void -ui_layout_position__in_place_rec(UI_Box *root, Axis2 axis) +ui_layout_position__in_place(UI_Box *root, Axis2 axis) { ProfBeginFunction(); - F32 layout_position = 0; - - //- rjf: lay out children - F32 bounds = 0; - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) + for(UI_Box *box = root; !ui_box_is_nil(box); box = ui_box_rec_df_pre(box, root).next) { - // rjf: grab original position - F32 original_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); + F32 layout_position = 0; - // rjf: calculate fixed position & size - if(!(child->flags & (UI_BoxFlag_FloatingX<first; !ui_box_is_nil(child); child = child->next) { - child->fixed_position.v[axis] = layout_position; - if(root->child_layout_axis == axis) + // rjf: grab original position + F32 original_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); + + // rjf: calculate fixed position & size + if(!(child->flags & (UI_BoxFlag_FloatingX<fixed_size.v[axis]; - bounds += child->fixed_size.v[axis]; + child->fixed_position.v[axis] = layout_position; + if(box->child_layout_axis == axis) + { + layout_position += child->fixed_size.v[axis]; + bounds += child->fixed_size.v[axis]; + } + else + { + bounds = Max(bounds, child->fixed_size.v[axis]); + } + } + + // rjf: determine final rect for child, given fixed_position & size + if(child->flags & (UI_BoxFlag_AnimatePosX<first_touched_build_index == child->last_touched_build_index) + { + child->fixed_position_animated = child->fixed_position; + } + child->rect.p0.v[axis] = box->rect.p0.v[axis] + child->fixed_position_animated.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]); } else { - bounds = Max(bounds, child->fixed_size.v[axis]); + child->rect.p0.v[axis] = box->rect.p0.v[axis] + child->fixed_position.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]); } + child->rect.p1.v[axis] = child->rect.p0.v[axis] + child->fixed_size.v[axis]; + child->rect.p0.x = floor_f32(child->rect.p0.x); + child->rect.p0.y = floor_f32(child->rect.p0.y); + child->rect.p1.x = floor_f32(child->rect.p1.x); + child->rect.p1.y = floor_f32(child->rect.p1.y); + + // rjf: grab new position + F32 new_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); + + // rjf: store position delta + child->position_delta.v[axis] = new_position - original_position; } - // rjf: determine final rect for child, given fixed_position & size - if(child->flags & (UI_BoxFlag_AnimatePosX<first_touched_build_index == child->last_touched_build_index) - { - child->fixed_position_animated = child->fixed_position; - } - child->rect.p0.v[axis] = root->rect.p0.v[axis] + child->fixed_position_animated.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]); + box->view_bounds.v[axis] = bounds; } - else - { - child->rect.p0.v[axis] = root->rect.p0.v[axis] + child->fixed_position.v[axis] - !(child->flags&(UI_BoxFlag_SkipViewOffX<view_off.v[axis]); - } - child->rect.p1.v[axis] = child->rect.p0.v[axis] + child->fixed_size.v[axis]; - child->rect.p0.x = floor_f32(child->rect.p0.x); - child->rect.p0.y = floor_f32(child->rect.p0.y); - child->rect.p1.x = floor_f32(child->rect.p1.x); - child->rect.p1.y = floor_f32(child->rect.p1.y); - - // rjf: grab new position - F32 new_position = Min(child->rect.p0.v[axis], child->rect.p1.v[axis]); - - // rjf: store position delta - child->position_delta.v[axis] = new_position - original_position; } - - //- rjf: store view bounds - { - root->view_bounds.v[axis] = bounds; - } - - //- rjf: recurse - for(UI_Box *child = root->first; !ui_box_is_nil(child); child = child->next) - { - ui_layout_position__in_place_rec(child, axis); - } - ProfEnd(); } @@ -1878,11 +1965,11 @@ internal void ui_layout_root(UI_Box *root, Axis2 axis) { ProfBegin("ui layout pass (%s)", axis == Axis2_X ? "x" : "y"); - ui_calc_sizes_standalone__in_place_rec(root, axis); - ui_calc_sizes_upwards_dependent__in_place_rec(root, axis); - ui_calc_sizes_downwards_dependent__in_place_rec(root, axis); - ui_layout_enforce_constraints__in_place_rec(root, axis); - ui_layout_position__in_place_rec(root, axis); + ui_calc_sizes_standalone__in_place(root, axis); + ui_calc_sizes_upwards_dependent__in_place(root, axis); + ui_calc_sizes_downwards_dependent__in_place(root, axis); + ui_layout_enforce_constraints__in_place(root, axis); + ui_layout_position__in_place(root, axis); ProfEnd(); } @@ -1911,13 +1998,17 @@ ui_tooltip_begin_base(void) ui_push_parent(ui_state->tooltip_root); ui_push_flags(0); ui_push_text_raster_flags(ui_bottom_text_raster_flags()); - ui_push_palette(ui_bottom_palette()); + ui_push_font_size(ui_bottom_font_size()); + ui_push_tag(str8_lit(".")); + ui_push_tag(str8_lit("floating")); } internal void ui_tooltip_end_base(void) { - ui_pop_palette(); + ui_pop_tag(); + ui_pop_tag(); + ui_pop_font_size(); ui_pop_text_raster_flags(); ui_pop_flags(); ui_pop_parent(); @@ -1928,10 +2019,9 @@ internal void ui_tooltip_begin(void) { ui_tooltip_begin_base(); - ui_push_palette(ui_state->widget_palette_info.tooltip_palette); - ui_set_next_squish(0.25f-ui_state->tooltip_open_t*0.25f); + ui_set_next_squish(0.1f-ui_state->tooltip_open_t*0.1f); ui_set_next_transparency(1-ui_state->tooltip_open_t); - UI_Flags(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow) + UI_Flags(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBackgroundBlur|UI_BoxFlag_DrawDropShadow|UI_BoxFlag_SquishAnchored) UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_children_sum(1)) UI_CornerRadius(ui_top_font_size()*0.25f) @@ -1960,7 +2050,6 @@ ui_tooltip_end(void) ui_row_end(); UI_PrefWidth(ui_px(0, 1)) ui_spacer(ui_em(1.f, 1.f)); ui_column_end(); - ui_pop_palette(); ui_tooltip_end_base(); } @@ -1998,9 +2087,9 @@ ui_begin_ctx_menu(UI_Key key) ui_push_pref_height(ui_bottom_pref_height()); ui_push_focus_hot(UI_FocusKind_Root); ui_push_focus_active(UI_FocusKind_Root); - ui_push_palette(ui_state->widget_palette_info.ctx_menu_palette); + ui_push_tag(str8_lit(".")); B32 is_open = ui_key_match(key, ui_state->ctx_menu_key) && ui_state->ctx_menu_open; - if(is_open != 0) + if(is_open != 0) UI_TagF("floating") { ui_state->ctx_menu_touched_this_frame = 1; ui_state->ctx_menu_root->flags |= UI_BoxFlag_RoundChildrenByParent; @@ -2011,8 +2100,10 @@ ui_begin_ctx_menu(UI_Key key) ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clip; ui_state->ctx_menu_root->flags |= UI_BoxFlag_Clickable; ui_state->ctx_menu_root->corner_radii[Corner_00] = ui_state->ctx_menu_root->corner_radii[Corner_01] = ui_state->ctx_menu_root->corner_radii[Corner_10] = ui_state->ctx_menu_root->corner_radii[Corner_11] = ui_top_font_size()*0.25f; - ui_state->ctx_menu_root->palette = ui_top_palette(); + ui_state->ctx_menu_root->tags_key = ui_top_tags_key(); ui_state->ctx_menu_root->blur_size = ui_top_blur_size(); + ui_state->ctx_menu_root->text_color = ui_color_from_name(str8_lit("text")); + ui_state->ctx_menu_root->background_color = ui_color_from_name(str8_lit("background")); ui_spacer(ui_em(1.f, 1.f)); } ui_state->is_in_open_ctx_menu = is_open; @@ -2027,7 +2118,7 @@ ui_end_ctx_menu(void) ui_state->is_in_open_ctx_menu = 0; ui_spacer(ui_em(1.f, 1.f)); } - ui_pop_palette(); + ui_pop_tag(); ui_pop_focus_active(); ui_pop_focus_hot(); ui_pop_pref_width(); @@ -2161,27 +2252,170 @@ ui_set_auto_focus_hot_key(UI_Key key) } } -//- rjf: palette forming +//- rjf: current style tags key -internal UI_Palette * -ui_build_palette_(UI_Palette *base, UI_Palette *overrides) +internal UI_Key +ui_top_tags_key(void) { - UI_Palette *palette = push_array(ui_build_arena(), UI_Palette, 1); - if(base != 0) + UI_Key key = ui_key_zero(); + if(ui_state->tags_key_stack_top != 0) { - MemoryCopyStruct(palette, base); + key = ui_state->tags_key_stack_top->key; } - for EachEnumVal(UI_ColorCode, code) + return key; +} + +//- rjf: theme color lookups + +internal Vec4F32 +ui_color_from_name(String8 name) +{ + Vec4F32 result = ui_color_from_tags_key_name(ui_top_tags_key(), name); + return result; +} + +internal Vec4F32 +ui_color_from_tags_key_extras(UI_Key key, String8Array extras) +{ + Vec4F32 result = {0}; + if(ui_state->theme_pattern_cache_slots_count && extras.count > 0) { - if(overrides->colors[code].x != 0 || - overrides->colors[code].y != 0 || - overrides->colors[code].z != 0 || - overrides->colors[code].w != 0) + //- rjf: compute final key, mixing (tags_key, extras) + UI_Key final_key = key; + for EachIndex(idx, extras.count) { - palette->colors[code] = overrides->colors[code]; + final_key = ui_key_from_string(final_key, extras.v[idx]); + } + + //- rjf: map to existing node + U64 slot_idx = final_key.u64[0]%ui_state->theme_pattern_cache_slots_count; + UI_ThemePatternCacheSlot *slot = &ui_state->theme_pattern_cache_slots[slot_idx]; + UI_ThemePatternCacheNode *node = 0; + for(UI_ThemePatternCacheNode *n = slot->first; + n != 0; + n = n->slot_next) + { + if(ui_key_match(n->key, final_key)) + { + node = n; + } + } + + //- rjf: no node, or this node is stale? create and/or update + if(node == 0 || node->last_build_index_accessed < ui_state->build_index) + { + // rjf: map tags_key (without name) -> full list of tags + String8Array tags = {0}; + { + U64 tags_cache_slot_idx = key.u64[0]%ui_state->tags_cache_slots_count; + UI_TagsCacheSlot *tags_cache_slot = &ui_state->tags_cache_slots[tags_cache_slot_idx]; + for(UI_TagsCacheNode *n = tags_cache_slot->first; n != 0; n = n->next) + { + if(ui_key_match(n->key, key)) + { + tags = n->tags; + break; + } + } + } + + // rjf: map tags to theme pattern + UI_Theme *theme = ui_state->theme; + UI_ThemePattern *pattern = 0; + U64 best_match_count = 0; + for(U64 idx = 0; idx < theme->patterns_count; idx += 1) + { + UI_ThemePattern *p = &theme->patterns[idx]; + U64 match_count = 0; + B32 name_matches = 0; + B32 all_p_tags_in_key = 1; + for EachIndex(p_tags_idx, p->tags.count) + { + B32 p_tag_in_key = 0; + for EachIndex(key_tags_idx, tags.count + extras.count) + { + String8 key_string = key_tags_idx < tags.count ? tags.v[key_tags_idx] : extras.v[key_tags_idx - tags.count]; + if(str8_match(p->tags.v[p_tags_idx], key_string, 0)) + { + if(key_tags_idx == tags.count + extras.count - 1) + { + name_matches = 1; + } + p_tag_in_key = 1; + match_count += 1; + break; + } + } + if(!p_tag_in_key) + { + all_p_tags_in_key = 0; + break; + } + } + if(name_matches && all_p_tags_in_key && match_count > best_match_count) + { + pattern = p; + best_match_count = match_count; + } + if(match_count == tags.count + extras.count) + { + break; + } + } + + // rjf: store in (key, name) -> (pattern) cache + B32 node_is_new = 0; + if(node == 0) + { + node_is_new = 1; + node = ui_state->theme_pattern_cache_node_free; + if(node != 0) + { + SLLStackPop_N(ui_state->theme_pattern_cache_node_free, slot_next); + } + else + { + node = push_array(ui_state->arena, UI_ThemePatternCacheNode, 1); + } + DLLPushBack_NP(slot->first, slot->last, node, slot_next, slot_prev); + DLLPushBack_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); + node->key = final_key; + } + + // rjf: update node's target color + if(pattern != 0) + { + node->target_rgba = pattern->linear; + if(node_is_new) + { + node->current_rgba = node->target_rgba; + } + } + } + + //- rjf: mark this node as most-recently-used + if(node != 0 && node->last_build_index_accessed < ui_state->build_index) + { + node->last_build_index_accessed = ui_state->build_index; + DLLRemove_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); + DLLPushBack_NP(ui_state->lru_theme_pattern_cache_node, ui_state->mru_theme_pattern_cache_node, node, lru_next, lru_prev); + } + + //- rjf: grab resultant color + if(node != 0) + { + result = node->current_rgba; } } - return palette; + return result; +} + +internal Vec4F32 +ui_color_from_tags_key_name(UI_Key key, String8 name) +{ + String8Array extras = {&name, 1}; + Vec4F32 result = ui_color_from_tags_key_extras(key, extras); + return result; } //- rjf: box node construction @@ -2256,7 +2490,7 @@ ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) //- rjf: fill box { box->key = key; - box->flags = flags|ui_state->flags_stack.top->v; + box->flags = (flags | ui_state->flags_stack.top->v) & ~ui_state->omit_flags_stack.top->v; box->fastpath_codepoint = ui_state->fastpath_codepoint_stack.top->v; box->group_key = ui_state->group_key_stack.top->v; @@ -2305,6 +2539,8 @@ ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) { box->pref_size[Axis2_Y] = ui_state->pref_height_stack.top->v; } + box->min_size.v[Axis2_X] = ui_state->min_width_stack.top->v; + box->min_size.v[Axis2_Y] = ui_state->min_height_stack.top->v; B32 is_auto_focus_active = ui_is_key_auto_focus_active(key); B32 is_auto_focus_hot = ui_is_key_auto_focus_hot(key); @@ -2329,7 +2565,6 @@ ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) box->text_align = ui_state->text_alignment_stack.top->v; box->child_layout_axis = ui_state->child_layout_axis_stack.top->v; - box->palette = ui_state->palette_stack.top->v; box->font = ui_state->font_stack.top->v; box->font_size = ui_state->font_size_stack.top->v; box->tab_size = ui_state->tab_size_stack.top->v; @@ -2344,6 +2579,33 @@ ui_build_box_from_key(UI_BoxFlags flags, UI_Key key) box->text_padding = ui_state->text_padding_stack.top->v; box->hover_cursor = ui_state->hover_cursor_stack.top->v; box->custom_draw = 0; + box->tags_key = ui_key_zero(); + if(ui_state->tags_key_stack_top != 0) + { + box->tags_key = ui_state->tags_key_stack_top->key; + } + if(box->flags & UI_BoxFlag_DrawBackground) + { + if(ui_state->background_color_stack.top != &ui_state->background_color_nil_stack_top) + { + box->background_color = ui_state->background_color_stack.top->v; + } + else + { + box->background_color = ui_color_from_name(str8_lit("background")); + } + } + if(box->flags & UI_BoxFlag_DrawText) + { + if(ui_state->text_color_stack.top != &ui_state->text_color_nil_stack_top) + { + box->text_color = ui_state->text_color_stack.top->v; + } + else + { + box->text_color = ui_color_from_name(str8_lit("text")); + } + } } //- rjf: auto-pop all stacks @@ -2417,13 +2679,14 @@ ui_box_equip_display_string(UI_Box *box, String8 string) ProfBeginFunction(); box->string = push_str8_copy(ui_build_arena(), string); box->flags |= UI_BoxFlag_HasDisplayString; - UI_ColorCode text_color_code = (box->flags & UI_BoxFlag_DrawTextWeak ? UI_ColorCode_TextWeak : UI_ColorCode_Text); + Vec4F32 text_color = box->text_color; if(box->flags & UI_BoxFlag_DrawText && (box->fastpath_codepoint == 0 || !(box->flags & UI_BoxFlag_DrawTextFastpathCodepoint))) { String8 display_string = ui_box_display_string(box); - DR_FancyStringNode fancy_string_n = {0, {box->font, display_string, box->palette->colors[text_color_code], box->font_size, 0, 0}}; - DR_FancyStringList fancy_strings = {&fancy_string_n, &fancy_string_n, 1}; - box->display_string_runs = dr_fancy_run_list_from_fancy_string_list(ui_build_arena(), box->tab_size, box->text_raster_flags, &fancy_strings); + DR_FStrNode fstr_n = {0, {display_string, {box->font, box->text_raster_flags, text_color, box->font_size, 0, 0}}}; + DR_FStrList fstrs = {&fstr_n, &fstr_n, 1}; + box->display_fstrs = dr_fstrs_copy(ui_build_arena(), &fstrs); + box->display_fruns = dr_fruns_from_fstrs(ui_build_arena(), box->tab_size, &box->display_fstrs); } else if(box->flags & UI_BoxFlag_DrawText && box->flags & UI_BoxFlag_DrawTextFastpathCodepoint && box->fastpath_codepoint != 0) { @@ -2434,17 +2697,19 @@ ui_box_equip_display_string(UI_Box *box, String8 string) U64 fpcp_pos = str8_find_needle(display_string, 0, fpcp, StringMatchFlag_CaseInsensitive); if(fpcp_pos < display_string.size) { - DR_FancyStringNode pst_fancy_string_n = {0, {box->font, str8_skip(display_string, fpcp_pos+fpcp.size), box->palette->colors[text_color_code], box->font_size, 0, 0}}; - DR_FancyStringNode cdp_fancy_string_n = {&pst_fancy_string_n, {box->font, str8_substr(display_string, r1u64(fpcp_pos, fpcp_pos+fpcp.size)), box->palette->colors[text_color_code], box->font_size, 3.f, 0}}; - DR_FancyStringNode pre_fancy_string_n = {&cdp_fancy_string_n, {box->font, str8_prefix(display_string, fpcp_pos), box->palette->colors[text_color_code], box->font_size, 0, 0}}; - DR_FancyStringList fancy_strings = {&pre_fancy_string_n, &pst_fancy_string_n, 3}; - box->display_string_runs = dr_fancy_run_list_from_fancy_string_list(ui_build_arena(), box->tab_size, box->text_raster_flags, &fancy_strings); + DR_FStrNode pst_fstr_n = {0, {str8_skip(display_string, fpcp_pos+fpcp.size), {box->font, box->text_raster_flags, text_color, box->font_size, 0, 0}}}; + DR_FStrNode cdp_fstr_n = {&pst_fstr_n, {str8_substr(display_string, r1u64(fpcp_pos, fpcp_pos+fpcp.size)), {box->font, box->text_raster_flags, text_color, box->font_size, 3.f, 0}}}; + DR_FStrNode pre_fstr_n = {&cdp_fstr_n, {str8_prefix(display_string, fpcp_pos), {box->font, box->text_raster_flags, text_color, box->font_size, 0, 0}}}; + DR_FStrList fstrs = {&pre_fstr_n, &pst_fstr_n, 3}; + box->display_fstrs = dr_fstrs_copy(ui_build_arena(), &fstrs); + box->display_fruns = dr_fruns_from_fstrs(ui_build_arena(), box->tab_size, &box->display_fstrs); } else { - DR_FancyStringNode fancy_string_n = {0, {box->font, display_string, box->palette->colors[UI_ColorCode_Text], box->font_size, 0, 0}}; - DR_FancyStringList fancy_strings = {&fancy_string_n, &fancy_string_n, 1}; - box->display_string_runs = dr_fancy_run_list_from_fancy_string_list(ui_build_arena(), box->tab_size, box->text_raster_flags, &fancy_strings); + DR_FStrNode fstr_n = {0, {display_string, {box->font, box->text_raster_flags, text_color, box->font_size, 0, 0}}}; + DR_FStrList fstrs = {&fstr_n, &fstr_n, 1}; + box->display_fstrs = dr_fstrs_copy(ui_build_arena(), &fstrs); + box->display_fruns = dr_fruns_from_fstrs(ui_build_arena(), box->tab_size, &box->display_fstrs); } scratch_end(scratch); } @@ -2452,19 +2717,12 @@ ui_box_equip_display_string(UI_Box *box, String8 string) } internal void -ui_box_equip_display_fancy_strings(UI_Box *box, DR_FancyStringList *strings) +ui_box_equip_display_fstrs(UI_Box *box, DR_FStrList *strings) { box->flags |= UI_BoxFlag_HasDisplayString; - box->string = dr_string_from_fancy_string_list(ui_build_arena(), strings); - box->display_string_runs = dr_fancy_run_list_from_fancy_string_list(ui_build_arena(), box->tab_size, box->text_raster_flags, strings); -} - -internal inline void -ui_box_equip_display_string_fancy_runs(UI_Box *box, String8 string, DR_FancyRunList *runs) -{ - box->flags |= UI_BoxFlag_HasDisplayString; - box->string = push_str8_copy(ui_build_arena(), string); - box->display_string_runs = dr_fancy_run_list_copy(ui_build_arena(), runs); + box->string = dr_string_from_fstrs(ui_build_arena(), strings); + box->display_fstrs = dr_fstrs_copy(ui_build_arena(), strings); + box->display_fruns = dr_fruns_from_fstrs(ui_build_arena(), box->tab_size, &box->display_fstrs); } internal inline void @@ -2515,7 +2773,7 @@ ui_box_text_position(UI_Box *box) FNT_Tag font = box->font; F32 font_size = box->font_size; FNT_Metrics font_metrics = fnt_metrics_from_tag_size(font, font_size); - result.y = floor_f32((box->rect.p0.y + box->rect.p1.y)/2.f) + font_metrics.capital_height/2.f - 1.f; + result.y = floor_f32((box->rect.p0.y + box->rect.p1.y)/2.f) + font_metrics.ascent/2.f - 2.f; if(!fnt_tag_match(font, ui_icon_font())) { result.y += font_metrics.descent/2; @@ -2529,13 +2787,13 @@ ui_box_text_position(UI_Box *box) }break; case UI_TextAlign_Center: { - Vec2F32 text_dim = box->display_string_runs.dim; + Vec2F32 text_dim = box->display_fruns.dim; result.x = round_f32((box->rect.p0.x + box->rect.p1.x)/2 - text_dim.x/2); result.x = ClampBot(result.x, box->rect.x0); }break; case UI_TextAlign_Right: { - Vec2F32 text_dim = box->display_string_runs.dim; + Vec2F32 text_dim = box->display_fruns.dim; result.x = round_f32((box->rect.p1.x) - text_dim.x - box->text_padding); result.x = ClampBot(result.x, box->rect.x0); }break; @@ -2695,6 +2953,7 @@ ui_signal_from_box(UI_Box *box) //- rjf: focus is hot & copy event -> remember to copy this box tree's text content if(is_focus_hot && evt->flags & UI_EventFlag_Copy && + !(evt->flags & UI_EventFlag_Delete) && !ui_key_match(ui_key_zero(), box->key)) { ui_state->clipboard_copy_key = box->key; @@ -2734,7 +2993,7 @@ ui_signal_from_box(UI_Box *box) //- rjf: scrolling if(box->flags & UI_BoxFlag_Scroll && evt->kind == UI_EventKind_Scroll && - evt->modifiers != OS_Modifier_Ctrl && + (evt->modifiers == 0 || evt->modifiers == OS_Modifier_Shift) && evt_mouse_in_bounds) { Vec2F32 delta = evt->delta_2f32; @@ -2755,7 +3014,7 @@ ui_signal_from_box(UI_Box *box) //- rjf: view scrolling if(box->flags & UI_BoxFlag_ViewScroll && box->first_touched_build_index != box->last_touched_build_index && evt->kind == UI_EventKind_Scroll && - evt->modifiers != OS_Modifier_Ctrl && + (evt->modifiers == 0 || evt->modifiers == OS_Modifier_Shift) && evt_mouse_in_bounds) { Vec2F32 delta = evt->delta_2f32; @@ -2979,6 +3238,7 @@ ui_anim_(UI_Key key, UI_AnimParams *params) { // rjf: get animation cache node UI_AnimNode *node = &ui_nil_anim_node; + if(ui_state != 0) { U64 slot_idx = key.u64[0]%ui_state->anim_slots_count; UI_AnimSlot *slot = &ui_state->anim_slots[slot_idx]; @@ -3014,16 +3274,23 @@ ui_anim_(UI_Key key, UI_AnimParams *params) } // rjf: touch node & update parameters - grab current - node->last_touched_build_index = ui_state->build_index; - DLLPushBack_NPZ(&ui_nil_anim_node, ui_state->lru_anim_node, ui_state->mru_anim_node, node, lru_next, lru_prev); - MemoryCopyStruct(&node->params, params); - if(node->params.epsilon == 0) + if(node != &ui_nil_anim_node) { - node->params.epsilon = 0.01f; - } - if(node->params.rate == 1) - { - node->current = node->params.target; + node->last_touched_build_index = ui_state->build_index; + DLLPushBack_NPZ(&ui_nil_anim_node, ui_state->lru_anim_node, ui_state->mru_anim_node, node, lru_next, lru_prev); + if(params->reset) + { + node->current = params->initial; + } + MemoryCopyStruct(&node->params, params); + if(node->params.epsilon == 0) + { + node->params.epsilon = 0.005f; + } + if(node->params.rate == 1 || abs_f32(node->current - node->params.target) < abs_f32(node->params.epsilon)) + { + node->current = node->params.target; + } } return node->current; } @@ -3031,6 +3298,170 @@ ui_anim_(UI_Key key, UI_AnimParams *params) //////////////////////////////// //~ rjf: Stacks +#define UI_StackTopImpl(state, name_upper, name_lower) \ +return state->name_lower##_stack.top->v; + +#define UI_StackBottomImpl(state, name_upper, name_lower) \ +return state->name_lower##_stack.bottom_val; + +#define UI_StackPushImpl(state, name_upper, name_lower, type, new_value) \ +UI_##name_upper##Node *node = state->name_lower##_stack.free;\ +if(node != 0) {SLLStackPop(state->name_lower##_stack.free);}\ +else {node = push_array(ui_build_arena(), UI_##name_upper##Node, 1);}\ +type old_value = state->name_lower##_stack.top->v;\ +node->v = new_value;\ +SLLStackPush(state->name_lower##_stack.top, node);\ +if(node->next == &state->name_lower##_nil_stack_top)\ +{\ +state->name_lower##_stack.bottom_val = (node->v);\ +}\ +state->name_lower##_stack.auto_pop = 0;\ +state->name_lower##_stack.gen += 1;\ +return old_value; + +#define UI_StackPopImpl(state, name_upper, name_lower) \ +UI_##name_upper##Node *popped = state->name_lower##_stack.top;\ +if(popped != &state->name_lower##_nil_stack_top)\ +{\ +SLLStackPop(state->name_lower##_stack.top);\ +SLLStackPush(state->name_lower##_stack.free, popped);\ +state->name_lower##_stack.auto_pop = 0;\ +state->name_lower##_stack.gen += 1;\ +}\ +return popped->v;\ + +#define UI_StackSetNextImpl(state, name_upper, name_lower, type, new_value) \ +UI_##name_upper##Node *node = state->name_lower##_stack.free;\ +if(node != 0) {SLLStackPop(state->name_lower##_stack.free);}\ +else {node = push_array(ui_build_arena(), UI_##name_upper##Node, 1);}\ +type old_value = state->name_lower##_stack.top->v;\ +node->v = new_value;\ +SLLStackPush(state->name_lower##_stack.top, node);\ +state->name_lower##_stack.auto_pop = 1;\ +state->name_lower##_stack.gen += 1;\ +return old_value; + +internal void +ui__push_tags_key_from_appended_string(String8 string) +{ + B32 is_new_root = str8_match(str8_lit("."), string, 0); + + // rjf: generate new key, by combining hash of this new string with the top + // of the tags key stack + UI_Key seed_key = {0}; + if(!is_new_root && ui_state->tags_key_stack_top != 0) + { + seed_key = ui_state->tags_key_stack_top->key; + } + UI_Key key = seed_key; + if(!is_new_root && string.size > 0) + { + key = ui_key_from_string(seed_key, string); + } + + // rjf: push this new key onto the stack + { + UI_TagsKeyStackNode *node = ui_state->tags_key_stack_free; + if(node != 0) + { + SLLStackPop(ui_state->tags_key_stack_free); + } + else + { + node = push_array(ui_build_arena(), UI_TagsKeyStackNode, 1); + } + SLLStackPush(ui_state->tags_key_stack_top, node); + node->key = key; + } + + // rjf: store in tags cache + if(!is_new_root) + { + U64 slot_idx = key.u64[0] % ui_state->tags_cache_slots_count; + UI_TagsCacheSlot *slot = &ui_state->tags_cache_slots[slot_idx]; + UI_TagsCacheNode *node = 0; + for(UI_TagsCacheNode *n = slot->first; n != 0; n = n->next) + { + if(ui_key_match(n->key, key)) + { + node = n; + break; + } + } + if(node == 0) + { + Temp scratch = scratch_begin(0, 0); + String8List tags = {0}; + if(string.size != 0) + { + str8_list_push(scratch.arena, &tags, push_str8_copy(ui_build_arena(), string)); + } + for(UI_TagNode *n = ui_state->tag_stack.top; n != 0; n = n->next) + { + if(n->v.size == 1 && n->v.str[0] == '.') + { + break; + } + if(n->v.size != 0) + { + str8_list_push(scratch.arena, &tags, push_str8_copy(ui_build_arena(), n->v)); + } + } + node = push_array(ui_build_arena(), UI_TagsCacheNode, 1); + SLLQueuePush(slot->first, slot->last, node); + node->key = key; + node->tags = str8_array_from_list(ui_build_arena(), &tags); + scratch_end(scratch); + } + } +} + +internal void +ui__pop_tags_key(void) +{ + if(ui_state->tags_key_stack_top != 0) + { + UI_TagsKeyStackNode *popped = ui_state->tags_key_stack_top; + SLLStackPop(ui_state->tags_key_stack_top); + SLLStackPush(ui_state->tags_key_stack_free, popped); + } +} + +//- rjf: manual implementations + +internal String8 +ui_top_tag(void) +{ + UI_StackTopImpl(ui_state, Tag, tag) +} + +internal String8 +ui_bottom_tag(void) +{ + UI_StackBottomImpl(ui_state, Tag, tag) +} + +internal String8 +ui_push_tag(String8 v) +{ + ui__push_tags_key_from_appended_string(v); + UI_StackPushImpl(ui_state, Tag, tag, String8, push_str8_copy(ui_build_arena(), v)) +} + +internal String8 +ui_pop_tag(void) +{ + ui__pop_tags_key(); + UI_StackPopImpl(ui_state, Tag, tag) +} + +internal String8 +ui_set_next_tag(String8 v) +{ + ui__push_tags_key_from_appended_string(v); + UI_StackSetNextImpl(ui_state, Tag, tag, String8, push_str8_copy(ui_build_arena(), v)) +} + //- rjf: helpers internal Rng2F32 @@ -3116,47 +3547,34 @@ ui_pop_corner_radius(void) ui_pop_corner_radius_11(); } +internal void +ui_push_tagf(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + ui_push_tag(string); + va_end(args); + scratch_end(scratch); +} + +internal F32 +ui_top_px_height(void) +{ + F32 result = ui_top_font_size(); + for(UI_PrefHeightNode *n = ui_state->pref_height_stack.top; n != 0; n = n->next) + { + if(n->v.kind == UI_SizeKind_Pixels) + { + result = n->v.value; + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Generated Code -#define UI_StackTopImpl(state, name_upper, name_lower) \ -return state->name_lower##_stack.top->v; - -#define UI_StackBottomImpl(state, name_upper, name_lower) \ -return state->name_lower##_stack.bottom_val; - -#define UI_StackPushImpl(state, name_upper, name_lower, type, new_value) \ -UI_##name_upper##Node *node = state->name_lower##_stack.free;\ -if(node != 0) {SLLStackPop(state->name_lower##_stack.free);}\ -else {node = push_array(ui_build_arena(), UI_##name_upper##Node, 1);}\ -type old_value = state->name_lower##_stack.top->v;\ -node->v = new_value;\ -SLLStackPush(state->name_lower##_stack.top, node);\ -if(node->next == &state->name_lower##_nil_stack_top)\ -{\ -state->name_lower##_stack.bottom_val = (new_value);\ -}\ -state->name_lower##_stack.auto_pop = 0;\ -return old_value; - -#define UI_StackPopImpl(state, name_upper, name_lower) \ -UI_##name_upper##Node *popped = state->name_lower##_stack.top;\ -if(popped != &state->name_lower##_nil_stack_top)\ -{\ -SLLStackPop(state->name_lower##_stack.top);\ -SLLStackPush(state->name_lower##_stack.free, popped);\ -state->name_lower##_stack.auto_pop = 0;\ -}\ -return popped->v;\ - -#define UI_StackSetNextImpl(state, name_upper, name_lower, type, new_value) \ -UI_##name_upper##Node *node = state->name_lower##_stack.free;\ -if(node != 0) {SLLStackPop(state->name_lower##_stack.free);}\ -else {node = push_array(ui_build_arena(), UI_##name_upper##Node, 1);}\ -type old_value = state->name_lower##_stack.top->v;\ -node->v = new_value;\ -SLLStackPush(state->name_lower##_stack.top, node);\ -state->name_lower##_stack.auto_pop = 1;\ -return old_value; - #include "generated/ui.meta.c" diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 45c9c8b2..1c915ee5 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -49,15 +49,17 @@ UI_MouseButtonKind; typedef U32 UI_PermissionFlags; enum { - UI_PermissionFlag_ClicksLeft = (1<<0), - UI_PermissionFlag_ClicksMiddle = (1<<1), - UI_PermissionFlag_ClicksRight = (1<<2), - UI_PermissionFlag_ScrollX = (1<<3), - UI_PermissionFlag_ScrollY = (1<<4), - UI_PermissionFlag_Keyboard = (1<<5), - UI_PermissionFlag_Text = (1<<6), + UI_PermissionFlag_ClicksLeft = (1<<0), + UI_PermissionFlag_ClicksMiddle = (1<<1), + UI_PermissionFlag_ClicksRight = (1<<2), + UI_PermissionFlag_ScrollX = (1<<3), + UI_PermissionFlag_ScrollY = (1<<4), + UI_PermissionFlag_KeyboardPrimary = (1<<5), + UI_PermissionFlag_KeyboardSecondary = (1<<6), + UI_PermissionFlag_Text = (1<<7), //- rjf bundles + UI_PermissionFlag_Keyboard = (UI_PermissionFlag_KeyboardPrimary|UI_PermissionFlag_KeyboardSecondary), UI_PermissionFlag_Clicks = (UI_PermissionFlag_ClicksLeft|UI_PermissionFlag_ClicksMiddle|UI_PermissionFlag_ClicksRight), UI_PermissionFlag_All = 0xffffffff, }; @@ -90,7 +92,6 @@ typedef enum UI_EventKind UI_EventKind_Edit, UI_EventKind_MouseMove, UI_EventKind_Scroll, - UI_EventKind_AutocompleteHint, UI_EventKind_FileDrop, UI_EventKind_COUNT } @@ -118,6 +119,7 @@ enum UI_EventFlag_CapAtLine = (1<<6), UI_EventFlag_ExplicitDirectional = (1<<7), UI_EventFlag_Reorder = (1<<8), + UI_EventFlag_Secondary = (1<<9), }; typedef enum UI_EventDeltaUnit @@ -217,69 +219,34 @@ struct UI_Size }; //////////////////////////////// -//~ rjf: Palettes +//~ rjf: Themes -typedef enum UI_ColorCode +typedef struct UI_ThemePattern UI_ThemePattern; +struct UI_ThemePattern { - UI_ColorCode_Null, - UI_ColorCode_Background, - UI_ColorCode_Text, - UI_ColorCode_TextWeak, - UI_ColorCode_Border, - UI_ColorCode_Overlay, - UI_ColorCode_Cursor, - UI_ColorCode_Selection, - UI_ColorCode_COUNT -} -UI_ColorCode; - -typedef struct UI_Palette UI_Palette; -struct UI_Palette -{ - union - { - Vec4F32 colors[UI_ColorCode_COUNT]; - struct - { - Vec4F32 null; - Vec4F32 background; - Vec4F32 text; - Vec4F32 text_weak; - Vec4F32 border; - Vec4F32 overlay; - Vec4F32 cursor; - Vec4F32 selection; - }; - }; + String8Array tags; + Vec4F32 linear; }; -typedef struct UI_WidgetPaletteInfo UI_WidgetPaletteInfo; -struct UI_WidgetPaletteInfo +typedef struct UI_Theme UI_Theme; +struct UI_Theme { - UI_Palette *tooltip_palette; - UI_Palette *ctx_menu_palette; - UI_Palette *scrollbar_palette; + UI_ThemePattern *patterns; + U64 patterns_count; }; //////////////////////////////// //~ rjf: Animation Info -typedef U32 UI_AnimationInfoFlags; -enum -{ - UI_AnimationInfoFlag_HotAnimations = (1<<0), - UI_AnimationInfoFlag_ActiveAnimations = (1<<1), - UI_AnimationInfoFlag_FocusAnimations = (1<<2), - UI_AnimationInfoFlag_TooltipAnimations = (1<<3), - UI_AnimationInfoFlag_ContextMenuAnimations = (1<<4), - UI_AnimationInfoFlag_ScrollingAnimations = (1<<5), - UI_AnimationInfoFlag_All = 0xffffffff, -}; - typedef struct UI_AnimationInfo UI_AnimationInfo; struct UI_AnimationInfo { - UI_AnimationInfoFlags flags; + F32 hot_animation_rate; + F32 active_animation_rate; + F32 focus_animation_rate; + F32 tooltip_animation_rate; + F32 menu_animation_rate; + F32 scroll_animation_rate; }; //////////////////////////////// @@ -378,6 +345,10 @@ typedef U64 UI_BoxFlags; # define UI_BoxFlag_HasDisplayString (UI_BoxFlags)(1ull<<49) # define UI_BoxFlag_HasFuzzyMatchRanges (UI_BoxFlags)(1ull<<50) # define UI_BoxFlag_RoundChildrenByParent (UI_BoxFlags)(1ull<<51) +# define UI_BoxFlag_SquishAnchored (UI_BoxFlags)(1ull<<52) + +//- rjf: debug +# define UI_BoxFlag_Debug (UI_BoxFlags)(1ull<<53) //- rjf: bundles # define UI_BoxFlag_Clickable (UI_BoxFlag_MouseClickable|UI_BoxFlag_KeyboardClickable) @@ -409,10 +380,12 @@ struct UI_Box //- rjf: per-build equipment UI_Key key; UI_BoxFlags flags; + UI_Key tags_key; String8 string; UI_TextAlign text_align; Vec2F32 fixed_position; Vec2F32 fixed_size; + Vec2F32 min_size; UI_Size pref_size[Axis2_COUNT]; Axis2 child_layout_axis; OS_Cursor hover_cursor; @@ -421,7 +394,8 @@ struct UI_Box DR_Bucket *draw_bucket; UI_BoxCustomDrawFunctionType *custom_draw; void *custom_draw_user_data; - UI_Palette *palette; + Vec4F32 background_color; + Vec4F32 text_color; FNT_Tag font; F32 font_size; F32 tab_size; @@ -433,7 +407,8 @@ struct UI_Box F32 text_padding; //- rjf: per-build artifacts - DR_FancyRunList display_string_runs; + DR_FStrList display_fstrs; + DR_FRunList display_fruns; Rng2F32 rect; Vec2F32 fixed_position_animated; Vec2F32 position_delta; @@ -581,6 +556,7 @@ struct UI_AnimParams F32 target; F32 rate; F32 epsilon; + B32 reset; }; typedef struct UI_AnimNode UI_AnimNode; @@ -612,6 +588,54 @@ struct UI_AnimSlot //////////////////////////////// //~ rjf: State Types +//- rjf: cache for mapping 64-bit key -> array of tags + +typedef struct UI_TagsCacheNode UI_TagsCacheNode; +struct UI_TagsCacheNode +{ + UI_TagsCacheNode *next; + UI_Key key; + String8Array tags; +}; + +typedef struct UI_TagsCacheSlot UI_TagsCacheSlot; +struct UI_TagsCacheSlot +{ + UI_TagsCacheNode *first; + UI_TagsCacheNode *last; +}; + +typedef struct UI_TagsKeyStackNode UI_TagsKeyStackNode; +struct UI_TagsKeyStackNode +{ + UI_TagsKeyStackNode *next; + UI_Key key; +}; + +//- rjf: cache for mapping 64-bit key -> theme pattern + +typedef struct UI_ThemePatternCacheNode UI_ThemePatternCacheNode; +struct UI_ThemePatternCacheNode +{ + UI_ThemePatternCacheNode *slot_next; + UI_ThemePatternCacheNode *slot_prev; + UI_ThemePatternCacheNode *lru_next; + UI_ThemePatternCacheNode *lru_prev; + U64 last_build_index_accessed; + UI_Key key; + Vec4F32 target_rgba; + Vec4F32 current_rgba; +}; + +typedef struct UI_ThemePatternCacheSlot UI_ThemePatternCacheSlot; +struct UI_ThemePatternCacheSlot +{ + UI_ThemePatternCacheNode *first; + UI_ThemePatternCacheNode *last; +}; + +//- rjf: cache for mapping 64-bit key -> box + typedef struct UI_BoxHashSlot UI_BoxHashSlot; struct UI_BoxHashSlot { @@ -619,6 +643,8 @@ struct UI_BoxHashSlot UI_Box *hash_last; }; +//- rjf: main state bundle + typedef struct UI_State UI_State; struct UI_State { @@ -646,6 +672,22 @@ struct UI_State //- rjf: build state machine state B32 is_in_open_ctx_menu; + String8 autocomplete_string; + B32 tooltip_can_overflow_window; + UI_Key tooltip_anchor_key; + String8Array current_gen_tags; + U64 current_gen_tags_gen; + UI_TagsKeyStackNode *tags_key_stack_top; + UI_TagsKeyStackNode *tags_key_stack_free; + U64 tags_cache_slots_count; + UI_TagsCacheSlot *tags_cache_slots; + + //- rjf: theme pattern cache + U64 theme_pattern_cache_slots_count; + UI_ThemePatternCacheSlot *theme_pattern_cache_slots; + UI_ThemePatternCacheNode *theme_pattern_cache_node_free; + UI_ThemePatternCacheNode *lru_theme_pattern_cache_node; + UI_ThemePatternCacheNode *mru_theme_pattern_cache_node; //- rjf: build phase output UI_Box *root; @@ -659,7 +701,7 @@ struct UI_State //- rjf: build parameters UI_IconInfo icon_info; - UI_WidgetPaletteInfo widget_palette_info; + UI_Theme *theme; UI_AnimationInfo animation_info; OS_Handle window; UI_EventList *events; @@ -680,7 +722,8 @@ struct UI_State String8 drag_state_data; Arena *string_hover_arena; String8 string_hover_string; - DR_FancyRunList string_hover_fancy_runs; + F32 string_hover_size; + DR_FStrList string_hover_fstrs; U64 string_hover_begin_us; U64 string_hover_build_index; U64 last_time_mousemoved_us; @@ -741,11 +784,6 @@ internal UI_Size ui_size(UI_SizeKind kind, F32 value, F32 strictness); #define ui_pct(value, strictness) ui_size(UI_SizeKind_ParentPct, value, strictness) #define ui_children_sum(strictness) ui_size(UI_SizeKind_ChildrenSum, 0.f, strictness) -//////////////////////////////// -//~ rjf: Color Scheme Type Functions - -read_only global UI_Palette ui_g_nil_palette = {0}; - //////////////////////////////// //~ rjf: Scroll Point Type Functions @@ -789,7 +827,7 @@ internal UI_State *ui_get_selected_state(void); internal Arena * ui_build_arena(void); internal OS_Handle ui_window(void); internal Vec2F32 ui_mouse(void); -internal FNT_Tag ui_icon_font(void); +internal FNT_Tag ui_icon_font(void); internal String8 ui_icon_string_from_kind(UI_IconKind icon_kind); internal F32 ui_dt(void); @@ -803,6 +841,11 @@ internal B32 ui_key_release(OS_Modifiers mods, OS_Key key); internal B32 ui_text(U32 character); internal B32 ui_slot_press(UI_EventActionSlot slot); +//- rjf: autocomplete info +internal void ui_set_autocomplete_string(String8 string); +internal String8 ui_autocomplete_string(void); +internal String8 ui_autocomplete(void); + //- rjf: drag data internal Vec2F32 ui_drag_start_mouse(void); internal Vec2F32 ui_drag_delta(void); @@ -812,8 +855,8 @@ internal String8 ui_get_drag_data(U64 min_required_size); #define ui_get_drag_struct(type) ((type *)ui_get_drag_data(sizeof(type)).str) //- rjf: hovered string info -internal B32 ui_string_hover_active(void); -internal DR_FancyRunList ui_string_hover_runs(Arena *arena); +internal B32 ui_string_hover_active(void); +internal DR_FStrList ui_string_hover_fstrs(Arena *arena); //- rjf: interaction keys internal UI_Key ui_hot_key(void); @@ -829,13 +872,13 @@ internal UI_Box * ui_box_from_key(UI_Key key); //////////////////////////////// //~ rjf: Top-Level Building API -internal void ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, UI_WidgetPaletteInfo *widget_palette_info, UI_AnimationInfo *animation_info, F32 real_dt, F32 animation_dt); +internal void ui_begin_build(OS_Handle window, UI_EventList *events, UI_IconInfo *icon_info, UI_Theme *theme, UI_AnimationInfo *animation_info, F32 real_dt, F32 animation_dt); internal void ui_end_build(void); -internal void ui_calc_sizes_standalone__in_place_rec(UI_Box *root, Axis2 axis); -internal void ui_calc_sizes_upwards_dependent__in_place_rec(UI_Box *root, Axis2 axis); -internal void ui_calc_sizes_downwards_dependent__in_place_rec(UI_Box *root, Axis2 axis); -internal void ui_layout_enforce_constraints__in_place_rec(UI_Box *root, Axis2 axis); -internal void ui_layout_position__in_place_rec(UI_Box *root, Axis2 axis); +internal void ui_calc_sizes_standalone__in_place(UI_Box *root, Axis2 axis); +internal void ui_calc_sizes_upwards_dependent__in_place(UI_Box *root, Axis2 axis); +internal void ui_calc_sizes_downwards_dependent__in_place(UI_Box *root, Axis2 axis); +internal void ui_layout_enforce_constraints__in_place(UI_Box *root, Axis2 axis); +internal void ui_layout_position__in_place(UI_Box *root, Axis2 axis); internal void ui_layout_root(UI_Box *root, Axis2 axis); //////////////////////////////// @@ -868,9 +911,13 @@ internal B32 ui_is_key_auto_focus_hot(UI_Key key); internal void ui_set_auto_focus_active_key(UI_Key key); internal void ui_set_auto_focus_hot_key(UI_Key key); -//- rjf: palette forming -internal UI_Palette * ui_build_palette_(UI_Palette *base, UI_Palette *overrides); -#define ui_build_palette(base, ...) ui_build_palette_((base), &(UI_Palette){.text = v4f32(0, 0, 0, 0), __VA_ARGS__}) +//- rjf: current style tags key +internal UI_Key ui_top_tags_key(void); + +//- rjf: theme color lookups +internal Vec4F32 ui_color_from_name(String8 name); +internal Vec4F32 ui_color_from_tags_key_extras(UI_Key key, String8Array extras); +internal Vec4F32 ui_color_from_tags_key_name(UI_Key key, String8 name); //- rjf: box node construction internal UI_Box * ui_build_box_from_key(UI_BoxFlags flags, UI_Key key); @@ -880,8 +927,7 @@ internal UI_Box * ui_build_box_from_stringf(UI_BoxFlags flags, char *fm //- rjf: box node equipment internal inline void ui_box_equip_display_string(UI_Box *box, String8 string); -internal inline void ui_box_equip_display_fancy_strings(UI_Box *box, DR_FancyStringList *strings); -internal inline void ui_box_equip_display_string_fancy_runs(UI_Box *box, String8 string, DR_FancyRunList *runs); +internal inline void ui_box_equip_display_fstrs(UI_Box *box, DR_FStrList *strings); internal inline void ui_box_equip_fuzzy_match_ranges(UI_Box *box, FuzzyMatchRangeList *matches); internal inline void ui_box_equip_draw_bucket(UI_Box *box, DR_Bucket *bucket); internal inline void ui_box_equip_custom_draw(UI_Box *box, UI_BoxCustomDrawFunctionType *custom_draw, void *user_data); @@ -911,6 +957,9 @@ internal F32 ui_anim_(UI_Key key, UI_AnimParams *params); //////////////////////////////// //~ rjf: Stacks +internal void ui__push_tags_key_from_appended_string(String8 string); +internal void ui__pop_tags_key(void); + //- rjf: base internal UI_Box * ui_top_parent(void); internal Axis2 ui_top_child_layout_axis(void); @@ -922,12 +971,15 @@ internal UI_Size ui_top_pref_width(void); internal UI_Size ui_top_pref_height(void); internal UI_PermissionFlags ui_top_permission_flags(void); internal UI_BoxFlags ui_top_flags(void); +internal UI_BoxFlags ui_top_omit_flags(void); internal UI_FocusKind ui_top_focus_hot(void); internal UI_FocusKind ui_top_focus_active(void); internal U32 ui_top_fastpath_codepoint(void); internal UI_Key ui_top_group_key(void); internal F32 ui_top_transparency(void); -internal UI_Palette* ui_top_palette(void); +internal String8 ui_top_tag(void); +internal Vec4F32 ui_top_background_color(void); +internal Vec4F32 ui_top_text_color(void); internal F32 ui_top_squish(void); internal OS_Cursor ui_top_hover_cursor(void); internal FNT_Tag ui_top_font(void); @@ -951,12 +1003,15 @@ internal UI_Size ui_bottom_pref_width(void); internal UI_Size ui_bottom_pref_height(void); internal UI_PermissionFlags ui_bottom_permission_flags(void); internal UI_BoxFlags ui_bottom_flags(void); +internal UI_BoxFlags ui_bottom_omit_flags(void); internal UI_FocusKind ui_bottom_focus_hot(void); internal UI_FocusKind ui_bottom_focus_active(void); internal U32 ui_bottom_fastpath_codepoint(void); internal UI_Key ui_bottom_group_key(void); internal F32 ui_bottom_transparency(void); -internal UI_Palette* ui_bottom_palette(void); +internal String8 ui_bottom_tag(void); +internal Vec4F32 ui_bottom_background_color(void); +internal Vec4F32 ui_bottom_text_color(void); internal F32 ui_bottom_squish(void); internal OS_Cursor ui_bottom_hover_cursor(void); internal FNT_Tag ui_bottom_font(void); @@ -980,12 +1035,15 @@ internal UI_Size ui_push_pref_width(UI_Size v); internal UI_Size ui_push_pref_height(UI_Size v); internal UI_PermissionFlags ui_push_permission_flags(UI_PermissionFlags v); internal UI_BoxFlags ui_push_flags(UI_BoxFlags v); +internal UI_BoxFlags ui_push_omit_flags(UI_BoxFlags v); internal UI_FocusKind ui_push_focus_hot(UI_FocusKind v); internal UI_FocusKind ui_push_focus_active(UI_FocusKind v); internal U32 ui_push_fastpath_codepoint(U32 v); internal UI_Key ui_push_group_key(UI_Key v); internal F32 ui_push_transparency(F32 v); -internal UI_Palette* ui_push_palette(UI_Palette* v); +internal String8 ui_push_tag(String8 v); +internal Vec4F32 ui_push_background_color(Vec4F32 v); +internal Vec4F32 ui_push_text_color(Vec4F32 v); internal F32 ui_push_squish(F32 v); internal OS_Cursor ui_push_hover_cursor(OS_Cursor v); internal FNT_Tag ui_push_font(FNT_Tag v); @@ -1009,12 +1067,15 @@ internal UI_Size ui_pop_pref_width(void); internal UI_Size ui_pop_pref_height(void); internal UI_PermissionFlags ui_pop_permission_flags(void); internal UI_BoxFlags ui_pop_flags(void); +internal UI_BoxFlags ui_pop_omit_flags(void); internal UI_FocusKind ui_pop_focus_hot(void); internal UI_FocusKind ui_pop_focus_active(void); internal U32 ui_pop_fastpath_codepoint(void); internal UI_Key ui_pop_group_key(void); internal F32 ui_pop_transparency(void); -internal UI_Palette* ui_pop_palette(void); +internal String8 ui_pop_tag(void); +internal Vec4F32 ui_pop_background_color(void); +internal Vec4F32 ui_pop_text_color(void); internal F32 ui_pop_squish(void); internal OS_Cursor ui_pop_hover_cursor(void); internal FNT_Tag ui_pop_font(void); @@ -1038,12 +1099,15 @@ internal UI_Size ui_set_next_pref_width(UI_Size v); internal UI_Size ui_set_next_pref_height(UI_Size v); internal UI_PermissionFlags ui_set_next_permission_flags(UI_PermissionFlags v); internal UI_BoxFlags ui_set_next_flags(UI_BoxFlags v); +internal UI_BoxFlags ui_set_next_omit_flags(UI_BoxFlags v); internal UI_FocusKind ui_set_next_focus_hot(UI_FocusKind v); internal UI_FocusKind ui_set_next_focus_active(UI_FocusKind v); internal U32 ui_set_next_fastpath_codepoint(U32 v); internal UI_Key ui_set_next_group_key(UI_Key v); internal F32 ui_set_next_transparency(F32 v); -internal UI_Palette* ui_set_next_palette(UI_Palette* v); +internal String8 ui_set_next_tag(String8 v); +internal Vec4F32 ui_set_next_background_color(Vec4F32 v); +internal Vec4F32 ui_set_next_text_color(Vec4F32 v); internal F32 ui_set_next_squish(F32 v); internal OS_Cursor ui_set_next_hover_cursor(OS_Cursor v); internal FNT_Tag ui_set_next_font(FNT_Tag v); @@ -1067,6 +1131,8 @@ internal UI_Size ui_pop_pref_size(Axis2 axis); internal UI_Size ui_set_next_pref_size(Axis2 axis, UI_Size v); internal void ui_push_corner_radius(F32 v); internal void ui_pop_corner_radius(void); +internal void ui_push_tagf(char *fmt, ...); +internal F32 ui_top_px_height(void); //////////////////////////////// //~ rjf: Macro Loop Wrappers @@ -1080,14 +1146,19 @@ internal void ui_pop_corner_radius(void); #define UI_FixedHeight(v) DeferLoop(ui_push_fixed_height(v), ui_pop_fixed_height()) #define UI_PrefWidth(v) DeferLoop(ui_push_pref_width(v), ui_pop_pref_width()) #define UI_PrefHeight(v) DeferLoop(ui_push_pref_height(v), ui_pop_pref_height()) +#define UI_MinWidth(v) DeferLoop(ui_push_min_width(v), ui_pop_min_width()) +#define UI_MinHeight(v) DeferLoop(ui_push_min_height(v), ui_pop_min_height()) #define UI_PermissionFlags(v) DeferLoop(ui_push_permission_flags(v), ui_pop_permission_flags()) #define UI_Flags(v) DeferLoop(ui_push_flags(v), ui_pop_flags()) +#define UI_OmitFlags(v) DeferLoop(ui_push_omit_flags(v), ui_pop_omit_flags()) #define UI_FocusHot(v) DeferLoop(ui_push_focus_hot(v), ui_pop_focus_hot()) #define UI_FocusActive(v) DeferLoop(ui_push_focus_active(v), ui_pop_focus_active()) #define UI_FastpathCodepoint(v) DeferLoop(ui_push_fastpath_codepoint(v), ui_pop_fastpath_codepoint()) #define UI_GroupKey(v) DeferLoop(ui_push_group_key(v), ui_pop_group_key()) #define UI_Transparency(v) DeferLoop(ui_push_transparency(v), ui_pop_transparency()) -#define UI_Palette(v) DeferLoop(ui_push_palette(v), ui_pop_palette()) +#define UI_Tag(v) DeferLoop(ui_push_tag(v), ui_pop_tag()) +#define UI_BackgroundColor(v) DeferLoop(ui_push_background_color(v), ui_pop_background_color()) +#define UI_TextColor(v) DeferLoop(ui_push_text_color(v), ui_pop_text_color()) #define UI_Squish(v) DeferLoop(ui_push_squish(v), ui_pop_squish()) #define UI_HoverCursor(v) DeferLoop(ui_push_hover_cursor(v), ui_pop_hover_cursor()) #define UI_Font(v) DeferLoop(ui_push_font(v), ui_pop_font()) @@ -1112,6 +1183,7 @@ internal void ui_pop_corner_radius(void); #define UI_CornerRadius(v) DeferLoop(ui_push_corner_radius(v), ui_pop_corner_radius()) #define UI_Focus(kind) DeferLoop((ui_push_focus_hot(kind), ui_push_focus_active(kind)), (ui_pop_focus_hot(), ui_pop_focus_active())) #define UI_FlagsAdd(v) DeferLoop(ui_push_flags(ui_top_flags()|(v)), ui_pop_flags()) +#define UI_TagF(...) DeferLoop(ui_push_tagf(__VA_ARGS__), ui_pop_tag()) //- rjf: tooltip #define UI_TooltipBase DeferLoop(ui_tooltip_begin_base(), ui_tooltip_end_base()) @@ -1120,4 +1192,7 @@ internal void ui_pop_corner_radius(void); //- rjf: context menu #define UI_CtxMenu(key) DeferLoopChecked(ui_begin_ctx_menu(key), ui_end_ctx_menu()) +//- rjf: debug +#define UI_Debug UI_FlagsAdd(UI_BoxFlag_Debug) + #endif // UI_H diff --git a/src/ui/ui_inc.c b/src/ui/ui_inc.c index 7d4e8378..c9bed64e 100644 --- a/src/ui/ui_inc.c +++ b/src/ui/ui_inc.c @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#undef MARKUP_LAYER_COLOR -#define MARKUP_LAYER_COLOR 0.70f, 0.30f, 0.15f +#undef LAYER_COLOR +#define LAYER_COLOR 0xb5438dff #include "ui_core.c" #include "ui_basic_widgets.c"